]> git.saurik.com Git - wxWidgets.git/blame - src/generic/treebkg.cpp
don't use strlen() to verify the length of the string as it can contain embedded...
[wxWidgets.git] / src / generic / treebkg.cpp
CommitLineData
eca15c0d
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/generic/treebkg.cpp
3// Purpose: generic implementation of wxTreebook
4// Author: Evgeniy Tarassov, Vadim Zeitlin
5// Modified by:
6// Created: 2005-09-15
7// RCS-ID: $Id$
8// Copyright: (c) 2005 Vadim Zeitlin <vadim@wxwidgets.org>
9// Licence: wxWindows licence
10///////////////////////////////////////////////////////////////////////////////
11
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
24 #pragma hdrstop
25#endif
26
27#if wxUSE_TREEBOOK
28
29#include "wx/treebook.h"
9eddec69
WS
30
31#ifndef WX_PRECOMP
32 #include "wx/settings.h"
33#endif
34
eca15c0d 35#include "wx/imaglist.h"
eca15c0d
VZ
36
37// ----------------------------------------------------------------------------
38// various wxWidgets macros
39// ----------------------------------------------------------------------------
40
41// check that the page index is valid
42#define IS_VALID_PAGE(nPage) ((nPage) < DoInternalGetPageCount())
43
44// ----------------------------------------------------------------------------
45// event table
46// ----------------------------------------------------------------------------
47
2ddb4d13 48IMPLEMENT_DYNAMIC_CLASS(wxTreebook, wxBookCtrlBase)
eca15c0d
VZ
49IMPLEMENT_DYNAMIC_CLASS(wxTreebookEvent, wxNotifyEvent)
50
9cf0f6ae 51#if !WXWIN_COMPATIBILITY_EVENT_TYPES
eca15c0d
VZ
52const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING = wxNewEventType();
53const wxEventType wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED = wxNewEventType();
54const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED = wxNewEventType();
55const wxEventType wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED = wxNewEventType();
9cf0f6ae 56#endif
eca15c0d
VZ
57
58BEGIN_EVENT_TABLE(wxTreebook, wxBookCtrlBase)
447325a4
VZ
59 EVT_TREE_SEL_CHANGED (wxID_ANY, wxTreebook::OnTreeSelectionChange)
60 EVT_TREE_ITEM_EXPANDED (wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
61 EVT_TREE_ITEM_COLLAPSED(wxID_ANY, wxTreebook::OnTreeNodeExpandedCollapsed)
5e4a7f91
JG
62
63 WX_EVENT_TABLE_CONTROL_CONTAINER(wxTreebook)
eca15c0d
VZ
64END_EVENT_TABLE()
65
66// ============================================================================
67// wxTreebook implementation
68// ============================================================================
69
5e4a7f91
JG
70WX_DELEGATE_TO_CONTROL_CONTAINER(wxTreebook, wxControl)
71
eca15c0d
VZ
72// ----------------------------------------------------------------------------
73// wxTreebook creation
74// ----------------------------------------------------------------------------
75
76void wxTreebook::Init()
77{
5e4a7f91
JG
78 m_container.SetContainerWindow(this);
79
eca15c0d
VZ
80 m_selection =
81 m_actualSelection = wxNOT_FOUND;
82}
83
84bool
85wxTreebook::Create(wxWindow *parent,
86 wxWindowID id,
87 const wxPoint& pos,
88 const wxSize& size,
89 long style,
90 const wxString& name)
91{
92 // Check the style flag to have either wxTBK_RIGHT or wxTBK_LEFT
2ddb4d13 93 if ( (style & wxBK_ALIGN_MASK) == wxBK_DEFAULT )
eca15c0d 94 {
2ddb4d13 95 style |= wxBK_LEFT;
eca15c0d 96 }
5e4a7f91 97 style |= wxTAB_TRAVERSAL;
eca15c0d
VZ
98
99 // no border for this control, it doesn't look nice together with the tree
100 style &= ~wxBORDER_MASK;
101 style |= wxBORDER_NONE;
102
103 if ( !wxControl::Create(parent, id, pos, size,
104 style, wxDefaultValidator, name) )
105 return false;
106
2ddb4d13 107 m_bookctrl = new wxTreeCtrl
eca15c0d
VZ
108 (
109 this,
447325a4 110 wxID_ANY,
eca15c0d
VZ
111 wxDefaultPosition,
112 wxDefaultSize,
52f15cb7
JS
113#ifndef __WXMSW__
114 wxBORDER_SIMPLE | // On wxMSW this produces a black border which is wrong
115#endif
bc454ef8 116 wxTR_DEFAULT_STYLE |
eca15c0d 117 wxTR_HIDE_ROOT |
eca15c0d
VZ
118 wxTR_SINGLE
119 );
7c384067 120 GetTreeCtrl()->SetQuickBestSize(false); // do full size calculation
2ddb4d13 121 GetTreeCtrl()->AddRoot(wxEmptyString); // label doesn't matter, it's hidden
eca15c0d
VZ
122
123#ifdef __WXMSW__
2ddb4d13 124 // We need to add dummy size event to force possible scrollbar hiding
eca15c0d
VZ
125 wxSizeEvent evt;
126 GetEventHandler()->AddPendingEvent(evt);
127#endif
128
129 return true;
130}
131
132
133// insert a new page just before the pagePos
134bool wxTreebook::InsertPage(size_t pagePos,
135 wxWindow *page,
136 const wxString& text,
137 bool bSelect,
138 int imageId)
139{
140 return DoInsertPage(pagePos, page, text, bSelect, imageId);
141}
142
9d5371c6
VZ
143bool wxTreebook::InsertSubPage(size_t pagePos,
144 wxWindow *page,
145 const wxString& text,
146 bool bSelect,
147 int imageId)
eca15c0d
VZ
148{
149 return DoInsertSubPage(pagePos, page, text, bSelect, imageId);
150}
151
152bool wxTreebook::AddPage(wxWindow *page, const wxString& text, bool bSelect,
153 int imageId)
154{
155 return DoInsertPage(m_treeIds.GetCount(), page, text, bSelect, imageId);
156}
157
158// insertion time is linear to the number of top-pages
159bool wxTreebook::AddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
160{
161 return DoAddSubPage(page, text, bSelect, imageId);
162}
163
164
165bool wxTreebook::DoInsertPage(size_t pagePos,
166 wxWindow *page,
167 const wxString& text,
168 bool bSelect,
169 int imageId)
170{
171 wxCHECK_MSG( pagePos <= DoInternalGetPageCount(), false,
172 wxT("Invalid treebook page position") );
173
174 if ( !wxBookCtrlBase::InsertPage(pagePos, page, text, bSelect, imageId) )
175 return false;
176
2ddb4d13 177 wxTreeCtrl *tree = GetTreeCtrl();
eca15c0d
VZ
178 wxTreeItemId newId;
179 if ( pagePos == DoInternalGetPageCount() )
180 {
181 // append the page to the end
2ddb4d13 182 wxTreeItemId rootId = tree->GetRootItem();
eca15c0d 183
2ddb4d13 184 newId = tree->AppendItem(rootId, text, imageId);
eca15c0d
VZ
185 }
186 else // insert the new page before the given one
187 {
188 wxTreeItemId nodeId = m_treeIds[pagePos];
189
2ddb4d13
WS
190 wxTreeItemId previousId = tree->GetPrevSibling(nodeId);
191 wxTreeItemId parentId = tree->GetItemParent(nodeId);
eca15c0d
VZ
192
193 if ( previousId.IsOk() )
194 {
195 // insert before the sibling - previousId
2ddb4d13 196 newId = tree->InsertItem(parentId, previousId, text, imageId);
eca15c0d
VZ
197 }
198 else // no prev siblings -- insert as a first child
199 {
200 wxASSERT_MSG( parentId.IsOk(), wxT( "Tree has no root node?" ) );
201
2ddb4d13 202 newId = tree->PrependItem(parentId, text, imageId);
eca15c0d
VZ
203 }
204 }
205
206 if ( !newId.IsOk() )
207 {
208 //something wrong -> cleaning and returning with false
209 (void)wxBookCtrlBase::DoRemovePage(pagePos);
210
211 wxFAIL_MSG( wxT("Failed to insert treebook page") );
212 return false;
213 }
214
215 DoInternalAddPage(pagePos, page, newId);
216
217 DoUpdateSelection(bSelect, pagePos);
218
219 return true;
220}
221
222bool wxTreebook::DoAddSubPage(wxWindow *page, const wxString& text, bool bSelect, int imageId)
223{
2ddb4d13 224 wxTreeCtrl *tree = GetTreeCtrl();
eca15c0d 225
2ddb4d13
WS
226 wxTreeItemId rootId = tree->GetRootItem();
227
228 wxTreeItemId lastNodeId = tree->GetLastChild(rootId);
eca15c0d
VZ
229
230 wxCHECK_MSG( lastNodeId.IsOk(), false,
231 _T("Can't insert sub page when there are no pages") );
232
233 // now calculate its position (should we save/update it too?)
2ddb4d13
WS
234 size_t newPos = tree->GetCount() -
235 (tree->GetChildrenCount(lastNodeId, true) + 1);
eca15c0d
VZ
236
237 return DoInsertSubPage(newPos, page, text, bSelect, imageId);
238}
239
240bool wxTreebook::DoInsertSubPage(size_t pagePos,
241 wxTreebookPage *page,
242 const wxString& text,
243 bool bSelect,
244 int imageId)
245{
246 wxTreeItemId parentId = DoInternalGetPage(pagePos);
247 wxCHECK_MSG( parentId.IsOk(), false, wxT("invalid tree item") );
248
2ddb4d13
WS
249 wxTreeCtrl *tree = GetTreeCtrl();
250
251 size_t newPos = pagePos + tree->GetChildrenCount(parentId, true) + 1;
eca15c0d
VZ
252 wxASSERT_MSG( newPos <= DoInternalGetPageCount(),
253 wxT("Internal error in tree insert point calculation") );
254
255 if ( !wxBookCtrlBase::InsertPage(newPos, page, text, bSelect, imageId) )
256 return false;
257
2ddb4d13 258 wxTreeItemId newId = tree->AppendItem(parentId, text, imageId);
eca15c0d
VZ
259
260 if ( !newId.IsOk() )
261 {
262 (void)wxBookCtrlBase::DoRemovePage(newPos);
263
264 wxFAIL_MSG( wxT("Failed to insert treebook page") );
265 return false;
266 }
267
268 DoInternalAddPage(newPos, page, newId);
269
270 DoUpdateSelection(bSelect, newPos);
271
272 return true;
273}
274
275bool wxTreebook::DeletePage(size_t pagePos)
276{
277 wxCHECK_MSG( IS_VALID_PAGE(pagePos), false, wxT("Invalid tree index") );
278
279 wxTreebookPage *oldPage = DoRemovePage(pagePos);
280 if ( !oldPage )
281 return false;
282
283 delete oldPage;
284
285 return true;
286}
287
288wxTreebookPage *wxTreebook::DoRemovePage(size_t pagePos)
289{
290 wxTreeItemId pageId = DoInternalGetPage(pagePos);
291 wxCHECK_MSG( pageId.IsOk(), NULL, wxT("Invalid tree index") );
292
293 wxTreebookPage * oldPage = GetPage(pagePos);
2ddb4d13 294 wxTreeCtrl *tree = GetTreeCtrl();
eca15c0d 295
2ddb4d13 296 size_t subCount = tree->GetChildrenCount(pageId, true);
eca15c0d
VZ
297 wxASSERT_MSG ( IS_VALID_PAGE(pagePos + subCount),
298 wxT("Internal error in wxTreebook::DoRemovePage") );
299
300 // here we are going to delete ALL the pages in the range
301 // [pagePos, pagePos + subCount] -- the page and its children
302
303 // deleting all the pages from the base class
304 for ( size_t i = 0; i <= subCount; ++i )
305 {
306 wxTreebookPage *page = wxBookCtrlBase::DoRemovePage(pagePos);
307
308 // don't delete the page itself though -- it will be deleted in
309 // DeletePage() when we return
310 if ( i )
311 {
312 delete page;
313 }
314 }
315
316 DoInternalRemovePageRange(pagePos, subCount);
317
2ddb4d13
WS
318 tree->DeleteChildren( pageId );
319 tree->Delete( pageId );
eca15c0d
VZ
320
321 return oldPage;
322}
323
324bool wxTreebook::DeleteAllPages()
325{
326 wxBookCtrlBase::DeleteAllPages();
327 m_treeIds.Clear();
328 m_selection =
329 m_actualSelection = wxNOT_FOUND;
330
2ddb4d13
WS
331 wxTreeCtrl *tree = GetTreeCtrl();
332 tree->DeleteChildren(tree->GetRootItem());
eca15c0d
VZ
333
334 return true;
335}
336
337void wxTreebook::DoInternalAddPage(size_t newPos,
338 wxTreebookPage *page,
339 wxTreeItemId pageId)
340{
341 wxASSERT_MSG( newPos <= m_treeIds.GetCount(), wxT("Ivalid index passed to wxTreebook::DoInternalAddPage") );
342
343 // hide newly inserted page initially (it will be shown when selected)
344 if ( page )
345 page->Hide();
346
347 if ( newPos == m_treeIds.GetCount() )
348 {
349 // append
350 m_treeIds.Add(pageId);
351 }
352 else // insert
353 {
354 m_treeIds.Insert(pageId, newPos);
355
356 if ( m_selection != wxNOT_FOUND && newPos <= (size_t)m_selection )
357 {
358 // selection has been moved one unit toward the end
359 ++m_selection;
360 if ( m_actualSelection != wxNOT_FOUND )
361 ++m_actualSelection;
362 }
363 else if ( m_actualSelection != wxNOT_FOUND &&
364 newPos <= (size_t)m_actualSelection )
365 {
366 DoSetSelection(m_selection);
367 }
368 }
369}
370
371void wxTreebook::DoInternalRemovePageRange(size_t pagePos, size_t subCount)
372{
373 // Attention: this function is only for a situation when we delete a node
374 // with all its children so pagePos is the node's index and subCount is the
375 // node children count
376 wxASSERT_MSG( pagePos + subCount < m_treeIds.GetCount(),
377 wxT("Ivalid page index") );
378
379 wxTreeItemId pageId = m_treeIds[pagePos];
380
381 m_treeIds.RemoveAt(pagePos, subCount + 1);
382
383 if ( m_selection != wxNOT_FOUND )
384 {
385 if ( (size_t)m_selection > pagePos + subCount)
386 {
387 // selection is far after the deleted page, so just update the index and move on
388 m_selection -= 1 + subCount;
389 if ( m_actualSelection != wxNOT_FOUND)
390 {
391 m_actualSelection -= subCount + 1;
392 }
393 }
394 else if ( (size_t)m_selection >= pagePos )
395 {
2ddb4d13
WS
396 wxTreeCtrl *tree = GetTreeCtrl();
397
eca15c0d
VZ
398 // as selected page is going to be deleted, try to select the next
399 // sibling if exists, if not then the parent
2ddb4d13 400 wxTreeItemId nodeId = tree->GetNextSibling(pageId);
eca15c0d
VZ
401
402 m_selection = wxNOT_FOUND;
403 m_actualSelection = wxNOT_FOUND;
404
405 if ( nodeId.IsOk() )
406 {
407 // selecting next siblings
2ddb4d13 408 tree->SelectItem(nodeId);
eca15c0d
VZ
409 }
410 else // no next sibling, select the parent
411 {
2ddb4d13 412 wxTreeItemId parentId = tree->GetItemParent(pageId);
eca15c0d 413
2ddb4d13 414 if ( parentId.IsOk() && parentId != tree->GetRootItem() )
eca15c0d 415 {
2ddb4d13 416 tree->SelectItem(parentId);
eca15c0d
VZ
417 }
418 else // parent is root
419 {
420 // we can't select it as it's hidden
421 DoUpdateSelection(false, wxNOT_FOUND);
422 }
423 }
424 }
425 else if ( m_actualSelection != wxNOT_FOUND &&
426 (size_t)m_actualSelection >= pagePos )
427 {
428 // nothing to do -- selection is before the deleted node, but
429 // actually shown page (the first (sub)child with page != NULL) is
430 // already deleted
431 m_actualSelection = m_selection;
1d6fcbcc
VZ
432
433 // send event as documented
434 DoSetSelection(m_selection, SetSelection_SendEvent);
eca15c0d
VZ
435 }
436 //else: nothing to do -- selection is before the deleted node
437 }
438 else
439 {
440 DoUpdateSelection(false, wxNOT_FOUND);
441 }
442}
443
444
445void wxTreebook::DoUpdateSelection(bool bSelect, int newPos)
446{
447 int newSelPos;
448 if ( bSelect )
449 {
450 newSelPos = newPos;
451 }
452 else if ( m_selection == wxNOT_FOUND && DoInternalGetPageCount() > 0 )
453 {
454 newSelPos = 0;
455 }
456 else
457 {
458 newSelPos = wxNOT_FOUND;
459 }
460
461 if ( newSelPos != wxNOT_FOUND )
462 {
463 SetSelection((size_t)newSelPos);
464 }
465}
466
467wxTreeItemId wxTreebook::DoInternalGetPage(size_t pagePos) const
468{
469 if ( pagePos >= m_treeIds.GetCount() )
470 {
471 // invalid position but ok here, in this internal function, don't assert
472 // (the caller will do it)
473 return wxTreeItemId();
474 }
475
476 return m_treeIds[pagePos];
477}
478
479int wxTreebook::DoInternalFindPageById(wxTreeItemId pageId) const
480{
481 const size_t count = m_treeIds.GetCount();
482 for ( size_t i = 0; i < count; ++i )
483 {
484 if ( m_treeIds[i] == pageId )
485 return i;
486 }
487
488 return wxNOT_FOUND;
489}
490
491bool wxTreebook::IsNodeExpanded(size_t pagePos) const
492{
493 wxTreeItemId pageId = DoInternalGetPage(pagePos);
494
495 wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
496
2ddb4d13 497 return GetTreeCtrl()->IsExpanded(pageId);
eca15c0d
VZ
498}
499
500bool wxTreebook::ExpandNode(size_t pagePos, bool expand)
501{
502 wxTreeItemId pageId = DoInternalGetPage(pagePos);
503
504 wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
505
506 if ( expand )
507 {
2ddb4d13 508 GetTreeCtrl()->Expand( pageId );
eca15c0d
VZ
509 }
510 else // collapse
511 {
2ddb4d13 512 GetTreeCtrl()->Collapse( pageId );
eca15c0d
VZ
513
514 // rely on the events generated by wxTreeCtrl to update selection
515 }
516
517 return true;
518}
519
520int wxTreebook::GetPageParent(size_t pagePos) const
521{
522 wxTreeItemId nodeId = DoInternalGetPage( pagePos );
523 wxCHECK_MSG( nodeId.IsOk(), wxNOT_FOUND, wxT("Invalid page index spacified!") );
524
2ddb4d13 525 const wxTreeItemId parent = GetTreeCtrl()->GetItemParent( nodeId );
eca15c0d
VZ
526
527 return parent.IsOk() ? DoInternalFindPageById(parent) : wxNOT_FOUND;
528}
529
530bool wxTreebook::SetPageText(size_t n, const wxString& strText)
531{
532 wxTreeItemId pageId = DoInternalGetPage(n);
533
534 wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
535
2ddb4d13 536 GetTreeCtrl()->SetItemText(pageId, strText);
eca15c0d
VZ
537
538 return true;
539}
540
541wxString wxTreebook::GetPageText(size_t n) const
542{
543 wxTreeItemId pageId = DoInternalGetPage(n);
544
545 wxCHECK_MSG( pageId.IsOk(), wxString(), wxT("invalid tree item") );
546
2ddb4d13 547 return GetTreeCtrl()->GetItemText(pageId);
eca15c0d
VZ
548}
549
550int wxTreebook::GetPageImage(size_t n) const
551{
552 wxTreeItemId pageId = DoInternalGetPage(n);
553
554 wxCHECK_MSG( pageId.IsOk(), wxNOT_FOUND, wxT("invalid tree item") );
555
2ddb4d13 556 return GetTreeCtrl()->GetItemImage(pageId);
eca15c0d
VZ
557}
558
559bool wxTreebook::SetPageImage(size_t n, int imageId)
560{
561 wxTreeItemId pageId = DoInternalGetPage(n);
562
563 wxCHECK_MSG( pageId.IsOk(), false, wxT("invalid tree item") );
564
2ddb4d13 565 GetTreeCtrl()->SetItemImage(pageId, imageId);
eca15c0d
VZ
566
567 return true;
568}
569
570wxSize wxTreebook::CalcSizeFromPage(const wxSize& sizePage) const
571{
2ddb4d13 572 const wxSize sizeTree = GetControllerSize();
eca15c0d
VZ
573
574 wxSize size = sizePage;
575 size.x += sizeTree.x;
576
577 return size;
578}
579
580int wxTreebook::GetSelection() const
581{
582 return m_selection;
583}
584
1d6fcbcc 585int wxTreebook::DoSetSelection(size_t pagePos, int flags)
eca15c0d
VZ
586{
587 wxCHECK_MSG( IS_VALID_PAGE(pagePos), wxNOT_FOUND,
1d6fcbcc 588 wxT("invalid page index in wxListbook::DoSetSelection()") );
eca15c0d
VZ
589 wxASSERT_MSG( GetPageCount() == DoInternalGetPageCount(),
590 wxT("wxTreebook logic error: m_treeIds and m_pages not in sync!"));
591
1d6fcbcc 592 wxTreebookEvent event(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGING, m_windowId);
eca15c0d 593 const int oldSel = m_selection;
2ddb4d13 594 wxTreeCtrl *tree = GetTreeCtrl();
1d6fcbcc 595 bool allowed = false;
eca15c0d 596
1d6fcbcc
VZ
597 if (flags & SetSelection_SendEvent)
598 {
599 event.SetEventObject(this);
600 event.SetSelection(pagePos);
601 event.SetOldSelection(m_selection);
602
603 // don't send the event if the old and new pages are the same; do send it
604 // otherwise and be prepared for it to be vetoed
605 allowed = (int)pagePos == m_selection ||
606 !GetEventHandler()->ProcessEvent(event) ||
607 event.IsAllowed();
608 }
609
610 if ( !(flags & SetSelection_SendEvent) || allowed )
eca15c0d
VZ
611 {
612 // hide the previously shown page
613 wxTreebookPage * const oldPage = DoGetCurrentPage();
614 if ( oldPage )
615 oldPage->Hide();
616
617 // then show the new one
618 m_selection = pagePos;
619 wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
620 if ( !page )
621 {
622 // find the next page suitable to be shown: the first (grand)child
623 // of this one with a non-NULL associated page
624 wxTreeItemId childId = m_treeIds[pagePos];
6bd02a43 625 int actualPagePos = pagePos;
eca15c0d
VZ
626 while ( !page && childId.IsOk() )
627 {
628 wxTreeItemIdValue cookie;
2ddb4d13 629 childId = tree->GetFirstChild( childId, cookie );
eca15c0d
VZ
630 if ( childId.IsOk() )
631 {
6bd02a43 632 page = wxBookCtrlBase::GetPage(++actualPagePos);
eca15c0d
VZ
633 }
634 }
635
6bd02a43 636 m_actualSelection = page ? actualPagePos : m_selection;
eca15c0d
VZ
637 }
638
639 if ( page )
eca15c0d 640 page->Show();
eca15c0d 641
2ddb4d13 642 tree->SelectItem(DoInternalGetPage(pagePos));
eca15c0d 643
1d6fcbcc
VZ
644 if (flags & SetSelection_SendEvent)
645 {
646 // notify about the (now completed) page change
647 event.SetEventType(wxEVT_COMMAND_TREEBOOK_PAGE_CHANGED);
648 (void)GetEventHandler()->ProcessEvent(event);
649 }
eca15c0d 650 }
1d6fcbcc 651 else if ( (flags & SetSelection_SendEvent) && !allowed) // page change vetoed
eca15c0d
VZ
652 {
653 // tree selection might have already had changed
9f30729a
VZ
654 if ( oldSel != wxNOT_FOUND )
655 tree->SelectItem(DoInternalGetPage(oldSel));
eca15c0d
VZ
656 }
657
658 return oldSel;
659}
660
851b88c3
VZ
661wxTreebookPage *wxTreebook::DoGetCurrentPage() const
662{
663 if ( m_selection == wxNOT_FOUND )
664 return NULL;
665
666 wxTreebookPage *page = wxBookCtrlBase::GetPage(m_selection);
667 if ( !page && m_actualSelection != wxNOT_FOUND )
668 {
669 page = wxBookCtrlBase::GetPage(m_actualSelection);
670 }
671
672 return page;
673}
674
eca15c0d
VZ
675void wxTreebook::SetImageList(wxImageList *imageList)
676{
677 wxBookCtrlBase::SetImageList(imageList);
2ddb4d13 678 GetTreeCtrl()->SetImageList(imageList);
eca15c0d
VZ
679}
680
681void wxTreebook::AssignImageList(wxImageList *imageList)
682{
683 wxBookCtrlBase::AssignImageList(imageList);
2ddb4d13 684 GetTreeCtrl()->SetImageList(imageList);
eca15c0d
VZ
685}
686
687// ----------------------------------------------------------------------------
688// event handlers
689// ----------------------------------------------------------------------------
690
691void wxTreebook::OnTreeSelectionChange(wxTreeEvent& event)
692{
447325a4
VZ
693 if ( event.GetEventObject() != m_bookctrl )
694 {
695 event.Skip();
696 return;
697 }
698
eca15c0d
VZ
699 wxTreeItemId newId = event.GetItem();
700
701 if ( (m_selection == wxNOT_FOUND &&
2ddb4d13 702 (!newId.IsOk() || newId == GetTreeCtrl()->GetRootItem())) ||
eca15c0d
VZ
703 (m_selection != wxNOT_FOUND && newId == m_treeIds[m_selection]) )
704 {
705 // this event can only come when we modify the tree selection ourselves
706 // so we should simply ignore it
707 return;
708 }
709
710 int newPos = DoInternalFindPageById(newId);
711
712 if ( newPos != wxNOT_FOUND )
713 SetSelection( newPos );
714}
715
716void wxTreebook::OnTreeNodeExpandedCollapsed(wxTreeEvent & event)
717{
447325a4
VZ
718 if ( event.GetEventObject() != m_bookctrl )
719 {
720 event.Skip();
721 return;
722 }
723
eca15c0d 724 wxTreeItemId nodeId = event.GetItem();
2ddb4d13 725 if ( !nodeId.IsOk() || nodeId == GetTreeCtrl()->GetRootItem() )
eca15c0d
VZ
726 return;
727 int pagePos = DoInternalFindPageById(nodeId);
728 wxCHECK_RET( pagePos != wxNOT_FOUND, wxT("Internal problem in wxTreebook!..") );
729
2ddb4d13 730 wxTreebookEvent ev(GetTreeCtrl()->IsExpanded(nodeId)
eca15c0d
VZ
731 ? wxEVT_COMMAND_TREEBOOK_NODE_EXPANDED
732 : wxEVT_COMMAND_TREEBOOK_NODE_COLLAPSED,
733 m_windowId);
734
735 ev.SetSelection(pagePos);
736 ev.SetOldSelection(pagePos);
737 ev.SetEventObject(this);
738
739 GetEventHandler()->ProcessEvent(ev);
740}
741
742// ----------------------------------------------------------------------------
743// wxTreebook geometry management
744// ----------------------------------------------------------------------------
745
d0a84b63 746int wxTreebook::HitTest(wxPoint const & pt, long * flags) const
eca15c0d 747{
851b88c3 748 int pagePos = wxNOT_FOUND;
eca15c0d 749
d0a84b63 750 if ( flags )
9804d540 751 *flags = wxBK_HITTEST_NOWHERE;
851b88c3 752
d0a84b63
VZ
753 // convert from wxTreebook coorindates to wxTreeCtrl ones
754 const wxTreeCtrl * const tree = GetTreeCtrl();
755 const wxPoint treePt = tree->ScreenToClient(ClientToScreen(pt));
756
757 // is it over the tree?
22a35096 758 if ( wxRect(tree->GetSize()).Contains(treePt) )
eca15c0d 759 {
851b88c3
VZ
760 int flagsTree;
761 wxTreeItemId id = tree->HitTest(treePt, flagsTree);
762
763 if ( id.IsOk() && (flagsTree & wxTREE_HITTEST_ONITEM) )
764 {
765 pagePos = DoInternalFindPageById(id);
766 }
d0a84b63
VZ
767
768 if ( flags )
769 {
770 if ( pagePos != wxNOT_FOUND )
771 *flags = 0;
772
773 if ( flagsTree & (wxTREE_HITTEST_ONITEMBUTTON |
774 wxTREE_HITTEST_ONITEMICON |
775 wxTREE_HITTEST_ONITEMSTATEICON) )
9804d540 776 *flags |= wxBK_HITTEST_ONICON;
d0a84b63
VZ
777
778 if ( flagsTree & wxTREE_HITTEST_ONITEMLABEL )
9804d540 779 *flags |= wxBK_HITTEST_ONLABEL;
d0a84b63
VZ
780 }
781 }
782 else // not over the tree
783 {
22a35096 784 if ( flags && GetPageRect().Contains( pt ) )
9804d540 785 *flags |= wxBK_HITTEST_ONPAGE;
eca15c0d
VZ
786 }
787
851b88c3 788 return pagePos;
eca15c0d
VZ
789}
790
791#endif // wxUSE_TREEBOOK