]> git.saurik.com Git - wxWidgets.git/blob - src/msw/treectrl.cpp
wxUSE_SOCKETS added to setup(0).h; Cygwin corrections; doc tweaks
[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/wx.h"
32 #endif
33
34 #if defined(__WIN95__)
35
36 #include "wx/log.h"
37 #include "wx/dynarray.h"
38 #include "wx/imaglist.h"
39 #include "wx/msw/treectrl.h"
40
41 #include "wx/msw/private.h"
42
43 #ifdef __GNUWIN32__
44 #include "wx/msw/gnuwin32/extra.h"
45 #endif
46
47 #if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__)
48 #include <commctrl.h>
49 #endif
50
51 #ifdef GetFirstChild
52 #undef GetFirstChild
53 #endif
54
55 #ifdef GetNextChild
56 #undef GetNextChild
57 #endif
58
59 #ifdef GetNextSibling
60 #undef GetNextSibling
61 #endif
62
63 #ifdef GetClassInfo
64 #undef GetClassInfo
65 #endif
66
67 // Bug in headers, sometimes
68 #ifndef TVIS_FOCUSED
69 #define TVIS_FOCUSED 0x0001
70 #endif
71
72 // ----------------------------------------------------------------------------
73 // private classes
74 // ----------------------------------------------------------------------------
75
76 // a convenient wrapper around TV_ITEM struct which adds a ctor
77 struct wxTreeViewItem : public TV_ITEM
78 {
79 wxTreeViewItem(const wxTreeItemId& item,
80 UINT mask_, UINT stateMask_ = 0)
81 {
82 mask = mask_;
83 stateMask = stateMask_;
84 hItem = (HTREEITEM) (WXHTREEITEM) item;
85 }
86 };
87
88 // ----------------------------------------------------------------------------
89 // macros
90 // ----------------------------------------------------------------------------
91
92 #if !USE_SHARED_LIBRARY
93 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
94 #endif
95
96 // hide the ugly cast (of course, the macro is _quite_ ugly too...)
97 #define wxhWnd ((HWND)m_hWnd)
98
99 // ----------------------------------------------------------------------------
100 // variables
101 // ----------------------------------------------------------------------------
102
103 // handy table for sending events
104 static const wxEventType g_events[2][2] =
105 {
106 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
107 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
108 };
109
110 // ============================================================================
111 // implementation
112 // ============================================================================
113
114 // ----------------------------------------------------------------------------
115 // construction and destruction
116 // ----------------------------------------------------------------------------
117
118 void wxTreeCtrl::Init()
119 {
120 m_imageListNormal = NULL;
121 m_imageListState = NULL;
122 m_textCtrl = NULL;
123 }
124
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)
129 {
130 Init();
131
132 wxSystemSettings settings;
133
134 SetName(name);
135 SetValidator(validator);
136
137 m_windowStyle = style;
138
139 SetParent(parent);
140
141 m_windowId = (id == -1) ? NewControlId() : id;
142
143 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP | TVS_HASLINES;
144
145 bool want3D;
146 WXDWORD exStyle = Determine3DEffects(WS_EX_CLIENTEDGE, &want3D) ;
147
148 // Even with extended styles, need to combine with WS_BORDER
149 // for them to look right.
150 if ( want3D || wxStyleHasBorder(m_windowStyle) )
151 {
152 wstyle |= WS_BORDER;
153 }
154
155 if ( m_windowStyle & wxTR_HAS_BUTTONS )
156 wstyle |= TVS_HASBUTTONS;
157
158 if ( m_windowStyle & wxTR_EDIT_LABELS )
159 wstyle |= TVS_EDITLABELS;
160
161 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
162 wstyle |= TVS_LINESATROOT;
163
164 // Create the tree control.
165 m_hWnd = (WXHWND)::CreateWindowEx
166 (
167 exStyle,
168 WC_TREEVIEW,
169 "",
170 wstyle,
171 pos.x, pos.y, size.x, size.y,
172 (HWND)parent->GetHWND(),
173 (HMENU)m_windowId,
174 wxGetInstance(),
175 NULL
176 );
177
178 wxCHECK_MSG( m_hWnd, FALSE, "Failed to create tree ctrl" );
179
180 if ( parent )
181 parent->AddChild(this);
182
183 SubclassWin(m_hWnd);
184
185 return TRUE;
186 }
187
188 wxTreeCtrl::~wxTreeCtrl()
189 {
190 DeleteTextCtrl();
191
192 // delete user data to prevent memory leaks
193 DeleteAllItems();
194 }
195
196 // ----------------------------------------------------------------------------
197 // accessors
198 // ----------------------------------------------------------------------------
199
200 // simple wrappers which add error checking in debug mode
201
202 bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
203 {
204 if ( !TreeView_GetItem(wxhWnd, tvItem) )
205 {
206 wxLogLastError("TreeView_GetItem");
207
208 return FALSE;
209 }
210
211 return TRUE;
212 }
213
214 void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
215 {
216 if ( TreeView_SetItem(wxhWnd, tvItem) == -1 )
217 {
218 wxLogLastError("TreeView_SetItem");
219 }
220 }
221
222 size_t wxTreeCtrl::GetCount() const
223 {
224 return (size_t)TreeView_GetCount(wxhWnd);
225 }
226
227 unsigned int wxTreeCtrl::GetIndent() const
228 {
229 return TreeView_GetIndent(wxhWnd);
230 }
231
232 void wxTreeCtrl::SetIndent(unsigned int indent)
233 {
234 TreeView_SetIndent(wxhWnd, indent);
235 }
236
237 wxImageList *wxTreeCtrl::GetImageList() const
238 {
239 return m_imageListNormal;
240 }
241
242 wxImageList *wxTreeCtrl::GetStateImageList() const
243 {
244 return m_imageListNormal;
245 }
246
247 void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
248 {
249 // no error return
250 TreeView_SetImageList(wxhWnd,
251 imageList ? imageList->GetHIMAGELIST() : 0,
252 which);
253 }
254
255 void wxTreeCtrl::SetImageList(wxImageList *imageList)
256 {
257 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
258 }
259
260 void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
261 {
262 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
263 }
264
265 size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
266 {
267 long cookie;
268
269 size_t result = 0;
270
271 wxArrayLong children;
272 wxTreeItemId child = GetFirstChild(item, cookie);
273 while ( child.IsOk() )
274 {
275 if ( recursively )
276 {
277 // recursive call
278 result += GetChildrenCount(child, TRUE);
279 }
280
281 // add the child to the result in any case
282 result++;
283
284 child = GetNextChild(item, cookie);
285 }
286
287 return result;
288 }
289
290 // ----------------------------------------------------------------------------
291 // Item access
292 // ----------------------------------------------------------------------------
293
294 wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
295 {
296 char buf[512]; // the size is arbitrary...
297
298 wxTreeViewItem tvItem(item, TVIF_TEXT);
299 tvItem.pszText = buf;
300 tvItem.cchTextMax = WXSIZEOF(buf);
301 if ( !DoGetItem(&tvItem) )
302 {
303 // don't return some garbage which was on stack, but an empty string
304 buf[0] = '\0';
305 }
306
307 return wxString(buf);
308 }
309
310 void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
311 {
312 wxTreeViewItem tvItem(item, TVIF_TEXT);
313 tvItem.pszText = (char *)text.c_str(); // conversion is ok
314 DoSetItem(&tvItem);
315 }
316
317 int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
318 {
319 wxTreeViewItem tvItem(item, TVIF_IMAGE);
320 DoGetItem(&tvItem);
321
322 return tvItem.iImage;
323 }
324
325 void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
326 {
327 wxTreeViewItem tvItem(item, TVIF_IMAGE);
328 tvItem.iImage = image;
329 DoSetItem(&tvItem);
330 }
331
332 int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
333 {
334 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
335 DoGetItem(&tvItem);
336
337 return tvItem.iSelectedImage;
338 }
339
340 void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
341 {
342 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
343 tvItem.iSelectedImage = image;
344 DoSetItem(&tvItem);
345 }
346
347 wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
348 {
349 wxTreeViewItem tvItem(item, TVIF_PARAM);
350 if ( !DoGetItem(&tvItem) )
351 {
352 return NULL;
353 }
354
355 return (wxTreeItemData *)tvItem.lParam;
356 }
357
358 void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
359 {
360 wxTreeViewItem tvItem(item, TVIF_PARAM);
361 tvItem.lParam = (LPARAM)data;
362 DoSetItem(&tvItem);
363 }
364
365 void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
366 {
367 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
368 tvItem.cChildren = (int)has;
369 DoSetItem(&tvItem);
370 }
371
372 void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
373 {
374 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
375 tvItem.state = bold ? TVIS_BOLD : 0;
376 DoSetItem(&tvItem);
377 }
378
379 // ----------------------------------------------------------------------------
380 // Item status
381 // ----------------------------------------------------------------------------
382
383 bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
384 {
385 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
386 RECT rect;
387 return SendMessage(wxhWnd, TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
388
389 }
390
391 bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
392 {
393 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
394 DoGetItem(&tvItem);
395
396 return tvItem.cChildren != 0;
397 }
398
399 bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
400 {
401 // probably not a good idea to put it here
402 //wxASSERT( ItemHasChildren(item) );
403
404 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
405 DoGetItem(&tvItem);
406
407 return (tvItem.state & TVIS_EXPANDED) != 0;
408 }
409
410 bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
411 {
412 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
413 DoGetItem(&tvItem);
414
415 return (tvItem.state & TVIS_SELECTED) != 0;
416 }
417
418 bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
419 {
420 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
421 DoGetItem(&tvItem);
422
423 return (tvItem.state & TVIS_BOLD) != 0;
424 }
425
426 // ----------------------------------------------------------------------------
427 // navigation
428 // ----------------------------------------------------------------------------
429
430 wxTreeItemId wxTreeCtrl::GetRootItem() const
431 {
432 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(wxhWnd));
433 }
434
435 wxTreeItemId wxTreeCtrl::GetSelection() const
436 {
437 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(wxhWnd));
438 }
439
440 wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
441 {
442 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
443 }
444
445 wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
446 long& _cookie) const
447 {
448 // remember the last child returned in 'cookie'
449 _cookie = (long)TreeView_GetChild(wxhWnd, (HTREEITEM) (WXHTREEITEM)item);
450
451 return wxTreeItemId((WXHTREEITEM)_cookie);
452 }
453
454 wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
455 long& _cookie) const
456 {
457 wxTreeItemId l = wxTreeItemId((WXHTREEITEM)TreeView_GetNextSibling(wxhWnd,
458 (HTREEITEM)(WXHTREEITEM)_cookie));
459 _cookie = (long)l;
460
461 return l;
462 }
463
464 wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
465 {
466 // can this be done more efficiently?
467 long cookie;
468
469 wxTreeItemId childLast,
470 child = GetFirstChild(item, cookie);
471 while ( child.IsOk() )
472 {
473 childLast = child;
474 child = GetNextChild(item, cookie);
475 }
476
477 return childLast;
478 }
479
480 wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
481 {
482 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
483 }
484
485 wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
486 {
487 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
488 }
489
490 wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
491 {
492 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(wxhWnd));
493 }
494
495 wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
496 {
497 wxASSERT_MSG( IsVisible(item), "The item you call GetNextVisible() "
498 "for must be visible itself!");
499
500 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
501 }
502
503 wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
504 {
505 wxASSERT_MSG( IsVisible(item), "The item you call GetPrevVisible() "
506 "for must be visible itself!");
507
508 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
509 }
510
511 // ----------------------------------------------------------------------------
512 // Usual operations
513 // ----------------------------------------------------------------------------
514
515 wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
516 wxTreeItemId hInsertAfter,
517 const wxString& text,
518 int image, int selectedImage,
519 wxTreeItemData *data)
520 {
521 TV_INSERTSTRUCT tvIns;
522 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
523 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
524 UINT mask = 0;
525 if ( !text.IsEmpty() )
526 {
527 mask |= TVIF_TEXT;
528 tvIns.item.pszText = (char *)text.c_str(); // cast is ok
529 }
530
531 if ( image != -1 )
532 {
533 mask |= TVIF_IMAGE;
534 tvIns.item.iImage = image;
535
536 if ( selectedImage == -1 )
537 {
538 // take the same image for selected icon if not specified
539 selectedImage = image;
540 }
541 }
542
543 if ( selectedImage != -1 )
544 {
545 mask |= TVIF_SELECTEDIMAGE;
546 tvIns.item.iSelectedImage = selectedImage;
547 }
548
549 if ( data != NULL )
550 {
551 mask |= TVIF_PARAM;
552 tvIns.item.lParam = (LPARAM)data;
553 }
554
555 tvIns.item.mask = mask;
556
557 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(wxhWnd, &tvIns);
558 if ( id == 0 )
559 {
560 wxLogLastError("TreeView_InsertItem");
561 }
562
563 if ( data != NULL )
564 {
565 // associate the application tree item with Win32 tree item handle
566 data->SetId((WXHTREEITEM)id);
567 }
568
569 return wxTreeItemId((WXHTREEITEM)id);
570 }
571
572 // for compatibility only
573 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
574 const wxString& text,
575 int image, int selImage,
576 long insertAfter)
577 {
578 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
579 image, selImage, NULL);
580 }
581
582 wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
583 int image, int selectedImage,
584 wxTreeItemData *data)
585 {
586 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
587 text, image, selectedImage, data);
588 }
589
590 wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
591 const wxString& text,
592 int image, int selectedImage,
593 wxTreeItemData *data)
594 {
595 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
596 text, image, selectedImage, data);
597 }
598
599 wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
600 const wxTreeItemId& idPrevious,
601 const wxString& text,
602 int image, int selectedImage,
603 wxTreeItemData *data)
604 {
605 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
606 }
607
608 wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
609 const wxString& text,
610 int image, int selectedImage,
611 wxTreeItemData *data)
612 {
613 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
614 text, image, selectedImage, data);
615 }
616
617 void wxTreeCtrl::Delete(const wxTreeItemId& item)
618 {
619 if ( !TreeView_DeleteItem(wxhWnd, (HTREEITEM)(WXHTREEITEM)item) )
620 {
621 wxLogLastError("TreeView_DeleteItem");
622 }
623 }
624
625 // delete all children (but don't delete the item itself)
626 void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
627 {
628 long cookie;
629
630 wxArrayLong children;
631 wxTreeItemId child = GetFirstChild(item, cookie);
632 while ( child.IsOk() )
633 {
634 children.Add((long)(WXHTREEITEM)child);
635
636 child = GetNextChild(item, cookie);
637 }
638
639 size_t nCount = children.Count();
640 for ( size_t n = 0; n < nCount; n++ )
641 {
642 if ( !TreeView_DeleteItem(wxhWnd, (HTREEITEM)children[n]) )
643 {
644 wxLogLastError("TreeView_DeleteItem");
645 }
646 }
647 }
648
649 void wxTreeCtrl::DeleteAllItems()
650 {
651 if ( !TreeView_DeleteAllItems(wxhWnd) )
652 {
653 wxLogLastError("TreeView_DeleteAllItems");
654 }
655 }
656
657 void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
658 {
659 wxASSERT_MSG( flag == TVE_COLLAPSE || flag == TVE_COLLAPSERESET ||
660 flag == TVE_EXPAND || flag == TVE_TOGGLE,
661 "Unknown flag in wxTreeCtrl::DoExpand" );
662
663 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
664 // emulate them
665 if ( TreeView_Expand(wxhWnd, (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
666 {
667 wxTreeEvent event(wxEVT_NULL, m_windowId);
668 event.m_item = item;
669
670 bool isExpanded = IsExpanded(item);
671
672 event.SetEventObject(this);
673
674 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
675 event.SetEventType(g_events[isExpanded][TRUE]);
676 GetEventHandler()->ProcessEvent(event);
677
678 event.SetEventType(g_events[isExpanded][FALSE]);
679 GetEventHandler()->ProcessEvent(event);
680 }
681 else
682 {
683 // I wonder if it really ever happens...
684 wxLogDebug("TreeView_Expand: change didn't took place.");
685 }
686 }
687
688 void wxTreeCtrl::Expand(const wxTreeItemId& item)
689 {
690 DoExpand(item, TVE_EXPAND);
691 }
692
693 void wxTreeCtrl::Collapse(const wxTreeItemId& item)
694 {
695 DoExpand(item, TVE_COLLAPSE);
696 }
697
698 void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
699 {
700 DoExpand(item, TVE_COLLAPSERESET);
701 }
702
703 void wxTreeCtrl::Toggle(const wxTreeItemId& item)
704 {
705 DoExpand(item, TVE_TOGGLE);
706 }
707
708 void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
709 {
710 DoExpand(item, action);
711 }
712
713 void wxTreeCtrl::Unselect()
714 {
715 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
716 }
717
718 void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
719 {
720 if ( !TreeView_SelectItem(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
721 {
722 wxLogLastError("TreeView_SelectItem");
723 }
724 }
725
726 void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
727 {
728 // no error return
729 TreeView_EnsureVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
730 }
731
732 void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
733 {
734 if ( !TreeView_SelectSetFirstVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
735 {
736 wxLogLastError("TreeView_SelectSetFirstVisible");
737 }
738 }
739
740 wxTextCtrl* wxTreeCtrl::GetEditControl() const
741 {
742 return m_textCtrl;
743 }
744
745 void wxTreeCtrl::DeleteTextCtrl()
746 {
747 if ( m_textCtrl )
748 {
749 m_textCtrl->UnsubclassWin();
750 m_textCtrl->SetHWND(0);
751 delete m_textCtrl;
752 m_textCtrl = NULL;
753 }
754 }
755
756 wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
757 wxClassInfo* textControlClass)
758 {
759 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
760
761 HWND hWnd = (HWND) TreeView_EditLabel(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
762
763 wxCHECK_MSG( hWnd, NULL, "Can't edit tree ctrl label" );
764
765 DeleteTextCtrl();
766
767 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
768 m_textCtrl->SetHWND((WXHWND)hWnd);
769 m_textCtrl->SubclassWin((WXHWND)hWnd);
770
771 return m_textCtrl;
772 }
773
774 // End label editing, optionally cancelling the edit
775 void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
776 {
777 TreeView_EndEditLabelNow(wxhWnd, discardChanges);
778
779 DeleteTextCtrl();
780 }
781
782 wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
783 {
784 TV_HITTESTINFO hitTestInfo;
785 hitTestInfo.pt.x = (int)point.x;
786 hitTestInfo.pt.y = (int)point.y;
787
788 TreeView_HitTest(wxhWnd, &hitTestInfo);
789
790 flags = 0;
791
792 // avoid repetition
793 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
794 flags |= wxTREE_HITTEST_##flag
795
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);
807
808 #undef TRANSLATE_FLAG
809
810 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
811 }
812
813 bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
814 wxRect& rect,
815 bool textOnly) const
816 {
817 RECT rc;
818 if ( TreeView_GetItemRect(wxhWnd, (HTREEITEM)(WXHTREEITEM)item,
819 &rc, textOnly) )
820 {
821 rect = wxRect(wxPoint(rc.left, rc.top), wxPoint(rc.right, rc.bottom));
822
823 return TRUE;
824 }
825 else
826 {
827 // couldn't retrieve rect: for example, item isn't visible
828 return FALSE;
829 }
830 }
831
832 // ----------------------------------------------------------------------------
833 // sorting stuff
834 // ----------------------------------------------------------------------------
835
836 static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
837 wxTreeItemData *pItem2,
838 wxTreeCtrl *tree)
839 {
840 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
841 }
842
843 int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
844 const wxTreeItemId& item2)
845 {
846 return strcmp(GetItemText(item1), GetItemText(item2));
847 }
848
849 void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
850 {
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) )
855 {
856 TreeView_SortChildren(wxhWnd, (HTREEITEM)(WXHTREEITEM)item, 0);
857 }
858 else
859 {
860 TV_SORTCB tvSort;
861 tvSort.hParent = (HTREEITEM)(WXHTREEITEM)item;
862 tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
863 tvSort.lParam = (LPARAM)this;
864 TreeView_SortChildrenCB(wxhWnd, &tvSort, 0 /* reserved */);
865 }
866 }
867
868 // ----------------------------------------------------------------------------
869 // implementation
870 // ----------------------------------------------------------------------------
871
872 bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
873 {
874 if ( cmd == EN_UPDATE )
875 {
876 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
877 event.SetEventObject( this );
878 ProcessCommand(event);
879 }
880 else if ( cmd == EN_KILLFOCUS )
881 {
882 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
883 event.SetEventObject( this );
884 ProcessCommand(event);
885 }
886 else
887 {
888 // nothing done
889 return FALSE;
890 }
891
892 // command processed
893 return TRUE;
894 }
895
896 // process WM_NOTIFY Windows message
897 bool wxTreeCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam, WXLPARAM *result)
898 {
899 wxTreeEvent event(wxEVT_NULL, m_windowId);
900 wxEventType eventType = wxEVT_NULL;
901 NMHDR *hdr = (NMHDR *)lParam;
902
903 switch ( hdr->code )
904 {
905 case TVN_BEGINDRAG:
906 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
907 // fall through
908
909 case TVN_BEGINRDRAG:
910 {
911 if ( eventType == wxEVT_NULL )
912 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
913 //else: left drag, already set above
914
915 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
916
917 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
918 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
919 break;
920 }
921
922 case TVN_BEGINLABELEDIT:
923 {
924 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
925 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
926
927 event.m_item = (WXHTREEITEM) info->item.hItem;
928 break;
929 }
930
931 case TVN_DELETEITEM:
932 {
933 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
934 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
935
936 event.m_item = (WXHTREEITEM) tv->itemOld.hItem;
937 break;
938 }
939
940 case TVN_ENDLABELEDIT:
941 {
942 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
943 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
944
945 event.m_item = (WXHTREEITEM) info->item.hItem;
946 break;
947 }
948
949 case TVN_GETDISPINFO:
950 eventType = wxEVT_COMMAND_TREE_GET_INFO;
951 // fall through
952
953 case TVN_SETDISPINFO:
954 {
955 if ( eventType == wxEVT_NULL )
956 eventType = wxEVT_COMMAND_TREE_SET_INFO;
957 //else: get, already set above
958
959 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
960
961 event.m_item = (WXHTREEITEM) info->item.hItem;
962 break;
963 }
964
965 case TVN_ITEMEXPANDING:
966 event.m_code = FALSE;
967 // fall through
968
969 case TVN_ITEMEXPANDED:
970 {
971 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
972
973 bool expand = FALSE;
974 switch ( tv->action )
975 {
976 case TVE_EXPAND:
977 expand = TRUE;
978 break;
979
980 case TVE_COLLAPSE:
981 expand = FALSE;
982 break;
983
984 default:
985 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
986 "message", tv->action);
987 }
988
989 bool ing = (hdr->code == TVN_ITEMEXPANDING);
990 eventType = g_events[expand][ing];
991
992 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
993 break;
994 }
995
996 case TVN_KEYDOWN:
997 {
998 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
999 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
1000
1001 event.m_code = wxCharCodeMSWToWX(info->wVKey);
1002
1003 // a separate event for this case
1004 if ( info->wVKey == VK_SPACE || info->wVKey == VK_RETURN )
1005 {
1006 wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
1007 m_windowId);
1008 event2.SetEventObject(this);
1009
1010 GetEventHandler()->ProcessEvent(event2);
1011 }
1012 break;
1013 }
1014
1015 case TVN_SELCHANGED:
1016 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
1017 // fall through
1018
1019 case TVN_SELCHANGING:
1020 {
1021 if ( eventType == wxEVT_NULL )
1022 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
1023 //else: already set above
1024
1025 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1026
1027 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1028 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
1029 break;
1030 }
1031
1032 default:
1033 return wxControl::MSWNotify(wParam, lParam, result);
1034 }
1035
1036 event.SetEventObject(this);
1037 event.SetEventType(eventType);
1038
1039 bool processed = GetEventHandler()->ProcessEvent(event);
1040
1041 // post processing
1042 if ( hdr->code == TVN_DELETEITEM )
1043 {
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
1050 }
1051
1052 *result = !event.IsAllowed();
1053
1054 return processed;
1055 }
1056
1057 // ----------------------------------------------------------------------------
1058 // Tree event
1059 // ----------------------------------------------------------------------------
1060
1061 IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
1062
1063 wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
1064 : wxNotifyEvent(commandType, id)
1065 {
1066 m_code = 0;
1067 m_itemOld = 0;
1068 }
1069
1070 #endif // __WIN95__
1071