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