*** empty log message ***
[wxWidgets.git] / src / os2 / treectrl.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: treectrl.cpp
3 // Purpose: wxTreeCtrl. See also Robert's generic wxTreeCtrl.
4 // Author: David Webster
5 // Modified by:
6 // Created: 10/17/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14
15 #include "wx/window.h"
16 #include "wx/os2/private.h"
17
18 #include "wx/log.h"
19 #include "wx/dynarray.h"
20 #include "wx/imaglist.h"
21 #include "wx/treectrl.h"
22 #include "wx/settings.h"
23
24 // Bug in headers, sometimes
25 #ifndef TVIS_FOCUSED
26 #define TVIS_FOCUSED 0x0001
27 #endif
28
29 // ----------------------------------------------------------------------------
30 // private classes
31 // ----------------------------------------------------------------------------
32
33 struct wxTreeViewItem// ??? : public TV_ITEM
34 {
35 wxTreeViewItem(const wxTreeItemId& item, // the item handle
36 UINT mask_, // fields which are valid
37 UINT stateMask_ = 0) // for TVIF_STATE only
38 {
39 // hItem member is always valid
40 mask = mask_; // | TVIF_HANDLE;
41 stateMask = stateMask_;
42 hItem = /*(HTREEITEM)*/ (WXHTREEITEM) item;
43 }
44 // OS/2 subs
45 UINT mask;
46 UINT stateMask;
47 WXHTREEITEM hItem;
48 };
49
50 // a class which encapsulates the tree traversal logic: it vists all (unless
51 // OnVisit() returns FALSE) items under the given one
52 class wxTreeTraversal
53 {
54 public:
55 wxTreeTraversal(const wxTreeCtrl *tree)
56 {
57 m_tree = tree;
58 }
59
60 // do traverse the tree: visit all items (recursively by default) under the
61 // given one; return TRUE if all items were traversed or FALSE if the
62 // traversal was aborted because OnVisit returned FALSE
63 bool DoTraverse(const wxTreeItemId& root, bool recursively = TRUE);
64
65 // override this function to do whatever is needed for each item, return
66 // FALSE to stop traversing
67 virtual bool OnVisit(const wxTreeItemId& item) = 0;
68
69 protected:
70 const wxTreeCtrl *GetTree() const { return m_tree; }
71
72 private:
73 bool Traverse(const wxTreeItemId& root, bool recursively);
74
75 const wxTreeCtrl *m_tree;
76 };
77
78 // internal class for getting the selected items
79 class TraverseSelections : public wxTreeTraversal
80 {
81 public:
82 TraverseSelections(const wxTreeCtrl *tree,
83 wxArrayTreeItemIds& selections)
84 : wxTreeTraversal(tree), m_selections(selections)
85 {
86 m_selections.Empty();
87
88 DoTraverse(tree->GetRootItem());
89 }
90
91 virtual bool OnVisit(const wxTreeItemId& item)
92 {
93 if ( GetTree()->IsItemChecked(item) )
94 {
95 m_selections.Add(item);
96 }
97
98 return TRUE;
99 }
100
101 private:
102 wxArrayTreeItemIds& m_selections;
103 };
104
105 // internal class for counting tree items
106 class TraverseCounter : public wxTreeTraversal
107 {
108 public:
109 TraverseCounter(const wxTreeCtrl *tree,
110 const wxTreeItemId& root,
111 bool recursively)
112 : wxTreeTraversal(tree)
113 {
114 m_count = 0;
115
116 DoTraverse(root, recursively);
117 }
118
119 virtual bool OnVisit(const wxTreeItemId& item)
120 {
121 m_count++;
122
123 return TRUE;
124 }
125
126 size_t GetCount() const { return m_count; }
127
128 private:
129 size_t m_count;
130 };
131
132 // ----------------------------------------------------------------------------
133 // This class is needed for support of different images: the Win32 common
134 // control natively supports only 2 images (the normal one and another for the
135 // selected state). We wish to provide support for 2 more of them for folder
136 // items (i.e. those which have children): for expanded state and for expanded
137 // selected state. For this we use this structure to store the additional items
138 // images.
139 //
140 // There is only one problem with this: when we retrieve the item's data, we
141 // don't know whether we get a pointer to wxTreeItemData or
142 // wxTreeItemIndirectData. So we have to maintain a list of all items which
143 // have indirect data inside the listctrl itself.
144 // ----------------------------------------------------------------------------
145 class wxTreeItemIndirectData
146 {
147 public:
148 // ctor associates this data with the item and the real item data becomes
149 // available through our GetData() method
150 wxTreeItemIndirectData(wxTreeCtrl *tree, const wxTreeItemId& item)
151 {
152 for ( size_t n = 0; n < WXSIZEOF(m_images); n++ )
153 {
154 m_images[n] = -1;
155 }
156
157 // save the old data
158 m_data = tree->GetItemData(item);
159
160 // and set ourselves as the new one
161 tree->SetIndirectItemData(item, this);
162 }
163
164 // dtor deletes the associated data as well
165 ~wxTreeItemIndirectData() { delete m_data; }
166
167 // accessors
168 // get the real data associated with the item
169 wxTreeItemData *GetData() const { return m_data; }
170 // change it
171 void SetData(wxTreeItemData *data) { m_data = data; }
172
173 // do we have such image?
174 bool HasImage(wxTreeItemIcon which) const { return m_images[which] != -1; }
175 // get image
176 int GetImage(wxTreeItemIcon which) const { return m_images[which]; }
177 // change it
178 void SetImage(int image, wxTreeItemIcon which) { m_images[which] = image; }
179
180 private:
181 // all the images associated with the item
182 int m_images[wxTreeItemIcon_Max];
183
184 wxTreeItemData *m_data;
185 };
186
187 // ----------------------------------------------------------------------------
188 // macros
189 // ----------------------------------------------------------------------------
190
191 #if !USE_SHARED_LIBRARY
192 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
193 #endif
194
195 // ----------------------------------------------------------------------------
196 // variables
197 // ----------------------------------------------------------------------------
198
199 // handy table for sending events
200 static const wxEventType g_events[2][2] =
201 {
202 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
203 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
204 };
205
206 // ============================================================================
207 // implementation
208 // ============================================================================
209
210 // ----------------------------------------------------------------------------
211 // tree traversal
212 // ----------------------------------------------------------------------------
213
214 bool wxTreeTraversal::DoTraverse(const wxTreeItemId& root, bool recursively)
215 {
216 if ( !OnVisit(root) )
217 return FALSE;
218
219 return Traverse(root, recursively);
220 }
221
222 bool wxTreeTraversal::Traverse(const wxTreeItemId& root, bool recursively)
223 {
224 long cookie;
225 wxTreeItemId child = m_tree->GetFirstChild(root, cookie);
226 while ( child.IsOk() )
227 {
228 // depth first traversal
229 if ( recursively && !Traverse(child, TRUE) )
230 return FALSE;
231
232 if ( !OnVisit(child) )
233 return FALSE;
234
235 child = m_tree->GetNextChild(root, cookie);
236 }
237
238 return TRUE;
239 }
240
241 // ----------------------------------------------------------------------------
242 // construction and destruction
243 // ----------------------------------------------------------------------------
244
245 void wxTreeCtrl::Init()
246 {
247 m_imageListNormal = NULL;
248 m_imageListState = NULL;
249 m_textCtrl = NULL;
250 }
251
252 bool wxTreeCtrl::Create(wxWindow *parent,
253 wxWindowID id,
254 const wxPoint& pos,
255 const wxSize& size,
256 long style,
257 const wxValidator& validator,
258 const wxString& name)
259 {
260 Init();
261
262 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
263 return FALSE;
264 // TODO:
265 /*
266 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
267 TVS_HASLINES | TVS_SHOWSELALWAYS;
268
269 if ( m_windowStyle & wxTR_HAS_BUTTONS )
270 wstyle |= TVS_HASBUTTONS;
271
272 if ( m_windowStyle & wxTR_EDIT_LABELS )
273 wstyle |= TVS_EDITLABELS;
274
275 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
276 wstyle |= TVS_LINESATROOT;
277
278 if ( m_windowStyle & wxTR_MULTIPLE )
279 wstyle |= TVS_CHECKBOXES;
280
281 // Create the tree control.
282 if ( !OS2CreateControl(WC_TREEVIEW, wstyle) )
283 return FALSE;
284 */
285 SetBackgroundColour(wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOW));
286 SetForegroundColour(wxWindow::GetParent()->GetForegroundColour());
287
288 // VZ: this is some experimental code which may be used to get the
289 // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71.
290 // AFAIK, the standard DLL does about the same thing anyhow.
291 #if 0
292 if ( m_windowStyle & wxTR_MULTIPLE )
293 {
294 wxBitmap bmp;
295
296 // create the DC compatible with the current screen
297 HDC hdcMem = CreateCompatibleDC(NULL);
298
299 // create a mono bitmap of the standard size
300 int x = GetSystemMetrics(SM_CXMENUCHECK);
301 int y = GetSystemMetrics(SM_CYMENUCHECK);
302 wxImageList imagelistCheckboxes(x, y, FALSE, 2);
303 HBITMAP hbmpCheck = CreateBitmap(x, y, // bitmap size
304 1, // # of color planes
305 1, // # bits needed for one pixel
306 0); // array containing colour data
307 SelectObject(hdcMem, hbmpCheck);
308
309 // then draw a check mark into it
310 RECT rect = { 0, 0, x, y };
311 if ( !::DrawFrameControl(hdcMem, &rect,
312 DFC_BUTTON,
313 DFCS_BUTTONCHECK | DFCS_CHECKED) )
314 {
315 wxLogLastError(wxT("DrawFrameControl(check)"));
316 }
317
318 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
319 imagelistCheckboxes.Add(bmp);
320
321 if ( !::DrawFrameControl(hdcMem, &rect,
322 DFC_BUTTON,
323 DFCS_BUTTONCHECK) )
324 {
325 wxLogLastError(wxT("DrawFrameControl(uncheck)"));
326 }
327
328 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
329 imagelistCheckboxes.Add(bmp);
330
331 // clean up
332 ::DeleteDC(hdcMem);
333
334 // set the imagelist
335 SetStateImageList(&imagelistCheckboxes);
336 }
337 #endif // 0
338
339 SetSize(pos.x, pos.y, size.x, size.y);
340
341 return TRUE;
342 }
343
344 wxTreeCtrl::~wxTreeCtrl()
345 {
346 DeleteTextCtrl();
347
348 // delete user data to prevent memory leaks
349 // DeleteAllItems();
350 }
351
352 // ----------------------------------------------------------------------------
353 // accessors
354 // ----------------------------------------------------------------------------
355
356 // simple wrappers which add error checking in debug mode
357
358 bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
359 {
360 // TODO:
361 /*
362 if ( !TreeView_GetItem(GetHwnd(), tvItem) )
363 {
364 wxLogLastError("TreeView_GetItem");
365
366 return FALSE;
367 }
368 */
369 return TRUE;
370 }
371
372 void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
373 {
374 // TODO:
375 /*
376 if ( TreeView_SetItem(GetHwnd(), tvItem) == -1 )
377 {
378 wxLogLastError("TreeView_SetItem");
379 }
380 */
381 }
382
383 size_t wxTreeCtrl::GetCount() const
384 {
385 // return (size_t)TreeView_GetCount(GetHwnd());
386 return 0;
387 }
388
389 unsigned int wxTreeCtrl::GetIndent() const
390 {
391 // return TreeView_GetIndent(GetHwnd());
392 return 0;
393 }
394
395 void wxTreeCtrl::SetIndent(unsigned int indent)
396 {
397 // TreeView_SetIndent(GetHwnd(), indent);
398 }
399
400 wxImageList *wxTreeCtrl::GetImageList() const
401 {
402 return m_imageListNormal;
403 }
404
405 wxImageList *wxTreeCtrl::GetStateImageList() const
406 {
407 return m_imageListNormal;
408 }
409
410 void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
411 {
412 // no error return
413 // TODO:
414 /*
415 TreeView_SetImageList(GetHwnd(),
416 imageList ? imageList->GetHIMAGELIST() : 0,
417 which);
418 */
419 }
420
421 void wxTreeCtrl::SetImageList(wxImageList *imageList)
422 {
423 // SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
424 }
425
426 void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
427 {
428 // SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
429 }
430
431 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
432 bool recursively) const
433 {
434 TraverseCounter counter(this, item, recursively);
435
436 return counter.GetCount() - 1;
437 }
438
439 // ----------------------------------------------------------------------------
440 // Item access
441 // ----------------------------------------------------------------------------
442
443 wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
444 {
445 wxChar buf[512]; // the size is arbitrary...
446 // TODO:
447 /*
448 wxTreeViewItem tvItem(item, TVIF_TEXT);
449 tvItem.pszText = buf;
450 tvItem.cchTextMax = WXSIZEOF(buf);
451 if ( !DoGetItem(&tvItem) )
452 {
453 // don't return some garbage which was on stack, but an empty string
454 buf[0] = wxT('\0');
455 }
456 */
457 return wxString(buf);
458 }
459
460 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
461 {
462 // TODO:
463 /*
464 wxTreeViewItem tvItem(item, TVIF_TEXT);
465 tvItem.pszText = (wxChar *)text.c_str(); // conversion is ok
466 DoSetItem(&tvItem);
467 */
468 }
469
470 int wxTreeCtrl::DoGetItemImageFromData(const wxTreeItemId& item,
471 wxTreeItemIcon which) const
472 {
473 // TODO:
474 /*
475 wxTreeViewItem tvItem(item, TVIF_PARAM);
476 if ( !DoGetItem(&tvItem) )
477 {
478 return -1;
479 }
480 return ((wxTreeItemIndirectData *)tvItem.lParam)->GetImage(which);
481 */
482 return -1;
483 }
484
485 void wxTreeCtrl::DoSetItemImageFromData(const wxTreeItemId& item,
486 int image,
487 wxTreeItemIcon which) const
488 {
489 // TODO:
490 /*
491 wxTreeViewItem tvItem(item, TVIF_PARAM);
492 if ( !DoGetItem(&tvItem) )
493 {
494 return;
495 }
496
497 wxTreeItemIndirectData *data = ((wxTreeItemIndirectData *)tvItem.lParam);
498
499 data->SetImage(image, which);
500
501 // make sure that we have selected images as well
502 if ( which == wxTreeItemIcon_Normal &&
503 !data->HasImage(wxTreeItemIcon_Selected) )
504 {
505 data->SetImage(image, wxTreeItemIcon_Selected);
506 }
507
508 if ( which == wxTreeItemIcon_Expanded &&
509 !data->HasImage(wxTreeItemIcon_SelectedExpanded) )
510 {
511 data->SetImage(image, wxTreeItemIcon_SelectedExpanded);
512 }
513 */
514 }
515
516 void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
517 int image,
518 int imageSel)
519 {
520 // TODO:
521 /*
522 wxTreeViewItem tvItem(item, TVIF_IMAGE | TVIF_SELECTEDIMAGE);
523 tvItem.iSelectedImage = imageSel;
524 tvItem.iImage = image;
525 DoSetItem(&tvItem);
526 */
527 }
528
529 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item,
530 wxTreeItemIcon which) const
531 {
532 if ( HasIndirectData(item) )
533 {
534 return DoGetItemImageFromData(item, which);
535 }
536
537 UINT mask;
538 switch ( which )
539 {
540 default:
541 wxFAIL_MSG( wxT("unknown tree item image type") );
542
543 case wxTreeItemIcon_Normal:
544 // mask = TVIF_IMAGE;
545 break;
546
547 case wxTreeItemIcon_Selected:
548 // mask = TVIF_SELECTEDIMAGE;
549 break;
550
551 case wxTreeItemIcon_Expanded:
552 case wxTreeItemIcon_SelectedExpanded:
553 return -1;
554 }
555
556 wxTreeViewItem tvItem(item, mask);
557 DoGetItem(&tvItem);
558
559 // return mask == TVIF_IMAGE ? tvItem.iImage : tvItem.iSelectedImage;
560 return FALSE;
561 }
562
563 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image,
564 wxTreeItemIcon which)
565 {
566 int imageNormal, imageSel;
567 switch ( which )
568 {
569 default:
570 wxFAIL_MSG( wxT("unknown tree item image type") );
571
572 case wxTreeItemIcon_Normal:
573 imageNormal = image;
574 imageSel = GetItemSelectedImage(item);
575 break;
576
577 case wxTreeItemIcon_Selected:
578 imageNormal = GetItemImage(item);
579 imageSel = image;
580 break;
581
582 case wxTreeItemIcon_Expanded:
583 case wxTreeItemIcon_SelectedExpanded:
584 if ( !HasIndirectData(item) )
585 {
586 // we need to get the old images first, because after we create
587 // the wxTreeItemIndirectData GetItemXXXImage() will use it to
588 // get the images
589 imageNormal = GetItemImage(item);
590 imageSel = GetItemSelectedImage(item);
591
592 // if it doesn't have it yet, add it
593 wxTreeItemIndirectData *data = new
594 wxTreeItemIndirectData(this, item);
595
596 // copy the data to the new location
597 data->SetImage(imageNormal, wxTreeItemIcon_Normal);
598 data->SetImage(imageSel, wxTreeItemIcon_Selected);
599 }
600
601 DoSetItemImageFromData(item, image, which);
602
603 // reset the normal/selected images because we won't use them any
604 // more - now they're stored inside the indirect data
605 // imageSel = I_IMAGECALLBACK;
606 break;
607 }
608
609 // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
610 // change both normal and selected image - otherwise the change simply
611 // doesn't take place!
612 DoSetItemImages(item, imageNormal, imageSel);
613 }
614
615 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
616 {
617 // TODO:
618 /*
619 wxTreeViewItem tvItem(item, TVIF_PARAM);
620 if ( !DoGetItem(&tvItem) )
621 {
622 return NULL;
623 }
624
625 if ( HasIndirectData(item) )
626 {
627 return ((wxTreeItemIndirectData *)tvItem.lParam)->GetData();
628 }
629 else
630 {
631 return (wxTreeItemData *)tvItem.lParam;
632 }
633 */
634 return 0;
635 }
636
637 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
638 {
639 // TODO:
640 /*
641 wxTreeViewItem tvItem(item, TVIF_PARAM);
642
643 if ( HasIndirectData(item) )
644 {
645 if ( DoGetItem(&tvItem) )
646 {
647 ((wxTreeItemIndirectData *)tvItem.lParam)->SetData(data);
648 }
649 else
650 {
651 wxFAIL_MSG( wxT("failed to change tree items data") );
652 }
653 }
654 else
655 {
656 tvItem.lParam = (MPARAM)data;
657 DoSetItem(&tvItem);
658 }
659 */
660 }
661
662 void wxTreeCtrl::SetIndirectItemData(const wxTreeItemId& item,
663 wxTreeItemIndirectData *data)
664 {
665 // this should never happen because it's unnecessary and will probably lead
666 // to crash too because the code elsewhere supposes that the pointer the
667 // wxTreeItemIndirectData has is a real wxItemData and not
668 // wxTreeItemIndirectData as well
669 wxASSERT_MSG( !HasIndirectData(item), wxT("setting indirect data twice?") );
670
671 SetItemData(item, (wxTreeItemData *)data);
672
673 m_itemsWithIndirectData.Add(item);
674 }
675
676 bool wxTreeCtrl::HasIndirectData(const wxTreeItemId& item) const
677 {
678 return m_itemsWithIndirectData.Index(item) != wxNOT_FOUND;
679 }
680
681 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
682 {
683 // TODO:
684 /*
685 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
686 tvItem.cChildren = (int)has;
687 DoSetItem(&tvItem);
688 */
689 }
690
691 void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
692 {
693 // TODO:
694 /*
695 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
696 tvItem.state = bold ? TVIS_BOLD : 0;
697 DoSetItem(&tvItem);
698 */
699 }
700
701 void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
702 {
703 // TODO:
704 /*
705 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
706 tvItem.state = highlight ? TVIS_DROPHILITED : 0;
707 DoSetItem(&tvItem);
708 */
709 }
710
711 // ----------------------------------------------------------------------------
712 // Item status
713 // ----------------------------------------------------------------------------
714
715 bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
716 {
717 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
718 // TODO:
719 /*
720 RECT rect;
721 return SendMessage(GetHwnd(), TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
722 */
723 return FALSE;
724 }
725
726 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
727 {
728 // TODO:
729 /*
730 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
731 DoGetItem(&tvItem);
732
733 return tvItem.cChildren != 0;
734 */
735 return FALSE;
736 }
737
738 bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
739 {
740 // probably not a good idea to put it here
741 //wxASSERT( ItemHasChildren(item) );
742
743 // TODO:
744 /*
745 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
746 DoGetItem(&tvItem);
747
748 return (tvItem.state & TVIS_EXPANDED) != 0;
749 */
750 return FALSE;
751 }
752
753 bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
754 {
755 // TODO:
756 /*
757 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
758 DoGetItem(&tvItem);
759
760 return (tvItem.state & TVIS_SELECTED) != 0;
761 */
762 return FALSE;
763 }
764
765 bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
766 {
767 // TODO:
768 /*
769 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
770 DoGetItem(&tvItem);
771
772 return (tvItem.state & TVIS_BOLD) != 0;
773 */
774 return FALSE;
775 }
776
777 // ----------------------------------------------------------------------------
778 // navigation
779 // ----------------------------------------------------------------------------
780
781 wxTreeItemId wxTreeCtrl::GetRootItem() const
782 {
783 // return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(GetHwnd()));
784 return 0;
785 }
786
787 wxTreeItemId wxTreeCtrl::GetSelection() const
788 {
789 wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0,
790 wxT("this only works with single selection controls") );
791
792 // return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd()));
793 return 0;
794 }
795
796 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
797 {
798 // return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
799 return 0;
800 }
801
802 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
803 long& _cookie) const
804 {
805 // TODO:
806 /*
807 // remember the last child returned in 'cookie'
808 _cookie = (long)TreeView_GetChild(GetHwnd(), (HTREEITEM) (WXHTREEITEM)item);
809
810 return wxTreeItemId((WXHTREEITEM)_cookie);
811 */
812 return 0;
813 }
814
815 wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
816 long& _cookie) const
817 {
818 wxTreeItemId l = 0; //wxTreeItemId((WXHTREEITEM)TreeView_GetNextSibling(GetHwnd(),
819 // (HTREEITEM)(WXHTREEITEM)_cookie));
820 _cookie = (long)l;
821
822 return l;
823 }
824
825 wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
826 {
827 // can this be done more efficiently?
828 long cookie;
829
830 wxTreeItemId childLast,
831 child = GetFirstChild(item, cookie);
832 while ( child.IsOk() )
833 {
834 childLast = child;
835 child = GetNextChild(item, cookie);
836 }
837
838 return childLast;
839 }
840
841 wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
842 {
843 // return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
844 return 0;
845 }
846
847 wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
848 {
849 // return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
850 return 0;
851 }
852
853 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
854 {
855 // return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(GetHwnd()));
856 return 0;
857 }
858
859 wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
860 {
861 wxASSERT_MSG( IsVisible(item), wxT("The item you call GetNextVisible() "
862 "for must be visible itself!"));
863
864 // return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
865 return 0;
866 }
867
868 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
869 {
870 wxASSERT_MSG( IsVisible(item), wxT("The item you call GetPrevVisible() "
871 "for must be visible itself!"));
872
873 // return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
874 return 0;
875 }
876
877 // ----------------------------------------------------------------------------
878 // multiple selections emulation
879 // ----------------------------------------------------------------------------
880
881 bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const
882 {
883 // receive the desired information.
884 // TODO:
885 /*
886 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
887 DoGetItem(&tvItem);
888
889 // state image indices are 1 based
890 return ((tvItem.state >> 12) - 1) == 1;
891 */
892 return FALSE;
893 }
894
895 void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
896 {
897 // receive the desired information.
898 // TODO:
899 /*
900 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
901
902 // state images are one-based
903 tvItem.state = (check ? 2 : 1) << 12;
904
905 DoSetItem(&tvItem);
906 */
907 }
908
909 size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const
910 {
911 TraverseSelections selector(this, selections);
912
913 return selections.GetCount();
914 }
915
916 // ----------------------------------------------------------------------------
917 // Usual operations
918 // ----------------------------------------------------------------------------
919
920 wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
921 wxTreeItemId hInsertAfter,
922 const wxString& text,
923 int image, int selectedImage,
924 wxTreeItemData *data)
925 {
926 // TODO:
927 /*
928 TV_INSERTSTRUCT tvIns;
929 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
930 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
931
932 // this is how we insert the item as the first child: supply a NULL
933 // hInsertAfter
934 if ( !tvIns.hInsertAfter )
935 {
936 tvIns.hInsertAfter = TVI_FIRST;
937 }
938
939 UINT mask = 0;
940 if ( !text.IsEmpty() )
941 {
942 mask |= TVIF_TEXT;
943 tvIns.item.pszText = (wxChar *)text.c_str(); // cast is ok
944 }
945
946 if ( image != -1 )
947 {
948 mask |= TVIF_IMAGE;
949 tvIns.item.iImage = image;
950
951 if ( selectedImage == -1 )
952 {
953 // take the same image for selected icon if not specified
954 selectedImage = image;
955 }
956 }
957
958 if ( selectedImage != -1 )
959 {
960 mask |= TVIF_SELECTEDIMAGE;
961 tvIns.item.iSelectedImage = selectedImage;
962 }
963
964 if ( data != NULL )
965 {
966 mask |= TVIF_PARAM;
967 tvIns.item.lParam = (LPARAM)data;
968 }
969
970 tvIns.item.mask = mask;
971
972 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns);
973 if ( id == 0 )
974 {
975 wxLogLastError("TreeView_InsertItem");
976 }
977
978 if ( data != NULL )
979 {
980 // associate the application tree item with Win32 tree item handle
981 data->SetId((WXHTREEITEM)id);
982 }
983
984 return wxTreeItemId((WXHTREEITEM)id);
985 */
986 return 0;
987 }
988
989 // for compatibility only
990 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
991 const wxString& text,
992 int image, int selImage,
993 long insertAfter)
994 {
995 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
996 image, selImage, NULL);
997 }
998
999 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
1000 int image, int selectedImage,
1001 wxTreeItemData *data)
1002 {
1003 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
1004 text, image, selectedImage, data);
1005 }
1006
1007 wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
1008 const wxString& text,
1009 int image, int selectedImage,
1010 wxTreeItemData *data)
1011 {
1012 // TODO:
1013 /*
1014 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
1015 text, image, selectedImage, data);
1016 */
1017 return 0;
1018 }
1019
1020 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
1021 const wxTreeItemId& idPrevious,
1022 const wxString& text,
1023 int image, int selectedImage,
1024 wxTreeItemData *data)
1025 {
1026 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
1027 }
1028
1029 wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
1030 const wxString& text,
1031 int image, int selectedImage,
1032 wxTreeItemData *data)
1033 {
1034 // TODO:
1035 /*
1036 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
1037 text, image, selectedImage, data);
1038 */
1039 return 0;
1040 }
1041
1042 void wxTreeCtrl::Delete(const wxTreeItemId& item)
1043 {
1044 // TODO:
1045 /*
1046 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item) )
1047 {
1048 wxLogLastError("TreeView_DeleteItem");
1049 }
1050 */
1051 }
1052
1053 // delete all children (but don't delete the item itself)
1054 void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
1055 {
1056 long cookie;
1057
1058 wxArrayLong children;
1059 wxTreeItemId child = GetFirstChild(item, cookie);
1060 while ( child.IsOk() )
1061 {
1062 children.Add((long)(WXHTREEITEM)child);
1063
1064 child = GetNextChild(item, cookie);
1065 }
1066
1067 size_t nCount = children.Count();
1068 // TODO:
1069 /*
1070 for ( size_t n = 0; n < nCount; n++ )
1071 {
1072 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)children[n]) )
1073 {
1074 wxLogLastError("TreeView_DeleteItem");
1075 }
1076 }
1077 */
1078 }
1079
1080 void wxTreeCtrl::DeleteAllItems()
1081 {
1082 // TODO:
1083 /*
1084 if ( !TreeView_DeleteAllItems(GetHwnd()) )
1085 {
1086 wxLogLastError("TreeView_DeleteAllItems");
1087 }
1088 */
1089 }
1090
1091 void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
1092 {
1093 // TODO:
1094 /*
1095 wxASSERT_MSG( flag == TVE_COLLAPSE ||
1096 flag == (TVE_COLLAPSE | TVE_COLLAPSERESET) ||
1097 flag == TVE_EXPAND ||
1098 flag == TVE_TOGGLE,
1099 wxT("Unknown flag in wxTreeCtrl::DoExpand") );
1100
1101 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
1102 // emulate them. This behaviour has changed slightly with comctl32.dll
1103 // v 4.70 - now it does send them but only the first time. To maintain
1104 // compatible behaviour and also in order to not have surprises with the
1105 // future versions, don't rely on this and still do everything ourselves.
1106 // To avoid that the messages be sent twice when the item is expanded for
1107 // the first time we must clear TVIS_EXPANDEDONCE style manually.
1108
1109 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDEDONCE);
1110 tvItem.state = 0;
1111 DoSetItem(&tvItem);
1112
1113 if ( TreeView_Expand(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
1114 {
1115 wxTreeEvent event(wxEVT_NULL, m_windowId);
1116 event.m_item = item;
1117
1118 bool isExpanded = IsExpanded(item);
1119
1120 event.SetEventObject(this);
1121
1122 // FIXME return value of {EXPAND|COLLAPS}ING event handler is discarded
1123 event.SetEventType(g_events[isExpanded][TRUE]);
1124 GetEventHandler()->ProcessEvent(event);
1125
1126 event.SetEventType(g_events[isExpanded][FALSE]);
1127 GetEventHandler()->ProcessEvent(event);
1128 }
1129 //else: change didn't took place, so do nothing at all
1130 */
1131 }
1132
1133 void wxTreeCtrl::Expand(const wxTreeItemId& item)
1134 {
1135 // DoExpand(item, TVE_EXPAND);
1136 }
1137
1138 void wxTreeCtrl::Collapse(const wxTreeItemId& item)
1139 {
1140 // DoExpand(item, TVE_COLLAPSE);
1141 }
1142
1143 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
1144 {
1145 // DoExpand(item, TVE_COLLAPSE | TVE_COLLAPSERESET);
1146 }
1147
1148 void wxTreeCtrl::Toggle(const wxTreeItemId& item)
1149 {
1150 // DoExpand(item, TVE_TOGGLE);
1151 }
1152
1153 void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
1154 {
1155 // DoExpand(item, action);
1156 }
1157
1158 void wxTreeCtrl::Unselect()
1159 {
1160 wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), wxT("doesn't make sense") );
1161
1162 // just remove the selection
1163 // SelectItem(wxTreeItemId((WXHTREEITEM) 0));
1164 }
1165
1166 void wxTreeCtrl::UnselectAll()
1167 {
1168 if ( m_windowStyle & wxTR_MULTIPLE )
1169 {
1170 wxArrayTreeItemIds selections;
1171 size_t count = GetSelections(selections);
1172 for ( size_t n = 0; n < count; n++ )
1173 {
1174 SetItemCheck(selections[n], FALSE);
1175 }
1176 }
1177 else
1178 {
1179 // just remove the selection
1180 Unselect();
1181 }
1182 }
1183
1184 void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
1185 {
1186 if ( m_windowStyle & wxTR_MULTIPLE )
1187 {
1188 // selecting the item means checking it
1189 SetItemCheck(item);
1190 }
1191 else
1192 {
1193 // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
1194 // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
1195 // send them ourselves
1196
1197 wxTreeEvent event(wxEVT_NULL, m_windowId);
1198 event.m_item = item;
1199 event.SetEventObject(this);
1200
1201 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
1202 // TODO:
1203 /*
1204 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
1205 {
1206 if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
1207 {
1208 wxLogLastError("TreeView_SelectItem");
1209 }
1210 else
1211 {
1212 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
1213 (void)GetEventHandler()->ProcessEvent(event);
1214 }
1215 }
1216 //else: program vetoed the change
1217 */
1218 }
1219 }
1220
1221 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
1222 {
1223 // no error return
1224 // TreeView_EnsureVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
1225 }
1226
1227 void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
1228 {
1229 // TODO:
1230 /*
1231 if ( !TreeView_SelectSetFirstVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
1232 {
1233 wxLogLastError("TreeView_SelectSetFirstVisible");
1234 }
1235 */
1236 }
1237
1238 wxTextCtrl* wxTreeCtrl::GetEditControl() const
1239 {
1240 return m_textCtrl;
1241 }
1242
1243 void wxTreeCtrl::DeleteTextCtrl()
1244 {
1245 if ( m_textCtrl )
1246 {
1247 m_textCtrl->UnsubclassWin();
1248 m_textCtrl->SetHWND(0);
1249 delete m_textCtrl;
1250 m_textCtrl = NULL;
1251 }
1252 }
1253
1254 wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
1255 wxClassInfo* textControlClass)
1256 {
1257 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
1258
1259 // TODO:
1260 /*
1261 HWND hWnd = (HWND) TreeView_EditLabel(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
1262
1263 // this is not an error - the TVN_BEGINLABELEDIT handler might have
1264 // returned FALSE
1265 if ( !hWnd )
1266 {
1267 return NULL;
1268 }
1269
1270 DeleteTextCtrl();
1271
1272 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
1273 m_textCtrl->SetHWND((WXHWND)hWnd);
1274 m_textCtrl->SubclassWin((WXHWND)hWnd);
1275 */
1276 return m_textCtrl;
1277 }
1278
1279 // End label editing, optionally cancelling the edit
1280 void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
1281 {
1282 // TreeView_EndEditLabelNow(GetHwnd(), discardChanges);
1283
1284 DeleteTextCtrl();
1285 }
1286
1287 wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
1288 {
1289 // TODO:
1290 /*
1291 TV_HITTESTINFO hitTestInfo;
1292 hitTestInfo.pt.x = (int)point.x;
1293 hitTestInfo.pt.y = (int)point.y;
1294
1295 TreeView_HitTest(GetHwnd(), &hitTestInfo);
1296
1297 flags = 0;
1298
1299 // avoid repetition
1300 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
1301 flags |= wxTREE_HITTEST_##flag
1302
1303 TRANSLATE_FLAG(ABOVE);
1304 TRANSLATE_FLAG(BELOW);
1305 TRANSLATE_FLAG(NOWHERE);
1306 TRANSLATE_FLAG(ONITEMBUTTON);
1307 TRANSLATE_FLAG(ONITEMICON);
1308 TRANSLATE_FLAG(ONITEMINDENT);
1309 TRANSLATE_FLAG(ONITEMLABEL);
1310 TRANSLATE_FLAG(ONITEMRIGHT);
1311 TRANSLATE_FLAG(ONITEMSTATEICON);
1312 TRANSLATE_FLAG(TOLEFT);
1313 TRANSLATE_FLAG(TORIGHT);
1314
1315 #undef TRANSLATE_FLAG
1316
1317 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
1318 */
1319 return 0;
1320 }
1321
1322 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
1323 wxRect& rect,
1324 bool textOnly) const
1325 {
1326 // TODO:
1327 /*
1328 RECT rc;
1329 if ( TreeView_GetItemRect(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item,
1330 &rc, textOnly) )
1331 {
1332 rect = wxRect(wxPoint(rc.left, rc.top), wxPoint(rc.right, rc.bottom));
1333
1334 return TRUE;
1335 }
1336 else
1337 {
1338 // couldn't retrieve rect: for example, item isn't visible
1339 return FALSE;
1340 }
1341 */
1342 return FALSE;
1343 }
1344
1345 // ----------------------------------------------------------------------------
1346 // sorting stuff
1347 // ----------------------------------------------------------------------------
1348
1349 static int TreeView_CompareCallback(wxTreeItemData *pItem1,
1350 wxTreeItemData *pItem2,
1351 wxTreeCtrl *tree)
1352 {
1353 wxCHECK_MSG( pItem1 && pItem2, 0,
1354 wxT("sorting tree without data doesn't make sense") );
1355
1356 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
1357 }
1358
1359 int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
1360 const wxTreeItemId& item2)
1361 {
1362 return wxStrcmp(GetItemText(item1), GetItemText(item2));
1363 }
1364
1365 void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
1366 {
1367 // rely on the fact that TreeView_SortChildren does the same thing as our
1368 // default behaviour, i.e. sorts items alphabetically and so call it
1369 // directly if we're not in derived class (much more efficient!)
1370 // TODO:
1371 /*
1372 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl) )
1373 {
1374 TreeView_SortChildren(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item, 0);
1375 }
1376 else
1377 {
1378 TV_SORTCB tvSort;
1379 tvSort.hParent = (HTREEITEM)(WXHTREEITEM)item;
1380 tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
1381 tvSort.lParam = (LPARAM)this;
1382 TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0);
1383 }
1384 */
1385 }
1386
1387 // ----------------------------------------------------------------------------
1388 // implementation
1389 // ----------------------------------------------------------------------------
1390
1391 bool wxTreeCtrl::OS2Command(WXUINT cmd, WXWORD id)
1392 {
1393 // TODO:
1394 /*
1395 if ( cmd == EN_UPDATE )
1396 {
1397 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
1398 event.SetEventObject( this );
1399 ProcessCommand(event);
1400 }
1401 else if ( cmd == EN_KILLFOCUS )
1402 {
1403 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
1404 event.SetEventObject( this );
1405 ProcessCommand(event);
1406 }
1407 else
1408 {
1409 // nothing done
1410 return FALSE;
1411 }
1412
1413 // command processed
1414 return TRUE;
1415 */
1416 return FALSE;
1417 }
1418
1419 // process WM_NOTIFY Windows message
1420 bool wxTreeCtrl::OS2OnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
1421 {
1422 // TODO:
1423 /*
1424 wxTreeEvent event(wxEVT_NULL, m_windowId);
1425 wxEventType eventType = wxEVT_NULL;
1426 NMHDR *hdr = (NMHDR *)lParam;
1427
1428 switch ( hdr->code )
1429 {
1430 case NM_RCLICK:
1431 {
1432 if ( wxControl::MSWOnNotify(idCtrl, lParam, result) )
1433 return TRUE;
1434
1435 TV_HITTESTINFO tvhti;
1436 ::GetCursorPos(&(tvhti.pt));
1437 ::ScreenToClient(GetHwnd(),&(tvhti.pt));
1438 if ( TreeView_HitTest(GetHwnd(),&tvhti) )
1439 {
1440 if( tvhti.flags & TVHT_ONITEM )
1441 {
1442 event.m_item = (WXHTREEITEM) tvhti.hItem;
1443 eventType=wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK;
1444 }
1445 }
1446 break;
1447 }
1448
1449 case TVN_BEGINDRAG:
1450 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
1451 // fall through
1452
1453 case TVN_BEGINRDRAG:
1454 {
1455 if ( eventType == wxEVT_NULL )
1456 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
1457 //else: left drag, already set above
1458
1459 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1460
1461 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1462 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
1463 break;
1464 }
1465
1466 case TVN_BEGINLABELEDIT:
1467 {
1468 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
1469 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1470
1471 event.m_item = (WXHTREEITEM) info->item.hItem;
1472 event.m_label = info->item.pszText;
1473 break;
1474 }
1475
1476 case TVN_DELETEITEM:
1477 {
1478 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
1479 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1480
1481 event.m_item = (WXHTREEITEM) tv->itemOld.hItem;
1482 break;
1483 }
1484
1485 case TVN_ENDLABELEDIT:
1486 {
1487 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
1488 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1489
1490 event.m_item = (WXHTREEITEM)info->item.hItem;
1491 event.m_label = info->item.pszText;
1492 break;
1493 }
1494
1495 case TVN_GETDISPINFO:
1496 eventType = wxEVT_COMMAND_TREE_GET_INFO;
1497 // fall through
1498
1499 case TVN_SETDISPINFO:
1500 {
1501 if ( eventType == wxEVT_NULL )
1502 eventType = wxEVT_COMMAND_TREE_SET_INFO;
1503 //else: get, already set above
1504
1505 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1506
1507 event.m_item = (WXHTREEITEM) info->item.hItem;
1508 break;
1509 }
1510
1511 case TVN_ITEMEXPANDING:
1512 event.m_code = FALSE;
1513 // fall through
1514
1515 case TVN_ITEMEXPANDED:
1516 {
1517 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
1518
1519 bool expand = FALSE;
1520 switch ( tv->action )
1521 {
1522 case TVE_EXPAND:
1523 expand = TRUE;
1524 break;
1525
1526 case TVE_COLLAPSE:
1527 expand = FALSE;
1528 break;
1529
1530 default:
1531 wxLogDebug(wxT("unexpected code %d in TVN_ITEMEXPAND "
1532 "message"), tv->action);
1533 }
1534
1535 bool ing = ((int)hdr->code == TVN_ITEMEXPANDING);
1536 eventType = g_events[expand][ing];
1537
1538 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1539 break;
1540 }
1541
1542 case TVN_KEYDOWN:
1543 {
1544 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
1545 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
1546
1547 event.m_code = wxCharCodeMSWToWX(info->wVKey);
1548
1549 // a separate event for this case
1550 if ( info->wVKey == VK_SPACE || info->wVKey == VK_RETURN )
1551 {
1552 wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
1553 m_windowId);
1554 event2.SetEventObject(this);
1555
1556 GetEventHandler()->ProcessEvent(event2);
1557 }
1558 break;
1559 }
1560
1561 case TVN_SELCHANGED:
1562 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
1563 // fall through
1564
1565 case TVN_SELCHANGING:
1566 {
1567 if ( eventType == wxEVT_NULL )
1568 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
1569 //else: already set above
1570
1571 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1572
1573 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1574 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
1575 break;
1576 }
1577
1578 default:
1579 return wxControl::MSWOnNotify(idCtrl, lParam, result);
1580 }
1581
1582 event.SetEventObject(this);
1583 event.SetEventType(eventType);
1584
1585 bool processed = GetEventHandler()->ProcessEvent(event);
1586
1587 // post processing
1588 switch ( hdr->code )
1589 {
1590 case TVN_DELETEITEM:
1591 {
1592 // NB: we might process this message using wxWindows event
1593 // tables, but due to overhead of wxWin event system we
1594 // prefer to do it here ourself (otherwise deleting a tree
1595 // with many items is just too slow)
1596 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1597
1598 wxTreeItemId item = event.m_item;
1599 if ( HasIndirectData(item) )
1600 {
1601 wxTreeItemIndirectData *data = (wxTreeItemIndirectData *)
1602 tv->itemOld.lParam;
1603 delete data; // can't be NULL here
1604
1605 m_itemsWithIndirectData.Remove(item);
1606 }
1607 else
1608 {
1609 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
1610 delete data; // may be NULL, ok
1611 }
1612
1613 processed = TRUE; // Make sure we don't get called twice
1614 }
1615 break;
1616
1617 case TVN_BEGINLABELEDIT:
1618 // return TRUE to cancel label editing
1619 *result = !event.IsAllowed();
1620 break;
1621
1622 case TVN_ENDLABELEDIT:
1623 // return TRUE to set the label to the new string
1624 *result = event.IsAllowed();
1625
1626 // ensure that we don't have the text ctrl which is going to be
1627 // deleted any more
1628 DeleteTextCtrl();
1629 break;
1630
1631 case TVN_SELCHANGING:
1632 case TVN_ITEMEXPANDING:
1633 // return TRUE to prevent the action from happening
1634 *result = !event.IsAllowed();
1635 break;
1636
1637 case TVN_GETDISPINFO:
1638 // NB: so far the user can't set the image himself anyhow, so do it
1639 // anyway - but this may change later
1640 if ( 1 // !processed && )
1641 {
1642 wxTreeItemId item = event.m_item;
1643 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1644 if ( info->item.mask & TVIF_IMAGE )
1645 {
1646 info->item.iImage =
1647 DoGetItemImageFromData
1648 (
1649 item,
1650 IsExpanded(item) ? wxTreeItemIcon_Expanded
1651 : wxTreeItemIcon_Normal
1652 );
1653 }
1654 if ( info->item.mask & TVIF_SELECTEDIMAGE )
1655 {
1656 info->item.iSelectedImage =
1657 DoGetItemImageFromData
1658 (
1659 item,
1660 IsExpanded(item) ? wxTreeItemIcon_SelectedExpanded
1661 : wxTreeItemIcon_Selected
1662 );
1663 }
1664 }
1665 break;
1666
1667 //default:
1668 // for the other messages the return value is ignored and there is
1669 // nothing special to do
1670 }
1671
1672 return processed;
1673 */
1674 return FALSE;
1675 }
1676
1677 // ----------------------------------------------------------------------------
1678 // Tree event
1679 // ----------------------------------------------------------------------------
1680
1681 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
1682
1683 wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
1684 : wxNotifyEvent(commandType, id)
1685 {
1686 m_code = 0;
1687 m_itemOld = 0;
1688 }
1689