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__)
67 // Bug in headers, sometimes
69 #define TVIS_FOCUSED 0x0001
72 // ----------------------------------------------------------------------------
74 // ----------------------------------------------------------------------------
76 // a convenient wrapper around TV_ITEM struct which adds a ctor
77 struct wxTreeViewItem
: public TV_ITEM
79 wxTreeViewItem(const wxTreeItemId
& item
,
80 UINT mask_
, UINT stateMask_
= 0)
83 stateMask
= stateMask_
;
84 hItem
= (HTREEITEM
) (WXHTREEITEM
) item
;
88 // ----------------------------------------------------------------------------
90 // ----------------------------------------------------------------------------
92 #if !USE_SHARED_LIBRARY
93 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl
, wxControl
)
96 // hide the ugly cast (of course, the macro is _quite_ ugly too...)
97 #define wxhWnd ((HWND)m_hWnd)
99 // ----------------------------------------------------------------------------
101 // ----------------------------------------------------------------------------
103 // handy table for sending events
104 static const wxEventType g_events
[2][2] =
106 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED
, wxEVT_COMMAND_TREE_ITEM_COLLAPSING
},
107 { wxEVT_COMMAND_TREE_ITEM_EXPANDED
, wxEVT_COMMAND_TREE_ITEM_EXPANDING
}
110 // ============================================================================
112 // ============================================================================
114 // ----------------------------------------------------------------------------
115 // construction and destruction
116 // ----------------------------------------------------------------------------
118 void wxTreeCtrl::Init()
120 m_imageListNormal
= NULL
;
121 m_imageListState
= NULL
;
125 bool wxTreeCtrl::Create(wxWindow
*parent
, wxWindowID id
,
126 const wxPoint
& pos
, const wxSize
& size
,
127 long style
, const wxValidator
& validator
,
128 const wxString
& name
)
132 wxSystemSettings settings
;
135 SetValidator(validator
);
137 m_windowStyle
= style
;
141 m_windowId
= (id
== -1) ? NewControlId() : id
;
143 DWORD wstyle
= WS_VISIBLE
| WS_CHILD
| WS_TABSTOP
| TVS_HASLINES
;
146 WXDWORD exStyle
= Determine3DEffects(WS_EX_CLIENTEDGE
, &want3D
) ;
148 // Even with extended styles, need to combine with WS_BORDER
149 // for them to look right.
150 if ( want3D
|| wxStyleHasBorder(m_windowStyle
) )
155 if ( m_windowStyle
& wxTR_HAS_BUTTONS
)
156 wstyle
|= TVS_HASBUTTONS
;
158 if ( m_windowStyle
& wxTR_EDIT_LABELS
)
159 wstyle
|= TVS_EDITLABELS
;
161 if ( m_windowStyle
& wxTR_LINES_AT_ROOT
)
162 wstyle
|= TVS_LINESATROOT
;
164 // Create the tree control.
165 m_hWnd
= (WXHWND
)::CreateWindowEx
171 pos
.x
, pos
.y
, size
.x
, size
.y
,
172 (HWND
)parent
->GetHWND(),
178 wxCHECK_MSG( m_hWnd
, FALSE
, "Failed to create tree ctrl" );
181 parent
->AddChild(this);
188 wxTreeCtrl::~wxTreeCtrl()
192 // delete user data to prevent memory leaks
196 // ----------------------------------------------------------------------------
198 // ----------------------------------------------------------------------------
200 // simple wrappers which add error checking in debug mode
202 bool wxTreeCtrl::DoGetItem(wxTreeViewItem
* tvItem
) const
204 if ( !TreeView_GetItem(wxhWnd
, tvItem
) )
206 wxLogLastError("TreeView_GetItem");
214 void wxTreeCtrl::DoSetItem(wxTreeViewItem
* tvItem
)
216 if ( TreeView_SetItem(wxhWnd
, tvItem
) == -1 )
218 wxLogLastError("TreeView_SetItem");
222 size_t wxTreeCtrl::GetCount() const
224 return (size_t)TreeView_GetCount(wxhWnd
);
227 unsigned int wxTreeCtrl::GetIndent() const
229 return TreeView_GetIndent(wxhWnd
);
232 void wxTreeCtrl::SetIndent(unsigned int indent
)
234 TreeView_SetIndent(wxhWnd
, indent
);
237 wxImageList
*wxTreeCtrl::GetImageList() const
239 return m_imageListNormal
;
242 wxImageList
*wxTreeCtrl::GetStateImageList() const
244 return m_imageListNormal
;
247 void wxTreeCtrl::SetAnyImageList(wxImageList
*imageList
, int which
)
250 TreeView_SetImageList(wxhWnd
,
251 imageList
? imageList
->GetHIMAGELIST() : 0,
255 void wxTreeCtrl::SetImageList(wxImageList
*imageList
)
257 SetAnyImageList(m_imageListNormal
= imageList
, TVSIL_NORMAL
);
260 void wxTreeCtrl::SetStateImageList(wxImageList
*imageList
)
262 SetAnyImageList(m_imageListState
= imageList
, TVSIL_STATE
);
265 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId
& item
, bool recursively
)
271 wxArrayLong children
;
272 wxTreeItemId child
= GetFirstChild(item
, cookie
);
273 while ( child
.IsOk() )
278 result
+= GetChildrenCount(child
, TRUE
);
281 // add the child to the result in any case
284 child
= GetNextChild(item
, cookie
);
290 // ----------------------------------------------------------------------------
292 // ----------------------------------------------------------------------------
294 wxString
wxTreeCtrl::GetItemText(const wxTreeItemId
& item
) const
296 char buf
[512]; // the size is arbitrary...
298 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
299 tvItem
.pszText
= buf
;
300 tvItem
.cchTextMax
= WXSIZEOF(buf
);
301 if ( !DoGetItem(&tvItem
) )
303 // don't return some garbage which was on stack, but an empty string
307 return wxString(buf
);
310 void wxTreeCtrl::SetItemText(const wxTreeItemId
& item
, const wxString
& text
)
312 wxTreeViewItem
tvItem(item
, TVIF_TEXT
);
313 tvItem
.pszText
= (char *)text
.c_str(); // conversion is ok
317 int wxTreeCtrl::GetItemImage(const wxTreeItemId
& item
) const
319 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
322 return tvItem
.iImage
;
325 void wxTreeCtrl::SetItemImage(const wxTreeItemId
& item
, int image
)
327 wxTreeViewItem
tvItem(item
, TVIF_IMAGE
);
328 tvItem
.iImage
= image
;
332 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId
& item
) const
334 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
337 return tvItem
.iSelectedImage
;
340 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId
& item
, int image
)
342 wxTreeViewItem
tvItem(item
, TVIF_SELECTEDIMAGE
);
343 tvItem
.iSelectedImage
= image
;
347 wxTreeItemData
*wxTreeCtrl::GetItemData(const wxTreeItemId
& item
) const
349 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
350 if ( !DoGetItem(&tvItem
) )
355 return (wxTreeItemData
*)tvItem
.lParam
;
358 void wxTreeCtrl::SetItemData(const wxTreeItemId
& item
, wxTreeItemData
*data
)
360 wxTreeViewItem
tvItem(item
, TVIF_PARAM
);
361 tvItem
.lParam
= (LPARAM
)data
;
365 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId
& item
, bool has
)
367 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
368 tvItem
.cChildren
= (int)has
;
372 void wxTreeCtrl::SetItemBold(const wxTreeItemId
& item
, bool bold
)
374 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
375 tvItem
.state
= bold
? TVIS_BOLD
: 0;
379 // ----------------------------------------------------------------------------
381 // ----------------------------------------------------------------------------
383 bool wxTreeCtrl::IsVisible(const wxTreeItemId
& item
) const
385 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
387 return SendMessage(wxhWnd
, TVM_GETITEMRECT
, FALSE
, (LPARAM
)&rect
) != 0;
391 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId
& item
) const
393 wxTreeViewItem
tvItem(item
, TVIF_CHILDREN
);
396 return tvItem
.cChildren
!= 0;
399 bool wxTreeCtrl::IsExpanded(const wxTreeItemId
& item
) const
401 // probably not a good idea to put it here
402 //wxASSERT( ItemHasChildren(item) );
404 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_EXPANDED
);
407 return (tvItem
.state
& TVIS_EXPANDED
) != 0;
410 bool wxTreeCtrl::IsSelected(const wxTreeItemId
& item
) const
412 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_SELECTED
);
415 return (tvItem
.state
& TVIS_SELECTED
) != 0;
418 bool wxTreeCtrl::IsBold(const wxTreeItemId
& item
) const
420 wxTreeViewItem
tvItem(item
, TVIF_STATE
, TVIS_BOLD
);
423 return (tvItem
.state
& TVIS_BOLD
) != 0;
426 // ----------------------------------------------------------------------------
428 // ----------------------------------------------------------------------------
430 wxTreeItemId
wxTreeCtrl::GetRootItem() const
432 return wxTreeItemId((WXHTREEITEM
) TreeView_GetRoot(wxhWnd
));
435 wxTreeItemId
wxTreeCtrl::GetSelection() const
437 return wxTreeItemId((WXHTREEITEM
) TreeView_GetSelection(wxhWnd
));
440 wxTreeItemId
wxTreeCtrl::GetParent(const wxTreeItemId
& item
) const
442 return wxTreeItemId((WXHTREEITEM
) TreeView_GetParent(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
445 wxTreeItemId
wxTreeCtrl::GetFirstChild(const wxTreeItemId
& item
,
448 // remember the last child returned in 'cookie'
449 _cookie
= (long)TreeView_GetChild(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
)item
);
451 return wxTreeItemId((WXHTREEITEM
)_cookie
);
454 wxTreeItemId
wxTreeCtrl::GetNextChild(const wxTreeItemId
& WXUNUSED(item
),
457 wxTreeItemId l
= wxTreeItemId((WXHTREEITEM
)TreeView_GetNextSibling(wxhWnd
,
458 (HTREEITEM
)(WXHTREEITEM
)_cookie
));
464 wxTreeItemId
wxTreeCtrl::GetLastChild(const wxTreeItemId
& item
) const
466 // can this be done more efficiently?
469 wxTreeItemId childLast
,
470 child
= GetFirstChild(item
, cookie
);
471 while ( child
.IsOk() )
474 child
= GetNextChild(item
, cookie
);
480 wxTreeItemId
wxTreeCtrl::GetNextSibling(const wxTreeItemId
& item
) const
482 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextSibling(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
485 wxTreeItemId
wxTreeCtrl::GetPrevSibling(const wxTreeItemId
& item
) const
487 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevSibling(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
490 wxTreeItemId
wxTreeCtrl::GetFirstVisibleItem() const
492 return wxTreeItemId((WXHTREEITEM
) TreeView_GetFirstVisible(wxhWnd
));
495 wxTreeItemId
wxTreeCtrl::GetNextVisible(const wxTreeItemId
& item
) const
497 wxASSERT_MSG( IsVisible(item
), "The item you call GetNextVisible() "
498 "for must be visible itself!");
500 return wxTreeItemId((WXHTREEITEM
) TreeView_GetNextVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
503 wxTreeItemId
wxTreeCtrl::GetPrevVisible(const wxTreeItemId
& item
) const
505 wxASSERT_MSG( IsVisible(item
), "The item you call GetPrevVisible() "
506 "for must be visible itself!");
508 return wxTreeItemId((WXHTREEITEM
) TreeView_GetPrevVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
));
511 // ----------------------------------------------------------------------------
513 // ----------------------------------------------------------------------------
515 wxTreeItemId
wxTreeCtrl::DoInsertItem(const wxTreeItemId
& parent
,
516 wxTreeItemId hInsertAfter
,
517 const wxString
& text
,
518 int image
, int selectedImage
,
519 wxTreeItemData
*data
)
521 TV_INSERTSTRUCT tvIns
;
522 tvIns
.hParent
= (HTREEITEM
) (WXHTREEITEM
)parent
;
523 tvIns
.hInsertAfter
= (HTREEITEM
) (WXHTREEITEM
) hInsertAfter
;
525 if ( !text
.IsEmpty() )
528 tvIns
.item
.pszText
= (char *)text
.c_str(); // cast is ok
534 tvIns
.item
.iImage
= image
;
536 if ( selectedImage
== -1 )
538 // take the same image for selected icon if not specified
539 selectedImage
= image
;
543 if ( selectedImage
!= -1 )
545 mask
|= TVIF_SELECTEDIMAGE
;
546 tvIns
.item
.iSelectedImage
= selectedImage
;
552 tvIns
.item
.lParam
= (LPARAM
)data
;
555 tvIns
.item
.mask
= mask
;
557 HTREEITEM id
= (HTREEITEM
) TreeView_InsertItem(wxhWnd
, &tvIns
);
560 wxLogLastError("TreeView_InsertItem");
565 // associate the application tree item with Win32 tree item handle
566 data
->SetId((WXHTREEITEM
)id
);
569 return wxTreeItemId((WXHTREEITEM
)id
);
572 // for compatibility only
573 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
574 const wxString
& text
,
575 int image
, int selImage
,
578 return DoInsertItem(parent
, (WXHTREEITEM
)insertAfter
, text
,
579 image
, selImage
, NULL
);
582 wxTreeItemId
wxTreeCtrl::AddRoot(const wxString
& text
,
583 int image
, int selectedImage
,
584 wxTreeItemData
*data
)
586 return DoInsertItem(wxTreeItemId((WXHTREEITEM
) 0), (WXHTREEITEM
) 0,
587 text
, image
, selectedImage
, data
);
590 wxTreeItemId
wxTreeCtrl::PrependItem(const wxTreeItemId
& parent
,
591 const wxString
& text
,
592 int image
, int selectedImage
,
593 wxTreeItemData
*data
)
595 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_FIRST
,
596 text
, image
, selectedImage
, data
);
599 wxTreeItemId
wxTreeCtrl::InsertItem(const wxTreeItemId
& parent
,
600 const wxTreeItemId
& idPrevious
,
601 const wxString
& text
,
602 int image
, int selectedImage
,
603 wxTreeItemData
*data
)
605 return DoInsertItem(parent
, idPrevious
, text
, image
, selectedImage
, data
);
608 wxTreeItemId
wxTreeCtrl::AppendItem(const wxTreeItemId
& parent
,
609 const wxString
& text
,
610 int image
, int selectedImage
,
611 wxTreeItemData
*data
)
613 return DoInsertItem(parent
, (WXHTREEITEM
) TVI_LAST
,
614 text
, image
, selectedImage
, data
);
617 void wxTreeCtrl::Delete(const wxTreeItemId
& item
)
619 if ( !TreeView_DeleteItem(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
) )
621 wxLogLastError("TreeView_DeleteItem");
625 // delete all children (but don't delete the item itself)
626 void wxTreeCtrl::DeleteChildren(const wxTreeItemId
& item
)
630 wxArrayLong children
;
631 wxTreeItemId child
= GetFirstChild(item
, cookie
);
632 while ( child
.IsOk() )
634 children
.Add((long)(WXHTREEITEM
)child
);
636 child
= GetNextChild(item
, cookie
);
639 size_t nCount
= children
.Count();
640 for ( size_t n
= 0; n
< nCount
; n
++ )
642 if ( !TreeView_DeleteItem(wxhWnd
, (HTREEITEM
)children
[n
]) )
644 wxLogLastError("TreeView_DeleteItem");
649 void wxTreeCtrl::DeleteAllItems()
651 if ( !TreeView_DeleteAllItems(wxhWnd
) )
653 wxLogLastError("TreeView_DeleteAllItems");
657 void wxTreeCtrl::DoExpand(const wxTreeItemId
& item
, int flag
)
659 wxASSERT_MSG( flag
== TVE_COLLAPSE
|| flag
== TVE_COLLAPSERESET
||
660 flag
== TVE_EXPAND
|| flag
== TVE_TOGGLE
,
661 "Unknown flag in wxTreeCtrl::DoExpand" );
663 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
665 if ( TreeView_Expand(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
, flag
) != 0 )
667 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
670 bool isExpanded
= IsExpanded(item
);
672 event
.SetEventObject(this);
674 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
675 event
.SetEventType(g_events
[isExpanded
][TRUE
]);
676 GetEventHandler()->ProcessEvent(event
);
678 event
.SetEventType(g_events
[isExpanded
][FALSE
]);
679 GetEventHandler()->ProcessEvent(event
);
683 // I wonder if it really ever happens...
684 wxLogDebug("TreeView_Expand: change didn't took place.");
688 void wxTreeCtrl::Expand(const wxTreeItemId
& item
)
690 DoExpand(item
, TVE_EXPAND
);
693 void wxTreeCtrl::Collapse(const wxTreeItemId
& item
)
695 DoExpand(item
, TVE_COLLAPSE
);
698 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId
& item
)
700 DoExpand(item
, TVE_COLLAPSERESET
);
703 void wxTreeCtrl::Toggle(const wxTreeItemId
& item
)
705 DoExpand(item
, TVE_TOGGLE
);
708 void wxTreeCtrl::ExpandItem(const wxTreeItemId
& item
, int action
)
710 DoExpand(item
, action
);
713 void wxTreeCtrl::Unselect()
715 SelectItem(wxTreeItemId((WXHTREEITEM
) 0));
718 void wxTreeCtrl::SelectItem(const wxTreeItemId
& item
)
720 if ( !TreeView_SelectItem(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
) )
722 wxLogLastError("TreeView_SelectItem");
726 void wxTreeCtrl::EnsureVisible(const wxTreeItemId
& item
)
729 TreeView_EnsureVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
);
732 void wxTreeCtrl::ScrollTo(const wxTreeItemId
& item
)
734 if ( !TreeView_SelectSetFirstVisible(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
) )
736 wxLogLastError("TreeView_SelectSetFirstVisible");
740 wxTextCtrl
* wxTreeCtrl::GetEditControl() const
745 void wxTreeCtrl::DeleteTextCtrl()
749 m_textCtrl
->UnsubclassWin();
750 m_textCtrl
->SetHWND(0);
756 wxTextCtrl
* wxTreeCtrl::EditLabel(const wxTreeItemId
& item
,
757 wxClassInfo
* textControlClass
)
759 wxASSERT( textControlClass
->IsKindOf(CLASSINFO(wxTextCtrl
)) );
761 HWND hWnd
= (HWND
) TreeView_EditLabel(wxhWnd
, (HTREEITEM
) (WXHTREEITEM
) item
);
763 wxCHECK_MSG( hWnd
, NULL
, "Can't edit tree ctrl label" );
767 m_textCtrl
= (wxTextCtrl
*)textControlClass
->CreateObject();
768 m_textCtrl
->SetHWND((WXHWND
)hWnd
);
769 m_textCtrl
->SubclassWin((WXHWND
)hWnd
);
774 // End label editing, optionally cancelling the edit
775 void wxTreeCtrl::EndEditLabel(const wxTreeItemId
& item
, bool discardChanges
)
777 TreeView_EndEditLabelNow(wxhWnd
, discardChanges
);
782 wxTreeItemId
wxTreeCtrl::HitTest(const wxPoint
& point
, int& flags
)
784 TV_HITTESTINFO hitTestInfo
;
785 hitTestInfo
.pt
.x
= (int)point
.x
;
786 hitTestInfo
.pt
.y
= (int)point
.y
;
788 TreeView_HitTest(wxhWnd
, &hitTestInfo
);
793 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
794 flags |= wxTREE_HITTEST_##flag
796 TRANSLATE_FLAG(ABOVE
);
797 TRANSLATE_FLAG(BELOW
);
798 TRANSLATE_FLAG(NOWHERE
);
799 TRANSLATE_FLAG(ONITEMBUTTON
);
800 TRANSLATE_FLAG(ONITEMICON
);
801 TRANSLATE_FLAG(ONITEMINDENT
);
802 TRANSLATE_FLAG(ONITEMLABEL
);
803 TRANSLATE_FLAG(ONITEMRIGHT
);
804 TRANSLATE_FLAG(ONITEMSTATEICON
);
805 TRANSLATE_FLAG(TOLEFT
);
806 TRANSLATE_FLAG(TORIGHT
);
808 #undef TRANSLATE_FLAG
810 return wxTreeItemId((WXHTREEITEM
) hitTestInfo
.hItem
);
813 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId
& item
,
818 if ( TreeView_GetItemRect(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
,
821 rect
= wxRect(wxPoint(rc
.left
, rc
.top
), wxPoint(rc
.right
, rc
.bottom
));
827 // couldn't retrieve rect: for example, item isn't visible
832 // ----------------------------------------------------------------------------
834 // ----------------------------------------------------------------------------
836 static int CALLBACK
TreeView_CompareCallback(wxTreeItemData
*pItem1
,
837 wxTreeItemData
*pItem2
,
840 return tree
->OnCompareItems(pItem1
->GetId(), pItem2
->GetId());
843 int wxTreeCtrl::OnCompareItems(const wxTreeItemId
& item1
,
844 const wxTreeItemId
& item2
)
846 return strcmp(GetItemText(item1
), GetItemText(item2
));
849 void wxTreeCtrl::SortChildren(const wxTreeItemId
& item
)
851 // rely on the fact that TreeView_SortChildren does the same thing as our
852 // default behaviour, i.e. sorts items alphabetically and so call it
853 // directly if we're not in derived class (much more efficient!)
854 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl
) )
856 TreeView_SortChildren(wxhWnd
, (HTREEITEM
)(WXHTREEITEM
)item
, 0);
861 tvSort
.hParent
= (HTREEITEM
)(WXHTREEITEM
)item
;
862 tvSort
.lpfnCompare
= (PFNTVCOMPARE
)TreeView_CompareCallback
;
863 tvSort
.lParam
= (LPARAM
)this;
864 TreeView_SortChildrenCB(wxhWnd
, &tvSort
, 0 /* reserved */);
868 // ----------------------------------------------------------------------------
870 // ----------------------------------------------------------------------------
872 bool wxTreeCtrl::MSWCommand(WXUINT cmd
, WXWORD id
)
874 if ( cmd
== EN_UPDATE
)
876 wxCommandEvent
event(wxEVT_COMMAND_TEXT_UPDATED
, id
);
877 event
.SetEventObject( this );
878 ProcessCommand(event
);
880 else if ( cmd
== EN_KILLFOCUS
)
882 wxCommandEvent
event(wxEVT_KILL_FOCUS
, id
);
883 event
.SetEventObject( this );
884 ProcessCommand(event
);
896 // process WM_NOTIFY Windows message
897 bool wxTreeCtrl::MSWNotify(WXWPARAM wParam
, WXLPARAM lParam
, WXLPARAM
*result
)
899 wxTreeEvent
event(wxEVT_NULL
, m_windowId
);
900 wxEventType eventType
= wxEVT_NULL
;
901 NMHDR
*hdr
= (NMHDR
*)lParam
;
906 eventType
= wxEVT_COMMAND_TREE_BEGIN_DRAG
;
911 if ( eventType
== wxEVT_NULL
)
912 eventType
= wxEVT_COMMAND_TREE_BEGIN_RDRAG
;
913 //else: left drag, already set above
915 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
917 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
918 event
.m_pointDrag
= wxPoint(tv
->ptDrag
.x
, tv
->ptDrag
.y
);
922 case TVN_BEGINLABELEDIT
:
924 eventType
= wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT
;
925 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
927 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
933 eventType
= wxEVT_COMMAND_TREE_DELETE_ITEM
;
934 NM_TREEVIEW
*tv
= (NM_TREEVIEW
*)lParam
;
936 event
.m_item
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
940 case TVN_ENDLABELEDIT
:
942 eventType
= wxEVT_COMMAND_TREE_END_LABEL_EDIT
;
943 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
945 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
949 case TVN_GETDISPINFO
:
950 eventType
= wxEVT_COMMAND_TREE_GET_INFO
;
953 case TVN_SETDISPINFO
:
955 if ( eventType
== wxEVT_NULL
)
956 eventType
= wxEVT_COMMAND_TREE_SET_INFO
;
957 //else: get, already set above
959 TV_DISPINFO
*info
= (TV_DISPINFO
*)lParam
;
961 event
.m_item
= (WXHTREEITEM
) info
->item
.hItem
;
965 case TVN_ITEMEXPANDING
:
966 event
.m_code
= FALSE
;
969 case TVN_ITEMEXPANDED
:
971 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
974 switch ( tv
->action
)
985 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
986 "message", tv
->action
);
989 bool ing
= (hdr
->code
== TVN_ITEMEXPANDING
);
990 eventType
= g_events
[expand
][ing
];
992 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
998 eventType
= wxEVT_COMMAND_TREE_KEY_DOWN
;
999 TV_KEYDOWN
*info
= (TV_KEYDOWN
*)lParam
;
1001 event
.m_code
= wxCharCodeMSWToWX(info
->wVKey
);
1003 // a separate event for this case
1004 if ( info
->wVKey
== VK_SPACE
|| info
->wVKey
== VK_RETURN
)
1006 wxTreeEvent
event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED
,
1008 event2
.SetEventObject(this);
1010 GetEventHandler()->ProcessEvent(event2
);
1015 case TVN_SELCHANGED
:
1016 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGED
;
1019 case TVN_SELCHANGING
:
1021 if ( eventType
== wxEVT_NULL
)
1022 eventType
= wxEVT_COMMAND_TREE_SEL_CHANGING
;
1023 //else: already set above
1025 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1027 event
.m_item
= (WXHTREEITEM
) tv
->itemNew
.hItem
;
1028 event
.m_itemOld
= (WXHTREEITEM
) tv
->itemOld
.hItem
;
1033 return wxControl::MSWNotify(wParam
, lParam
, result
);
1036 event
.SetEventObject(this);
1037 event
.SetEventType(eventType
);
1039 bool processed
= GetEventHandler()->ProcessEvent(event
);
1042 if ( hdr
->code
== TVN_DELETEITEM
)
1044 // NB: we might process this message using wxWindows event tables, but
1045 // due to overhead of wxWin event system we prefer to do it here
1046 // (otherwise deleting a tree with many items is just too slow)
1047 NM_TREEVIEW
* tv
= (NM_TREEVIEW
*)lParam
;
1048 wxTreeItemData
*data
= (wxTreeItemData
*)tv
->itemOld
.lParam
;
1049 delete data
; // may be NULL, ok
1052 *result
= !event
.IsAllowed();
1057 // ----------------------------------------------------------------------------
1059 // ----------------------------------------------------------------------------
1061 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent
, wxNotifyEvent
)
1063 wxTreeEvent::wxTreeEvent(wxEventType commandType
, int id
)
1064 : wxNotifyEvent(commandType
, id
)