]> git.saurik.com Git - wxWidgets.git/blob - src/msw/treectrl.cpp
new wxTreeCtrl files
[wxWidgets.git] / src / msw / treectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: treectrl.cpp
3 // Purpose: wxTreeCtrl
4 // Author: Julian Smart
5 // Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
6 // Created: 1997
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ============================================================================
13 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19 #ifdef __GNUG__
20 #pragma implementation "treectrl.h"
21 #endif
22
23 // For compilers that support precompilation, includes "wx.h".
24 #include "wx/wxprec.h"
25
26 #ifdef __BORLANDC__
27 #pragma hdrstop
28 #endif
29
30 #ifndef WX_PRECOMP
31 #include "wx.h"
32 #endif
33
34 #if defined(__WIN95__)
35
36 #include "wx/log.h"
37 #include "wx/imaglist.h"
38
39 #include "wx/msw/private.h"
40
41 #ifndef __GNUWIN32__
42 #include <commctrl.h>
43 #endif
44
45 #define wxHTREEITEM_DEFINED // flag used in wx/msw/treectrl.h
46 #include "wx/treectrl.h"
47
48 // Bug in headers, sometimes
49 #ifndef TVIS_FOCUSED
50 #define TVIS_FOCUSED 0x0001
51 #endif
52
53 // ----------------------------------------------------------------------------
54 // private classes
55 // ----------------------------------------------------------------------------
56
57 // a convenient wrapper around TV_ITEM struct which adds a ctor
58 struct wxTreeViewItem : public TV_ITEM
59 {
60 wxTreeViewItem(const wxTreeItemId& item,
61 UINT mask_, UINT stateMask_ = 0)
62 {
63 mask = mask_;
64 stateMask = stateMask_;
65 hItem = (HTREEITEM)item;
66 }
67 };
68
69 // ----------------------------------------------------------------------------
70 // macros
71 // ----------------------------------------------------------------------------
72
73 #if !USE_SHARED_LIBRARY
74 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
75 #endif
76
77 // hide the ugly cast (of course, the macro is _quite_ ugly too...)
78 #define hwnd ((HWND)m_hWnd)
79
80 // ----------------------------------------------------------------------------
81 // variables
82 // ----------------------------------------------------------------------------
83
84 // handy table for sending events
85 static const wxEventType g_events[2][2] =
86 {
87 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
88 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
89 };
90
91 // ============================================================================
92 // implementation
93 // ============================================================================
94
95 // ----------------------------------------------------------------------------
96 // construction and destruction
97 // ----------------------------------------------------------------------------
98
99 void wxTreeCtrl::Init()
100 {
101 m_imageListNormal = NULL;
102 m_imageListState = NULL;
103 m_textCtrl = NULL;
104 }
105
106 bool wxTreeCtrl::Create(wxWindow *parent, wxWindowID id,
107 const wxPoint& pos, const wxSize& size,
108 long style, const wxValidator& validator,
109 const wxString& name)
110 {
111 Init();
112
113 wxSystemSettings settings;
114
115 SetName(name);
116 SetValidator(validator);
117
118 m_windowStyle = style;
119
120 SetParent(parent);
121
122 m_windowId = (id == -1) ? NewControlId() : id;
123
124 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES;
125
126 bool want3D;
127 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
128
129 // Even with extended styles, need to combine with WS_BORDER
130 // for them to look right.
131 if ( want3D || wxStyleHasBorder(m_windowStyle) )
132 {
133 wstyle |= WS_BORDER;
134 }
135
136 if ( m_windowStyle & wxTR_HAS_BUTTONS )
137 wstyle |= TVS_HASBUTTONS;
138
139 if ( m_windowStyle & wxTR_EDIT_LABELS )
140 wstyle |= TVS_EDITLABELS;
141
142 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
143 wstyle |= TVS_LINESATROOT;
144
145 // Create the tree control.
146 m_hWnd = (WXHWND)::CreateWindowEx
147 (
148 exStyle,
149 WC_TREEVIEW,
150 "",
151 wstyle,
152 pos.x, pos.y, size.x, size.y,
153 (HWND)parent->GetHWND(),
154 (HMENU)m_windowId,
155 wxGetInstance(),
156 NULL
157 );
158
159 wxCHECK_MSG( m_hWnd, FALSE, "Failed to create tree ctrl" );
160
161 if ( parent )
162 parent->AddChild(this);
163
164 SubclassWin(m_hWnd);
165
166 return TRUE;
167 }
168
169 wxTreeCtrl::~wxTreeCtrl()
170 {
171 DeleteTextCtrl();
172
173 // delete user data to prevent memory leaks
174 DeleteAllItems();
175 }
176
177 // ----------------------------------------------------------------------------
178 // accessors
179 // ----------------------------------------------------------------------------
180
181 // simple wrappers which add error checking in debug mode
182
183 bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
184 {
185 if ( !TreeView_GetItem(hwnd, tvItem) )
186 {
187 wxLogLastError("TreeView_GetItem");
188
189 return FALSE;
190 }
191
192 return TRUE;
193 }
194
195 void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
196 {
197 if ( TreeView_SetItem(hwnd, tvItem) == -1 )
198 {
199 wxLogLastError("TreeView_SetItem");
200 }
201 }
202
203 size_t wxTreeCtrl::GetCount() const
204 {
205 return (size_t)TreeView_GetCount(hwnd);
206 }
207
208 unsigned int wxTreeCtrl::GetIndent() const
209 {
210 return TreeView_GetIndent(hwnd);
211 }
212
213 void wxTreeCtrl::SetIndent(unsigned int indent)
214 {
215 TreeView_SetIndent(hwnd, indent);
216 }
217
218 wxImageList *wxTreeCtrl::GetImageList() const
219 {
220 return m_imageListNormal;
221 }
222
223 wxImageList *wxTreeCtrl::GetStateImageList() const
224 {
225 return m_imageListNormal;
226 }
227
228 void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
229 {
230 // no error return
231 TreeView_SetImageList(hwnd,
232 imageList ? imageList->GetHIMAGELIST() : 0,
233 which);
234 }
235
236 void wxTreeCtrl::SetImageList(wxImageList *imageList)
237 {
238 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
239 }
240
241 void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
242 {
243 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
244 }
245
246 // ----------------------------------------------------------------------------
247 // Item access
248 // ----------------------------------------------------------------------------
249
250 wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
251 {
252 char buf[512]; // the size is arbitrary...
253
254 wxTreeViewItem tvItem(item, TVIF_TEXT);
255 tvItem.pszText = buf;
256 tvItem.cchTextMax = WXSIZEOF(buf);
257 if ( !DoGetItem(&tvItem) )
258 {
259 // don't return some garbage which was on stack, but an empty string
260 buf[0] = '\0';
261 }
262
263 return wxString(buf);
264 }
265
266 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
267 {
268 wxTreeViewItem tvItem(item, TVIF_TEXT);
269 tvItem.pszText = (char *)text.c_str(); // conversion is ok
270 DoSetItem(&tvItem);
271 }
272
273 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
274 {
275 wxTreeViewItem tvItem(item, TVIF_IMAGE);
276 DoGetItem(&tvItem);
277
278 return tvItem.iImage;
279 }
280
281 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
282 {
283 wxTreeViewItem tvItem(item, TVIF_IMAGE);
284 tvItem.iImage = image;
285 DoSetItem(&tvItem);
286 }
287
288 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
289 {
290 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
291 DoGetItem(&tvItem);
292
293 return tvItem.iSelectedImage;
294 }
295
296 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
297 {
298 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
299 tvItem.iSelectedImage = image;
300 DoSetItem(&tvItem);
301 }
302
303 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
304 {
305 wxTreeViewItem tvItem(item, TVIF_PARAM);
306 if ( !DoGetItem(&tvItem) )
307 {
308 return NULL;
309 }
310
311 wxTreeItemData *data = (wxTreeItemData *)tvItem.lParam;
312 if ( data != NULL )
313 {
314 // the data object should know about its id
315 data->m_itemId = item;
316 }
317
318 return data;
319 }
320
321 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
322 {
323 wxTreeViewItem tvItem(item, TVIF_PARAM);
324 tvItem.lParam = (LPARAM)data;
325 DoSetItem(&tvItem);
326 }
327
328 // ----------------------------------------------------------------------------
329 // Item status
330 // ----------------------------------------------------------------------------
331
332 bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
333 {
334 RECT rect;
335 return TreeView_GetItemRect(hwnd, (HTREEITEM)item, &rect, FALSE) != 0;
336 }
337
338 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
339 {
340 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
341 DoGetItem(&tvItem);
342
343 return tvItem.cChildren != 0;
344 }
345
346 bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
347 {
348 // probably not a good idea to put it here
349 //wxASSERT( ItemHasChildren(item) );
350
351 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
352 DoGetItem(&tvItem);
353
354 return (tvItem.state & TVIS_EXPANDED) != 0;
355 }
356
357 bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
358 {
359 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
360 DoGetItem(&tvItem);
361
362 return (tvItem.state & TVIS_SELECTED) != 0;
363 }
364
365 // ----------------------------------------------------------------------------
366 // navigation
367 // ----------------------------------------------------------------------------
368
369 wxTreeItemId wxTreeCtrl::GetRootItem() const
370 {
371 return wxTreeItemId(TreeView_GetRoot(hwnd));
372 }
373
374 wxTreeItemId wxTreeCtrl::GetSelection() const
375 {
376 return wxTreeItemId(TreeView_GetSelection(hwnd));
377 }
378
379 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
380 {
381 return wxTreeItemId(TreeView_GetParent(hwnd, item));
382 }
383
384 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
385 long& cookie) const
386 {
387 // remember the last child returned in 'cookie'
388 cookie = (long)TreeView_GetChild(hwnd, (HTREEITEM)item);
389
390 return wxTreeItemId((HTREEITEM)cookie);
391 }
392
393 wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
394 long& cookie) const
395 {
396 return wxTreeItemId(TreeView_GetNextSibling(hwnd,
397 (HTREEITEM)cookie));
398 }
399
400 wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
401 {
402 return wxTreeItemId(TreeView_GetNextSibling(hwnd, item));
403 }
404
405 wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
406 {
407 return wxTreeItemId(TreeView_GetPrevSibling(hwnd, item));
408 }
409
410 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
411 {
412 return wxTreeItemId(TreeView_GetFirstVisible(hwnd));
413 }
414
415 wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
416 {
417 wxASSERT_MSG( IsVisible(item), "The item you call GetNextVisible() "
418 "for must be visible itself!");
419
420 return wxTreeItemId(TreeView_GetNextVisible(hwnd, item));
421 }
422
423 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
424 {
425 wxASSERT_MSG( IsVisible(item), "The item you call GetPrevVisible() "
426 "for must be visible itself!");
427
428 return wxTreeItemId(TreeView_GetPrevVisible(hwnd, item));
429 }
430
431 // ----------------------------------------------------------------------------
432 // Usual operations
433 // ----------------------------------------------------------------------------
434
435 wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
436 wxTreeItemId hInsertAfter,
437 const wxString& text,
438 int image, int selectedImage,
439 wxTreeItemData *data)
440 {
441 TV_INSERTSTRUCT tvIns;
442 tvIns.hParent = (HTREEITEM)parent;
443 tvIns.hInsertAfter = hInsertAfter;
444 UINT mask = 0;
445 if ( !text.IsEmpty() )
446 {
447 mask |= TVIF_TEXT;
448 tvIns.item.pszText = (char *)text.c_str(); // cast is ok
449 }
450
451 if ( image != -1 )
452 {
453 mask |= TVIF_IMAGE;
454 tvIns.item.iImage = image;
455 }
456
457 if ( selectedImage != -1 )
458 {
459 mask |= TVIF_SELECTEDIMAGE;
460 tvIns.item.iSelectedImage = selectedImage;
461 }
462
463 if ( data != NULL )
464 {
465 mask |= TVIF_PARAM;
466 tvIns.item.lParam = (LPARAM)data;
467 }
468
469 tvIns.item.mask = mask;
470
471 HTREEITEM id = TreeView_InsertItem(hwnd, &tvIns);
472 if ( id == 0 )
473 {
474 wxLogLastError("TreeView_InsertItem");
475 }
476
477 return wxTreeItemId(id);
478 }
479
480 // for compatibility only
481 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
482 const wxString& text,
483 int image, int selImage,
484 long insertAfter)
485 {
486 return DoInsertItem(parent, (HTREEITEM)insertAfter, text,
487 image, selImage, NULL);
488 }
489
490 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
491 int image, int selectedImage,
492 wxTreeItemData *data)
493 {
494 return DoInsertItem(wxTreeItemId(0), 0,
495 text, image, selectedImage, data);
496 }
497
498 wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
499 const wxString& text,
500 int image, int selectedImage,
501 wxTreeItemData *data)
502 {
503 return DoInsertItem(parent, TVI_FIRST,
504 text, image, selectedImage, data);
505 }
506
507 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
508 const wxTreeItemId& idPrevious,
509 const wxString& text,
510 int image, int selectedImage,
511 wxTreeItemData *data)
512 {
513 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
514 }
515
516 wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
517 const wxString& text,
518 int image, int selectedImage,
519 wxTreeItemData *data)
520 {
521 return DoInsertItem(parent, TVI_LAST,
522 text, image, selectedImage, data);
523 }
524
525 void wxTreeCtrl::Delete(const wxTreeItemId& item)
526 {
527 wxTreeItemData *data = GetItemData(item);
528 delete data; // may be NULL, ok
529
530 if ( !TreeView_DeleteItem(hwnd, (HTREEITEM)item) )
531 {
532 wxLogLastError("TreeView_DeleteItem");
533 }
534 }
535
536 void wxTreeCtrl::DeleteAllItems()
537 {
538 if ( !TreeView_DeleteAllItems(hwnd) )
539 {
540 wxLogLastError("TreeView_DeleteAllItems");
541 }
542 }
543
544 void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
545 {
546 wxASSERT_MSG( flag == TVE_COLLAPSE || flag == TVE_COLLAPSERESET ||
547 flag == TVE_EXPAND || flag == TVE_TOGGLE,
548 "Unknown flag in wxTreeCtrl::DoExpand" );
549
550 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
551 // emulate them
552 if ( TreeView_Expand(hwnd, item, flag) != 0 )
553 {
554 wxTreeEvent event(wxEVT_NULL, m_windowId);
555 event.m_item = item;
556
557 bool isExpanded = IsExpanded(item);
558
559 event.SetEventObject(this);
560
561 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
562 event.SetEventType(g_events[isExpanded][TRUE]);
563 GetEventHandler()->ProcessEvent(event);
564
565 event.SetEventType(g_events[isExpanded][FALSE]);
566 GetEventHandler()->ProcessEvent(event);
567 }
568 else
569 {
570 // I wonder if it really ever happens...
571 wxLogDebug("TreeView_Expand: change didn't took place.");
572 }
573 }
574
575 void wxTreeCtrl::Expand(const wxTreeItemId& item)
576 {
577 DoExpand(item, TVE_EXPAND);
578 }
579
580 void wxTreeCtrl::Collapse(const wxTreeItemId& item)
581 {
582 DoExpand(item, TVE_COLLAPSE);
583 }
584
585 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
586 {
587 DoExpand(item, TVE_COLLAPSERESET);
588 }
589
590 void wxTreeCtrl::Toggle(const wxTreeItemId& item)
591 {
592 DoExpand(item, TVE_TOGGLE);
593 }
594
595 void wxTreeCtrl::Unselect()
596 {
597 SelectItem(wxTreeItemId(0));
598 }
599
600 void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
601 {
602 if ( !TreeView_SelectItem(hwnd, item) )
603 {
604 wxLogLastError("TreeView_SelectItem");
605 }
606 }
607
608 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
609 {
610 // no error return
611 TreeView_EnsureVisible(hwnd, item);
612 }
613
614 void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
615 {
616 if ( !TreeView_SelectSetFirstVisible(hwnd, item) )
617 {
618 wxLogLastError("TreeView_SelectSetFirstVisible");
619 }
620 }
621
622 wxTextCtrl* wxTreeCtrl::GetEditControl() const
623 {
624 return m_textCtrl;
625 }
626
627 void wxTreeCtrl::DeleteTextCtrl()
628 {
629 if ( m_textCtrl )
630 {
631 m_textCtrl->UnsubclassWin();
632 m_textCtrl->SetHWND(0);
633 delete m_textCtrl;
634 m_textCtrl = NULL;
635 }
636 }
637
638 wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
639 wxClassInfo* textControlClass)
640 {
641 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
642
643 HWND hWnd = TreeView_EditLabel(hwnd, item);
644
645 wxCHECK_MSG( hWnd, NULL, "Can't edit tree ctrl label" );
646
647 DeleteTextCtrl();
648
649 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
650 m_textCtrl->SetHWND((WXHWND)hWnd);
651 m_textCtrl->SubclassWin((WXHWND)hWnd);
652
653 return m_textCtrl;
654 }
655
656 // End label editing, optionally cancelling the edit
657 void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
658 {
659 TreeView_EndEditLabelNow(hwnd, discardChanges);
660
661 DeleteTextCtrl();
662 }
663
664 wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
665 {
666 TV_HITTESTINFO hitTestInfo;
667 hitTestInfo.pt.x = (int)point.x;
668 hitTestInfo.pt.y = (int)point.y;
669
670 TreeView_HitTest(hwnd, &hitTestInfo);
671
672 flags = 0;
673
674 // avoid repetition
675 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
676 flags |= wxTREE_HITTEST_##flag
677
678 TRANSLATE_FLAG(ABOVE);
679 TRANSLATE_FLAG(BELOW);
680 TRANSLATE_FLAG(NOWHERE);
681 TRANSLATE_FLAG(ONITEMBUTTON);
682 TRANSLATE_FLAG(ONITEMICON);
683 TRANSLATE_FLAG(ONITEMINDENT);
684 TRANSLATE_FLAG(ONITEMLABEL);
685 TRANSLATE_FLAG(ONITEMRIGHT);
686 TRANSLATE_FLAG(ONITEMSTATEICON);
687 TRANSLATE_FLAG(TOLEFT);
688 TRANSLATE_FLAG(TORIGHT);
689
690 #undef TRANSLATE_FLAG
691
692 return wxTreeItemId(hitTestInfo.hItem);
693 }
694
695 void wxTreeCtrl::SortChildren(const wxTreeItemId& item,
696 wxTreeItemCmpFunc *cmpFunction)
697 {
698 if ( cmpFunction == NULL )
699 {
700 TreeView_SortChildren(hwnd, item, 0);
701 }
702 else
703 {
704 // TODO: use TreeView_SortChildrenCB
705 wxFAIL_MSG("wxTreeCtrl::SortChildren not implemented");
706 }
707 }
708
709 // ----------------------------------------------------------------------------
710 // implementation
711 // ----------------------------------------------------------------------------
712
713 bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
714 {
715 if ( cmd == EN_UPDATE )
716 {
717 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
718 event.SetEventObject( this );
719 ProcessCommand(event);
720 }
721 else if ( cmd == EN_KILLFOCUS )
722 {
723 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
724 event.SetEventObject( this );
725 ProcessCommand(event);
726 }
727 else
728 {
729 // nothing done
730 return FALSE;
731 }
732
733 // command processed
734 return TRUE;
735 }
736
737 // process WM_NOTIFY Windows message
738 bool wxTreeCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam)
739 {
740 wxTreeEvent event(wxEVT_NULL, m_windowId);
741 wxEventType eventType = wxEVT_NULL;
742 NMHDR *hdr = (NMHDR *)lParam;
743
744 switch ( hdr->code )
745 {
746 case TVN_BEGINDRAG:
747 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
748 // fall through
749
750 case TVN_BEGINRDRAG:
751 {
752 if ( eventType == wxEVT_NULL )
753 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
754 //else: left drag, already set above
755
756 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
757
758 event.m_item = tv->itemNew.hItem;
759 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
760 break;
761 }
762
763 case TVN_BEGINLABELEDIT:
764 {
765 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
766 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
767
768 event.m_item = info->item.hItem;
769 break;
770 }
771
772 case TVN_DELETEITEM:
773 {
774 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
775 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
776
777 event.m_item = tv->itemOld.hItem;
778 break;
779 }
780
781 case TVN_ENDLABELEDIT:
782 {
783 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
784 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
785
786 event.m_item = info->item.hItem;
787 break;
788 }
789
790 case TVN_GETDISPINFO:
791 eventType = wxEVT_COMMAND_TREE_GET_INFO;
792 // fall through
793
794 case TVN_SETDISPINFO:
795 {
796 if ( eventType == wxEVT_NULL )
797 eventType = wxEVT_COMMAND_TREE_SET_INFO;
798 //else: get, already set above
799
800 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
801
802 event.m_item = info->item.hItem;
803 break;
804 }
805
806 case TVN_ITEMEXPANDING:
807 event.m_code = FALSE;
808 // fall through
809
810 case TVN_ITEMEXPANDED:
811 {
812 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
813
814 bool expand = FALSE;
815 switch ( tv->action )
816 {
817 case TVE_EXPAND:
818 expand = TRUE;
819 break;
820
821 case TVE_COLLAPSE:
822 expand = FALSE;
823 break;
824
825 default:
826 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
827 "message", tv->action);
828 }
829
830 bool ing = hdr->code == TVN_ITEMEXPANDING;
831 eventType = g_events[expand][ing];
832
833 event.m_item = tv->itemNew.hItem;
834 break;
835 }
836
837 case TVN_KEYDOWN:
838 {
839 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
840 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
841
842 event.m_code = wxCharCodeMSWToWX(info->wVKey);
843 break;
844 }
845
846 case TVN_SELCHANGED:
847 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
848 // fall through
849
850 case TVN_SELCHANGING:
851 {
852 if ( eventType == wxEVT_NULL )
853 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
854 //else: already set above
855
856 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
857
858 event.m_item = tv->itemNew.hItem;
859 event.m_itemOld = tv->itemOld.hItem;
860 break;
861 }
862
863 default:
864 return wxControl::MSWNotify(wParam, lParam);
865 }
866
867 event.SetEventObject(this);
868 event.SetEventType(eventType);
869
870 bool rc = GetEventHandler()->ProcessEvent(event);
871
872 // post processing
873 switch ( hdr->code )
874 {
875 // NB: we might process this message using wxWindows event tables, but
876 // due to overhead of wxWin event system we prefer to do it here
877 // (otherwise deleting a tree with many items is just too slow)
878 case TVN_DELETEITEM:
879 {
880 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
881 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
882 delete data; // may be NULL, ok
883 }
884 break;
885
886 case TVN_ITEMEXPANDING:
887 // if user called Veto(), don't allow expansion/collapse by
888 // returning TRUE from here
889 rc = event.m_code != 0;
890 break;
891 }
892
893 return rc;
894 }
895
896 // ----------------------------------------------------------------------------
897 // Tree event
898 // ----------------------------------------------------------------------------
899
900 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent)
901
902 wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
903 : wxCommandEvent(commandType, id)
904 {
905 m_code = 0;
906 m_itemOld = 0;
907 }
908
909 #endif // __WIN95__
910