1 /////////////////////////////////////////////////////////////////////////////
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
12 // ============================================================================
14 // ============================================================================
16 // ----------------------------------------------------------------------------
18 // ----------------------------------------------------------------------------
20 #pragma implementation "treectrl.h"
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
34 #if defined(__WIN95__)
37 #include "wx/dynarray.h"
38 #include "wx/imaglist.h"
39 #include "wx/msw/treectrl.h"
41 #include "wx/msw/private.h"
44 #include "wx/msw/gnuwin32/extra.h"
47 #if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__)
51 // Bug in headers, sometimes
53 #define TVIS_FOCUSED 0x0001
56 // ----------------------------------------------------------------------------
58 // ----------------------------------------------------------------------------
60 // a convenient wrapper around TV_ITEM struct which adds a ctor
61 struct wxTreeViewItem
: public TV_ITEM
63 wxTreeViewItem(const wxTreeItemId
& item
,
64 UINT mask_
, UINT stateMask_
= 0)
67 stateMask
= stateMask_
;
68 hItem
= (HTREEITEM
) (WXHTREEITEM
) item
;
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 #if !USE_SHARED_LIBRARY
77 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxControl
)
80 // hide the ugly cast (of course, the macro is _quite_ ugly too...)
81 #define wxhWnd ((HWND)m_hWnd)
83 // ----------------------------------------------------------------------------
85 // ----------------------------------------------------------------------------
87 // handy table for sending events
88 static const wxEventType g_events
[2][2] =
90 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED
, wxEVT_COMMAND_TREE_ITEM_COLLAPSING
},
91 { wxEVT_COMMAND_TREE_ITEM_EXPANDED
, wxEVT_COMMAND_TREE_ITEM_EXPANDING
}
94 // ============================================================================
96 // ============================================================================
98 // ----------------------------------------------------------------------------
99 // construction and destruction
100 // ----------------------------------------------------------------------------
102 void wxTreeCtrl::Init()
104 m_imageListNormal
= NULL
;
105 m_imageListState
= NULL
;
109 bool wxTreeCtrl::Create(wxWindow
*parent
, wxWindowID id
,
110 const wxPoint
& pos
, const wxSize
& size
,
111 long style
, const wxValidator
& validator
,
112 const wxString
& name
)
116 wxSystemSettings settings
;
119 SetValidator(validator
);
121 m_windowStyle
= style
;
125 m_windowId
= (id
== -1) ? NewControlId() : id
;
127 DWORD wstyle
= WS_VISIBLE
| WS_CHILD
| WS_TABSTOP
| TVS_HASLINES
| TVS_SHOWSELALWAYS
;
131 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
) ;
133 // Even with extended styles, need to combine with WS_BORDER
134 // for them to look right.
135 if ( want3D
|| wxStyleHasBorder(m_windowStyle
) )
140 if ( m_windowStyle
& wxTR_HAS_BUTTONS
)
141 wstyle
|= TVS_HASBUTTONS
;
143 if ( m_windowStyle
& wxTR_EDIT_LABELS
)
144 wstyle
|= TVS_EDITLABELS
;
146 if ( m_windowStyle
& wxTR_LINES_AT_ROOT
)
147 wstyle
|= TVS_LINESATROOT
;
149 // Create the tree control.
150 m_hWnd
= (WXHWND
)::CreateWindowEx
156 pos
.x
, pos
.y
, size
.x
, size
.y
,
157 (HWND
)parent
->GetHWND(),
163 wxCHECK_MSG( m_hWnd
, FALSE
, "Failed to create tree ctrl" );
166 parent
->AddChild(this);
173 wxTreeCtrl::~wxTreeCtrl()
177 // delete user data to prevent memory leaks
181 // ----------------------------------------------------------------------------
183 // ----------------------------------------------------------------------------
185 // simple wrappers which add error checking in debug mode
187 bool wxTreeCtrl::DoGetItem(wxTreeViewItem
* tvItem
) const
189 if ( !TreeView_GetItem(wxhWnd
, tvItem
) )
191 wxLogLastError("TreeView_GetItem");
199 void wxTreeCtrl::DoSetItem(wxTreeViewItem
* tvItem
)
201 if ( TreeView_SetItem(wxhWnd
, tvItem
) == -1 )
203 wxLogLastError("TreeView_SetItem");
207 size_t wxTreeCtrl::GetCount() const
209 return (size_t)TreeView_GetCount(wxhWnd
);
212 unsigned int wxTreeCtrl::GetIndent() const
214 return TreeView_GetIndent(wxhWnd
);
217 void wxTreeCtrl::SetIndent(unsigned int indent
)
219 TreeView_SetIndent(wxhWnd
, indent
);
222 wxImageList
*wxTreeCtrl::GetImageList() const
224 return m_imageListNormal
;
227 wxImageList
*wxTreeCtrl::GetStateImageList() const
229 return m_imageListNormal
;
232 void wxTreeCtrl::SetAnyImageList(wxImageList
*imageList
, int which
)
235 TreeView_SetImageList(wxhWnd
,
236 imageList
? imageList
->GetHIMAGELIST() : 0,
240 void wxTreeCtrl::SetImageList(wxImageList
*imageList
)
242 SetAnyImageList(m_imageListNormal
= imageList
, TVSIL_NORMAL
);
245 void wxTreeCtrl::SetStateImageList(wxImageList
*imageList
)
247 SetAnyImageList(m_imageListState
= imageList
, TVSIL_STATE
);
250 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
)
256 wxArrayLong children
;
257 wxTreeItemId child
= GetFirstChild(item
, cookie
);
258 while ( child
.IsOk() )
263 result
+= GetChildrenCount(child
, TRUE
);
266 // add the child to the result in any case
269 child
= GetNextChild(item
, cookie
);
275 // ----------------------------------------------------------------------------
277 // ----------------------------------------------------------------------------
279 wxString
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const
281 char buf
[512]; // the size is arbitrary...
283 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
284 tvItem
.pszText
= buf
;
285 tvItem
.cchTextMax
= WXSIZEOF(buf
);
286 if ( !DoGetItem(&tvItem
) )
288 // don't return some garbage which was on stack, but an empty string
292 return wxString(buf
);
295 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
)
297 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
298 tvItem
.pszText
= (char *)text
.c_str(); // conversion is ok
302 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const
304 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
307 return tvItem
.iImage
;
310 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
)
312 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
313 tvItem
.iImage
= image
;
317 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const
319 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
322 return tvItem
.iSelectedImage
;
325 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
)
327 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
328 tvItem
.iSelectedImage
= image
;
332 wxTreeItemData
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const
334 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
335 if ( !DoGetItem(&tvItem
) )
340 return (wxTreeItemData
*)tvItem
.lParam
;
343 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
)
345 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
346 tvItem
.lParam
= (LPARAM
)data
;
350 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
352 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
353 tvItem
.cChildren
= (int)has
;
357 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
359 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
360 tvItem
.state
= bold
? TVIS_BOLD
: 0;
364 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId
& item
, bool highlight
)
366 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_DROPHILITED
);
367 tvItem
.state
= highlight
? TVIS_DROPHILITED
: 0;
371 // ----------------------------------------------------------------------------
373 // ----------------------------------------------------------------------------
375 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& item
) const
377 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
379 return SendMessage(wxhWnd
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&rect
) != 0;
383 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const
385 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
388 return tvItem
.cChildren
!= 0;
391 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const
393 // probably not a good idea to put it here
394 //wxASSERT( ItemHasChildren(item) );
396 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_EXPANDED
);
399 return (tvItem
.state
& TVIS_EXPANDED
) != 0;
402 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const
404 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_SELECTED
);
407 return (tvItem
.state
& TVIS_SELECTED
) != 0;
410 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const
412 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
415 return (tvItem
.state
& TVIS_BOLD
) != 0;
418 // ----------------------------------------------------------------------------
420 // ----------------------------------------------------------------------------
422 wxTreeItemId
wxTreeCtrl::GetRootItem() const
424 return wxTreeItemId((WXHTREEITEM
) TreeView_GetRoot(wxhWnd
));
427 wxTreeItemId
wxTreeCtrl::GetSelection() const
429 return wxTreeItemId((WXHTREEITEM
) TreeView_GetSelection(wxhWnd
));
432 wxTreeItemId
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const
434 return wxTreeItemId((WXHTREEITEM
) TreeView_GetParent(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
437 wxTreeItemId
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
,
440 // remember the last child returned in 'cookie'
441 _cookie
= (long)TreeView_GetChild(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
)item
);
443 return wxTreeItemId((WXHTREEITEM
)_cookie
);
446 wxTreeItemId
wxTreeCtrl::GetNextChild(const wxTreeItemId
& WXUNUSED(item
),
449 wxTreeItemId l
= wxTreeItemId((WXHTREEITEM
)TreeView_GetNextSibling(wxhWnd
,
450 (HTREEITEM
)(WXHTREEITEM
)_cookie
));
456 wxTreeItemId
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const
458 // can this be done more efficiently?
461 wxTreeItemId childLast
,
462 child
= GetFirstChild(item
, cookie
);
463 while ( child
.IsOk() )
466 child
= GetNextChild(item
, cookie
);
472 wxTreeItemId
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const
474 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextSibling(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
477 wxTreeItemId
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
479 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevSibling(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
482 wxTreeItemId
wxTreeCtrl::GetFirstVisibleItem() const
484 return wxTreeItemId((WXHTREEITEM
) TreeView_GetFirstVisible(wxhWnd
));
487 wxTreeItemId
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const
489 wxASSERT_MSG( IsVisible(item
), "The item you call GetNextVisible() "
490 "for must be visible itself!");
492 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
495 wxTreeItemId
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const
497 wxASSERT_MSG( IsVisible(item
), "The item you call GetPrevVisible() "
498 "for must be visible itself!");
500 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
503 // ----------------------------------------------------------------------------
505 // ----------------------------------------------------------------------------
507 wxTreeItemId
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parent
,
508 wxTreeItemId hInsertAfter
,
509 const wxString
& text
,
510 int image
, int selectedImage
,
511 wxTreeItemData
*data
)
513 TV_INSERTSTRUCT tvIns
;
514 tvIns
.hParent
= (HTREEITEM
) (WXHTREEITEM
)parent
;
515 tvIns
.hInsertAfter
= (HTREEITEM
) (WXHTREEITEM
) hInsertAfter
;
517 // This is how we insert the item as the first child: supply a NULL hInsertAfter
518 if (tvIns
.hInsertAfter
== (HTREEITEM
) 0)
520 tvIns
.hInsertAfter
= TVI_FIRST
;
524 if ( !text
.IsEmpty() )
527 tvIns
.item
.pszText
= (char *)text
.c_str(); // cast is ok
533 tvIns
.item
.iImage
= image
;
535 if ( selectedImage
== -1 )
537 // take the same image for selected icon if not specified
538 selectedImage
= image
;
542 if ( selectedImage
!= -1 )
544 mask
|= TVIF_SELECTEDIMAGE
;
545 tvIns
.item
.iSelectedImage
= selectedImage
;
551 tvIns
.item
.lParam
= (LPARAM
)data
;
554 tvIns
.item
.mask
= mask
;
556 HTREEITEM id
= (HTREEITEM
) TreeView_InsertItem(wxhWnd
, &tvIns
);
559 wxLogLastError("TreeView_InsertItem");
564 // associate the application tree item with Win32 tree item handle
565 data
->SetId((WXHTREEITEM
)id
);
568 return wxTreeItemId((WXHTREEITEM
)id
);
571 // for compatibility only
572 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
573 const wxString
& text
,
574 int image
, int selImage
,
577 return DoInsertItem(parent
, (WXHTREEITEM
)insertAfter
, text
,
578 image
, selImage
, NULL
);
581 wxTreeItemId
wxTreeCtrl::AddRoot(const wxString
& text
,
582 int image
, int selectedImage
,
583 wxTreeItemData
*data
)
585 return DoInsertItem(wxTreeItemId((WXHTREEITEM
) 0), (WXHTREEITEM
) 0,
586 text
, image
, selectedImage
, data
);
589 wxTreeItemId
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
,
590 const wxString
& text
,
591 int image
, int selectedImage
,
592 wxTreeItemData
*data
)
594 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_FIRST
,
595 text
, image
, selectedImage
, data
);
598 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
599 const wxTreeItemId
& idPrevious
,
600 const wxString
& text
,
601 int image
, int selectedImage
,
602 wxTreeItemData
*data
)
604 return DoInsertItem(parent
, idPrevious
, text
, image
, selectedImage
, data
);
607 wxTreeItemId
wxTreeCtrl::AppendItem(const wxTreeItemId
& parent
,
608 const wxString
& text
,
609 int image
, int selectedImage
,
610 wxTreeItemData
*data
)
612 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_LAST
,
613 text
, image
, selectedImage
, data
);
616 void wxTreeCtrl::Delete(const wxTreeItemId
& item
)
618 if ( !TreeView_DeleteItem(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
) )
620 wxLogLastError("TreeView_DeleteItem");
624 // delete all children (but don't delete the item itself)
625 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& item
)
629 wxArrayLong children
;
630 wxTreeItemId child
= GetFirstChild(item
, cookie
);
631 while ( child
.IsOk() )
633 children
.Add((long)(WXHTREEITEM
)child
);
635 child
= GetNextChild(item
, cookie
);
638 size_t nCount
= children
.Count();
639 for ( size_t n
= 0; n
< nCount
; n
++ )
641 if ( !TreeView_DeleteItem(wxhWnd
, (HTREEITEM
)children
[n
]) )
643 wxLogLastError("TreeView_DeleteItem");
648 void wxTreeCtrl::DeleteAllItems()
650 if ( !TreeView_DeleteAllItems(wxhWnd
) )
652 wxLogLastError("TreeView_DeleteAllItems");
656 void wxTreeCtrl::DoExpand(const wxTreeItemId
& item
, int flag
)
658 wxASSERT_MSG( flag
== TVE_COLLAPSE
||
659 flag
== (TVE_COLLAPSE
| TVE_COLLAPSERESET
) ||
660 flag
== TVE_EXPAND
||
662 "Unknown flag in wxTreeCtrl::DoExpand" );
664 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
666 if ( TreeView_Expand(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
, flag
) != 0 )
668 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
671 bool isExpanded
= IsExpanded(item
);
673 event
.SetEventObject(this);
675 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
676 event
.SetEventType(g_events
[isExpanded
][TRUE
]);
677 GetEventHandler()->ProcessEvent(event
);
679 event
.SetEventType(g_events
[isExpanded
][FALSE
]);
680 GetEventHandler()->ProcessEvent(event
);
684 // I wonder if it really ever happens...
685 wxLogDebug("TreeView_Expand: change didn't took place.");
689 void wxTreeCtrl::Expand(const wxTreeItemId
& item
)
691 DoExpand(item
, TVE_EXPAND
);
694 void wxTreeCtrl::Collapse(const wxTreeItemId
& item
)
696 DoExpand(item
, TVE_COLLAPSE
);
699 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
)
701 DoExpand(item
, TVE_COLLAPSE
| TVE_COLLAPSERESET
);
704 void wxTreeCtrl::Toggle(const wxTreeItemId
& item
)
706 DoExpand(item
, TVE_TOGGLE
);
709 void wxTreeCtrl::ExpandItem(const wxTreeItemId
& item
, int action
)
711 DoExpand(item
, action
);
714 void wxTreeCtrl::Unselect()
716 SelectItem(wxTreeItemId((WXHTREEITEM
) 0));
719 void wxTreeCtrl::SelectItem(const wxTreeItemId
& item
)
721 if ( !TreeView_SelectItem(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
) )
723 wxLogLastError("TreeView_SelectItem");
727 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
)
730 TreeView_EnsureVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
);
733 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& item
)
735 if ( !TreeView_SelectSetFirstVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
) )
737 wxLogLastError("TreeView_SelectSetFirstVisible");
741 wxTextCtrl
* wxTreeCtrl::GetEditControl() const
746 void wxTreeCtrl::DeleteTextCtrl()
750 m_textCtrl
->UnsubclassWin();
751 m_textCtrl
->SetHWND(0);
757 wxTextCtrl
* wxTreeCtrl::EditLabel(const wxTreeItemId
& item
,
758 wxClassInfo
* textControlClass
)
760 wxASSERT( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)) );
762 HWND hWnd
= (HWND
) TreeView_EditLabel(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
);
764 wxCHECK_MSG( hWnd
, NULL
, "Can't edit tree ctrl label" );
768 m_textCtrl
= (wxTextCtrl
*)textControlClass
->CreateObject();
769 m_textCtrl
->SetHWND((WXHWND
)hWnd
);
770 m_textCtrl
->SubclassWin((WXHWND
)hWnd
);
775 // End label editing, optionally cancelling the edit
776 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& item
, bool discardChanges
)
778 TreeView_EndEditLabelNow(wxhWnd
, discardChanges
);
783 wxTreeItemId
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
)
785 TV_HITTESTINFO hitTestInfo
;
786 hitTestInfo
.pt
.x
= (int)point
.x
;
787 hitTestInfo
.pt
.y
= (int)point
.y
;
789 TreeView_HitTest(wxhWnd
, &hitTestInfo
);
794 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
795 flags |= wxTREE_HITTEST_##flag
797 TRANSLATE_FLAG(ABOVE
);
798 TRANSLATE_FLAG(BELOW
);
799 TRANSLATE_FLAG(NOWHERE
);
800 TRANSLATE_FLAG(ONITEMBUTTON
);
801 TRANSLATE_FLAG(ONITEMICON
);
802 TRANSLATE_FLAG(ONITEMINDENT
);
803 TRANSLATE_FLAG(ONITEMLABEL
);
804 TRANSLATE_FLAG(ONITEMRIGHT
);
805 TRANSLATE_FLAG(ONITEMSTATEICON
);
806 TRANSLATE_FLAG(TOLEFT
);
807 TRANSLATE_FLAG(TORIGHT
);
809 #undef TRANSLATE_FLAG
811 return wxTreeItemId((WXHTREEITEM
) hitTestInfo
.hItem
);
814 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
,
819 if ( TreeView_GetItemRect(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
,
822 rect
= wxRect(wxPoint(rc
.left
, rc
.top
), wxPoint(rc
.right
, rc
.bottom
));
828 // couldn't retrieve rect: for example, item isn't visible
833 // ----------------------------------------------------------------------------
835 // ----------------------------------------------------------------------------
837 static int CALLBACK
TreeView_CompareCallback(wxTreeItemData
*pItem1
,
838 wxTreeItemData
*pItem2
,
841 wxCHECK_MSG( pItem1
&& pItem2
, 0,
842 _T("sorting tree without data doesn't make sense") );
844 return tree
->OnCompareItems(pItem1
->GetId(), pItem2
->GetId());
847 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
,
848 const wxTreeItemId
& item2
)
850 return strcmp(GetItemText(item1
), GetItemText(item2
));
853 void wxTreeCtrl::SortChildren(const wxTreeItemId
& item
)
855 // rely on the fact that TreeView_SortChildren does the same thing as our
856 // default behaviour, i.e. sorts items alphabetically and so call it
857 // directly if we're not in derived class (much more efficient!)
858 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl
) )
860 TreeView_SortChildren(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
, 0);
865 tvSort
.hParent
= (HTREEITEM
)(WXHTREEITEM
)item
;
866 tvSort
.lpfnCompare
= (PFNTVCOMPARE
)TreeView_CompareCallback
;
867 tvSort
.lParam
= (LPARAM
)this;
868 TreeView_SortChildrenCB(wxhWnd
, &tvSort
, 0 /* reserved */);
872 // ----------------------------------------------------------------------------
874 // ----------------------------------------------------------------------------
876 bool wxTreeCtrl::MSWCommand(WXUINT cmd
, WXWORD id
)
878 if ( cmd
== EN_UPDATE
)
880 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, id
);
881 event
.SetEventObject( this );
882 ProcessCommand(event
);
884 else if ( cmd
== EN_KILLFOCUS
)
886 wxCommandEvent
event(wxEVT_KILL_FOCUS
, id
);
887 event
.SetEventObject( this );
888 ProcessCommand(event
);
900 // process WM_NOTIFY Windows message
901 bool wxTreeCtrl::MSWOnNotify(int idCtrl
, WXLPARAM lParam
, WXLPARAM
*result
)
903 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
904 wxEventType eventType
= wxEVT_NULL
;
905 NMHDR
*hdr
= (NMHDR
*)lParam
;
910 eventType
= wxEVT_COMMAND_TREE_BEGIN_DRAG
;
915 if ( eventType
== wxEVT_NULL
)
916 eventType
= wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
917 //else: left drag, already set above
919 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
921 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
922 event
.m_pointDrag
= wxPoint(tv
->ptDrag
.x
, tv
->ptDrag
.y
);
926 case TVN_BEGINLABELEDIT
:
928 eventType
= wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
;
929 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
931 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
937 eventType
= wxEVT_COMMAND_TREE_DELETE_ITEM
;
938 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
940 event
.m_item
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
944 case TVN_ENDLABELEDIT
:
946 eventType
= wxEVT_COMMAND_TREE_END_LABEL_EDIT
;
947 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
949 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
953 case TVN_GETDISPINFO
:
954 eventType
= wxEVT_COMMAND_TREE_GET_INFO
;
957 case TVN_SETDISPINFO
:
959 if ( eventType
== wxEVT_NULL
)
960 eventType
= wxEVT_COMMAND_TREE_SET_INFO
;
961 //else: get, already set above
963 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
965 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
969 case TVN_ITEMEXPANDING
:
970 event
.m_code
= FALSE
;
973 case TVN_ITEMEXPANDED
:
975 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
978 switch ( tv
->action
)
989 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
990 "message", tv
->action
);
993 bool ing
= (hdr
->code
== TVN_ITEMEXPANDING
);
994 eventType
= g_events
[expand
][ing
];
996 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
1002 eventType
= wxEVT_COMMAND_TREE_KEY_DOWN
;
1003 TV_KEYDOWN
*info
= (TV_KEYDOWN
*)lParam
;
1005 event
.m_code
= wxCharCodeMSWToWX(info
->wVKey
);
1007 // a separate event for this case
1008 if ( info
->wVKey
== VK_SPACE
|| info
->wVKey
== VK_RETURN
)
1010 wxTreeEvent
event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
,
1012 event2
.SetEventObject(this);
1014 GetEventHandler()->ProcessEvent(event2
);
1019 case TVN_SELCHANGED
:
1020 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGED
;
1023 case TVN_SELCHANGING
:
1025 if ( eventType
== wxEVT_NULL
)
1026 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGING
;
1027 //else: already set above
1029 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1031 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
1032 event
.m_itemOld
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
1037 return wxControl::MSWOnNotify(idCtrl
, lParam
, result
);
1040 event
.SetEventObject(this);
1041 event
.SetEventType(eventType
);
1043 bool processed
= GetEventHandler()->ProcessEvent(event
);
1046 if ( hdr
->code
== TVN_DELETEITEM
)
1048 // NB: we might process this message using wxWindows event tables, but
1049 // due to overhead of wxWin event system we prefer to do it here
1050 // (otherwise deleting a tree with many items is just too slow)
1051 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1052 wxTreeItemData
*data
= (wxTreeItemData
*)tv
->itemOld
.lParam
;
1053 delete data
; // may be NULL, ok
1054 processed
= TRUE
; // Make sure we don't get called twice
1057 *result
= !event
.IsAllowed();
1062 // ----------------------------------------------------------------------------
1064 // ----------------------------------------------------------------------------
1066 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
)
1068 wxTreeEvent::wxTreeEvent(wxEventType commandType
, int id
)
1069 : wxNotifyEvent(commandType
, id
)