]> git.saurik.com Git - wxWidgets.git/blame_incremental - src/msw/treectrl.cpp
Added dummy OnIdle to wxWindow in wxGTK; doc tweaks
[wxWidgets.git] / src / msw / treectrl.cpp
... / ...
CommitLineData
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
77struct 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
104static 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
118void wxTreeCtrl::Init()
119{
120 m_imageListNormal = NULL;
121 m_imageListState = NULL;
122 m_textCtrl = NULL;
123}
124
125bool 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
188wxTreeCtrl::~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
202bool 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
214void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
215{
216 if ( TreeView_SetItem(wxhWnd, tvItem) == -1 )
217 {
218 wxLogLastError("TreeView_SetItem");
219 }
220}
221
222size_t wxTreeCtrl::GetCount() const
223{
224 return (size_t)TreeView_GetCount(wxhWnd);
225}
226
227unsigned int wxTreeCtrl::GetIndent() const
228{
229 return TreeView_GetIndent(wxhWnd);
230}
231
232void wxTreeCtrl::SetIndent(unsigned int indent)
233{
234 TreeView_SetIndent(wxhWnd, indent);
235}
236
237wxImageList *wxTreeCtrl::GetImageList() const
238{
239 return m_imageListNormal;
240}
241
242wxImageList *wxTreeCtrl::GetStateImageList() const
243{
244 return m_imageListNormal;
245}
246
247void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
248{
249 // no error return
250 TreeView_SetImageList(wxhWnd,
251 imageList ? imageList->GetHIMAGELIST() : 0,
252 which);
253}
254
255void wxTreeCtrl::SetImageList(wxImageList *imageList)
256{
257 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
258}
259
260void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
261{
262 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
263}
264
265size_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
294wxString 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
310void 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
317int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
318{
319 wxTreeViewItem tvItem(item, TVIF_IMAGE);
320 DoGetItem(&tvItem);
321
322 return tvItem.iImage;
323}
324
325void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
326{
327 wxTreeViewItem tvItem(item, TVIF_IMAGE);
328 tvItem.iImage = image;
329 DoSetItem(&tvItem);
330}
331
332int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
333{
334 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
335 DoGetItem(&tvItem);
336
337 return tvItem.iSelectedImage;
338}
339
340void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
341{
342 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
343 tvItem.iSelectedImage = image;
344 DoSetItem(&tvItem);
345}
346
347wxTreeItemData *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
358void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
359{
360 wxTreeViewItem tvItem(item, TVIF_PARAM);
361 tvItem.lParam = (LPARAM)data;
362 DoSetItem(&tvItem);
363}
364
365void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
366{
367 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
368 tvItem.cChildren = (int)has;
369 DoSetItem(&tvItem);
370}
371
372void 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
383bool 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
391bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
392{
393 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
394 DoGetItem(&tvItem);
395
396 return tvItem.cChildren != 0;
397}
398
399bool 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
410bool 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
418bool 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
430wxTreeItemId wxTreeCtrl::GetRootItem() const
431{
432 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(wxhWnd));
433}
434
435wxTreeItemId wxTreeCtrl::GetSelection() const
436{
437 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(wxhWnd));
438}
439
440wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
441{
442 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
443}
444
445wxTreeItemId 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
454wxTreeItemId 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
464wxTreeItemId 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
480wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
481{
482 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
483}
484
485wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
486{
487 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
488}
489
490wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
491{
492 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(wxhWnd));
493}
494
495wxTreeItemId 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
503wxTreeItemId 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
515wxTreeItemId 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
573wxTreeItemId 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
582wxTreeItemId 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
590wxTreeItemId 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
599wxTreeItemId 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
608wxTreeItemId 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
617void 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)
626void 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
649void wxTreeCtrl::DeleteAllItems()
650{
651 if ( !TreeView_DeleteAllItems(wxhWnd) )
652 {
653 wxLogLastError("TreeView_DeleteAllItems");
654 }
655}
656
657void 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
688void wxTreeCtrl::Expand(const wxTreeItemId& item)
689{
690 DoExpand(item, TVE_EXPAND);
691}
692
693void wxTreeCtrl::Collapse(const wxTreeItemId& item)
694{
695 DoExpand(item, TVE_COLLAPSE);
696}
697
698void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
699{
700 DoExpand(item, TVE_COLLAPSERESET);
701}
702
703void wxTreeCtrl::Toggle(const wxTreeItemId& item)
704{
705 DoExpand(item, TVE_TOGGLE);
706}
707
708void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
709{
710 DoExpand(item, action);
711}
712
713void wxTreeCtrl::Unselect()
714{
715 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
716}
717
718void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
719{
720 if ( !TreeView_SelectItem(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
721 {
722 wxLogLastError("TreeView_SelectItem");
723 }
724}
725
726void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
727{
728 // no error return
729 TreeView_EnsureVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
730}
731
732void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
733{
734 if ( !TreeView_SelectSetFirstVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
735 {
736 wxLogLastError("TreeView_SelectSetFirstVisible");
737 }
738}
739
740wxTextCtrl* wxTreeCtrl::GetEditControl() const
741{
742 return m_textCtrl;
743}
744
745void 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
756wxTextCtrl* 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
775void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
776{
777 TreeView_EndEditLabelNow(wxhWnd, discardChanges);
778
779 DeleteTextCtrl();
780}
781
782wxTreeItemId 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
813bool 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
836static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
837 wxTreeItemData *pItem2,
838 wxTreeCtrl *tree)
839{
840 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
841}
842
843int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
844 const wxTreeItemId& item2)
845{
846 return strcmp(GetItemText(item1), GetItemText(item2));
847}
848
849void 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
872bool 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
897bool 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
1061IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
1062
1063wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
1064 : wxNotifyEvent(commandType, id)
1065{
1066 m_code = 0;
1067 m_itemOld = 0;
1068}
1069
1070#endif // __WIN95__
1071