]> git.saurik.com Git - wxWidgets.git/blame - src/msw/treectrl.cpp
fixed somebody's poorly done StreamSize-->GetSize transition
[wxWidgets.git] / src / msw / treectrl.cpp
CommitLineData
b823f5a1
JS
1/////////////////////////////////////////////////////////////////////////////
2// Name: treectrl.cpp
3// Purpose: wxTreeCtrl
4// Author: Julian Smart
08b7c251 5// Modified by: Vadim Zeitlin to be less MSW-specific on 10.10.98
b823f5a1
JS
6// Created: 1997
7// RCS-ID: $Id$
8// Copyright: (c) Julian Smart
08b7c251 9// Licence: wxWindows licence
b823f5a1 10/////////////////////////////////////////////////////////////////////////////
2bda0e17 11
08b7c251
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
2bda0e17 19#ifdef __GNUG__
08b7c251 20 #pragma implementation "treectrl.h"
2bda0e17
KB
21#endif
22
23// For compilers that support precompilation, includes "wx.h".
24#include "wx/wxprec.h"
25
26#ifdef __BORLANDC__
08b7c251 27 #pragma hdrstop
2bda0e17
KB
28#endif
29
0c589ad0
BM
30#include "wx/window.h"
31#include "wx/msw/private.h"
32
0c589ad0
BM
33// Mingw32 is a bit mental even though this is done in winundef
34#ifdef GetFirstChild
d220ae32 35 #undef GetFirstChild
0c589ad0 36#endif
d220ae32 37
0c589ad0 38#ifdef GetNextSibling
d220ae32 39 #undef GetNextSibling
2bda0e17
KB
40#endif
41
2bda0e17
KB
42#if defined(__WIN95__)
43
08b7c251 44#include "wx/log.h"
ce3ed50d 45#include "wx/dynarray.h"
08b7c251 46#include "wx/imaglist.h"
53f69f7a 47#include "wx/treectrl.h"
08b7c251 48
9a05fd8d 49#ifdef __GNUWIN32__
65fd5cb0 50#ifndef wxUSE_NORLANDER_HEADERS
9a05fd8d
JS
51#include "wx/msw/gnuwin32/extra.h"
52#endif
65fd5cb0 53#endif
9a05fd8d 54
65fd5cb0 55#if (defined(__WIN95__) && !defined(__GNUWIN32__)) || defined(__TWIN32__) || defined(wxUSE_NORLANDER_HEADERS)
08b7c251 56 #include <commctrl.h>
2bda0e17
KB
57#endif
58
59// Bug in headers, sometimes
60#ifndef TVIS_FOCUSED
08b7c251 61 #define TVIS_FOCUSED 0x0001
2bda0e17
KB
62#endif
63
08b7c251
VZ
64// ----------------------------------------------------------------------------
65// private classes
66// ----------------------------------------------------------------------------
2bda0e17 67
08b7c251
VZ
68// a convenient wrapper around TV_ITEM struct which adds a ctor
69struct wxTreeViewItem : public TV_ITEM
70{
9dfbf520
VZ
71 wxTreeViewItem(const wxTreeItemId& item, // the item handle
72 UINT mask_, // fields which are valid
73 UINT stateMask_ = 0) // for TVIF_STATE only
08b7c251 74 {
9dfbf520
VZ
75 // hItem member is always valid
76 mask = mask_ | TVIF_HANDLE;
08b7c251 77 stateMask = stateMask_;
06e38c8e 78 hItem = (HTREEITEM) (WXHTREEITEM) item;
08b7c251
VZ
79 }
80};
2bda0e17 81
9dfbf520
VZ
82// a class which encapsulates the tree traversal logic: it vists all (unless
83// OnVisit() returns FALSE) items under the given one
84class wxTreeTraversal
85{
86public:
87 wxTreeTraversal(const wxTreeCtrl *tree)
88 {
89 m_tree = tree;
90 }
91
92 // do traverse the tree: visit all items (recursively by default) under the
93 // given one; return TRUE if all items were traversed or FALSE if the
94 // traversal was aborted because OnVisit returned FALSE
95 bool DoTraverse(const wxTreeItemId& root, bool recursively = TRUE);
96
97 // override this function to do whatever is needed for each item, return
98 // FALSE to stop traversing
99 virtual bool OnVisit(const wxTreeItemId& item) = 0;
100
101protected:
102 const wxTreeCtrl *GetTree() const { return m_tree; }
103
104private:
105 bool Traverse(const wxTreeItemId& root, bool recursively);
106
107 const wxTreeCtrl *m_tree;
108};
109
08b7c251
VZ
110// ----------------------------------------------------------------------------
111// macros
112// ----------------------------------------------------------------------------
113
114#if !USE_SHARED_LIBRARY
115 IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxControl)
2bda0e17
KB
116#endif
117
08b7c251
VZ
118// ----------------------------------------------------------------------------
119// variables
120// ----------------------------------------------------------------------------
121
122// handy table for sending events
123static const wxEventType g_events[2][2] =
2bda0e17 124{
08b7c251
VZ
125 { wxEVT_COMMAND_TREE_ITEM_COLLAPSED, wxEVT_COMMAND_TREE_ITEM_COLLAPSING },
126 { wxEVT_COMMAND_TREE_ITEM_EXPANDED, wxEVT_COMMAND_TREE_ITEM_EXPANDING }
127};
128
129// ============================================================================
130// implementation
131// ============================================================================
132
9dfbf520
VZ
133// ----------------------------------------------------------------------------
134// tree traversal
135// ----------------------------------------------------------------------------
136
137bool wxTreeTraversal::DoTraverse(const wxTreeItemId& root, bool recursively)
138{
139 if ( !OnVisit(root) )
140 return FALSE;
141
142 return Traverse(root, recursively);
143}
144
145bool wxTreeTraversal::Traverse(const wxTreeItemId& root, bool recursively)
146{
147 long cookie;
148 wxTreeItemId child = m_tree->GetFirstChild(root, cookie);
149 while ( child.IsOk() )
150 {
151 // depth first traversal
152 if ( recursively && !Traverse(child, TRUE) )
153 return FALSE;
154
155 if ( !OnVisit(child) )
156 return FALSE;
157
158 child = m_tree->GetNextChild(root, cookie);
159 }
160
161 return TRUE;
162}
163
08b7c251
VZ
164// ----------------------------------------------------------------------------
165// construction and destruction
166// ----------------------------------------------------------------------------
167
168void wxTreeCtrl::Init()
169{
170 m_imageListNormal = NULL;
171 m_imageListState = NULL;
172 m_textCtrl = NULL;
2bda0e17
KB
173}
174
9dfbf520
VZ
175bool wxTreeCtrl::Create(wxWindow *parent,
176 wxWindowID id,
177 const wxPoint& pos,
178 const wxSize& size,
179 long style,
180 const wxValidator& validator,
08b7c251 181 const wxString& name)
2bda0e17 182{
08b7c251 183 Init();
2bda0e17 184
9dfbf520
VZ
185 if ( !CreateControl(parent, id, pos, size, style, validator, name) )
186 return FALSE;
2bda0e17 187
5ea47806
VZ
188 DWORD wstyle = WS_VISIBLE | WS_CHILD | WS_TABSTOP |
189 TVS_HASLINES | TVS_SHOWSELALWAYS;
2bda0e17 190
08b7c251
VZ
191 if ( m_windowStyle & wxTR_HAS_BUTTONS )
192 wstyle |= TVS_HASBUTTONS;
2bda0e17 193
08b7c251
VZ
194 if ( m_windowStyle & wxTR_EDIT_LABELS )
195 wstyle |= TVS_EDITLABELS;
2bda0e17 196
08b7c251
VZ
197 if ( m_windowStyle & wxTR_LINES_AT_ROOT )
198 wstyle |= TVS_LINESATROOT;
2bda0e17 199
65fd5cb0 200#if !defined( __GNUWIN32__ ) && !defined(wxUSE_NORLANDER_HEADERS)
9dfbf520
VZ
201 // we emulate the multiple selection tree controls by using checkboxes: set
202 // up the image list we need for this if we do have multiple selections
203 if ( m_windowStyle & wxTR_MULTIPLE )
10fcf31a 204 wstyle |= TVS_CHECKBOXES;
2899e223 205#endif
9dfbf520 206
08b7c251 207 // Create the tree control.
9dfbf520
VZ
208 if ( !MSWCreateControl(WC_TREEVIEW, wstyle) )
209 return FALSE;
210
10fcf31a
VZ
211 // the treectrl with any other background looks ugly because the items
212 // background is white anyhow
213 SetBackgroundColour(*wxWHITE);
214
9dfbf520
VZ
215 // VZ: this is some experimental code which may be used to get the
216 // TVS_CHECKBOXES style functionality for comctl32.dll < 4.71.
217 // AFAIK, the standard DLL does about the same thing anyhow.
218#if 0
219 if ( m_windowStyle & wxTR_MULTIPLE )
220 {
221 wxBitmap bmp;
222
223 // create the DC compatible with the current screen
224 HDC hdcMem = CreateCompatibleDC(NULL);
225
226 // create a mono bitmap of the standard size
227 int x = GetSystemMetrics(SM_CXMENUCHECK);
228 int y = GetSystemMetrics(SM_CYMENUCHECK);
229 wxImageList imagelistCheckboxes(x, y, FALSE, 2);
230 HBITMAP hbmpCheck = CreateBitmap(x, y, // bitmap size
231 1, // # of color planes
232 1, // # bits needed for one pixel
233 0); // array containing colour data
234 SelectObject(hdcMem, hbmpCheck);
235
236 // then draw a check mark into it
237 RECT rect = { 0, 0, x, y };
238 if ( !::DrawFrameControl(hdcMem, &rect,
239 DFC_BUTTON,
240 DFCS_BUTTONCHECK | DFCS_CHECKED) )
241 {
242 wxLogLastError(_T("DrawFrameControl(check)"));
243 }
244
245 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
246 imagelistCheckboxes.Add(bmp);
247
248 if ( !::DrawFrameControl(hdcMem, &rect,
249 DFC_BUTTON,
250 DFCS_BUTTONCHECK) )
251 {
252 wxLogLastError(_T("DrawFrameControl(uncheck)"));
253 }
254
255 bmp.SetHBITMAP((WXHBITMAP)hbmpCheck);
256 imagelistCheckboxes.Add(bmp);
257
258 // clean up
259 ::DeleteDC(hdcMem);
260
261 // set the imagelist
262 SetStateImageList(&imagelistCheckboxes);
263 }
264#endif // 0
265
266 SetSize(pos.x, pos.y, size.x, size.y);
2bda0e17 267
08b7c251 268 return TRUE;
2bda0e17
KB
269}
270
08b7c251 271wxTreeCtrl::~wxTreeCtrl()
2bda0e17 272{
08b7c251 273 DeleteTextCtrl();
2bda0e17 274
08b7c251
VZ
275 // delete user data to prevent memory leaks
276 DeleteAllItems();
2bda0e17
KB
277}
278
08b7c251
VZ
279// ----------------------------------------------------------------------------
280// accessors
281// ----------------------------------------------------------------------------
2bda0e17 282
08b7c251 283// simple wrappers which add error checking in debug mode
2bda0e17 284
08b7c251 285bool wxTreeCtrl::DoGetItem(wxTreeViewItem* tvItem) const
2bda0e17 286{
d220ae32 287 if ( !TreeView_GetItem(GetHwnd(), tvItem) )
2bda0e17 288 {
08b7c251
VZ
289 wxLogLastError("TreeView_GetItem");
290
291 return FALSE;
292 }
293
294 return TRUE;
2bda0e17
KB
295}
296
08b7c251 297void wxTreeCtrl::DoSetItem(wxTreeViewItem* tvItem)
2bda0e17 298{
d220ae32 299 if ( TreeView_SetItem(GetHwnd(), tvItem) == -1 )
2bda0e17 300 {
08b7c251
VZ
301 wxLogLastError("TreeView_SetItem");
302 }
2bda0e17
KB
303}
304
08b7c251 305size_t wxTreeCtrl::GetCount() const
2bda0e17 306{
d220ae32 307 return (size_t)TreeView_GetCount(GetHwnd());
2bda0e17
KB
308}
309
08b7c251 310unsigned int wxTreeCtrl::GetIndent() const
2bda0e17 311{
d220ae32 312 return TreeView_GetIndent(GetHwnd());
2bda0e17
KB
313}
314
08b7c251 315void wxTreeCtrl::SetIndent(unsigned int indent)
2bda0e17 316{
d220ae32 317 TreeView_SetIndent(GetHwnd(), indent);
2bda0e17
KB
318}
319
08b7c251 320wxImageList *wxTreeCtrl::GetImageList() const
2bda0e17 321{
08b7c251 322 return m_imageListNormal;
2bda0e17
KB
323}
324
08b7c251 325wxImageList *wxTreeCtrl::GetStateImageList() const
2bda0e17 326{
08b7c251 327 return m_imageListNormal;
2bda0e17
KB
328}
329
08b7c251 330void wxTreeCtrl::SetAnyImageList(wxImageList *imageList, int which)
2bda0e17 331{
08b7c251 332 // no error return
d220ae32 333 TreeView_SetImageList(GetHwnd(),
08b7c251
VZ
334 imageList ? imageList->GetHIMAGELIST() : 0,
335 which);
2bda0e17
KB
336}
337
08b7c251 338void wxTreeCtrl::SetImageList(wxImageList *imageList)
2bda0e17 339{
08b7c251 340 SetAnyImageList(m_imageListNormal = imageList, TVSIL_NORMAL);
2bda0e17
KB
341}
342
08b7c251 343void wxTreeCtrl::SetStateImageList(wxImageList *imageList)
2bda0e17 344{
08b7c251 345 SetAnyImageList(m_imageListState = imageList, TVSIL_STATE);
2bda0e17
KB
346}
347
9dfbf520
VZ
348size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item,
349 bool recursively) const
23fd5130 350{
9dfbf520 351 class TraverseCounter : public wxTreeTraversal
23fd5130 352 {
9dfbf520
VZ
353 public:
354 TraverseCounter(const wxTreeCtrl *tree,
355 const wxTreeItemId& root,
356 bool recursively)
357 : wxTreeTraversal(tree)
358 {
359 m_count = 0;
360
361 DoTraverse(root, recursively);
362 }
363
364 virtual bool OnVisit(const wxTreeItemId& item)
23fd5130 365 {
9dfbf520
VZ
366 m_count++;
367
368 return TRUE;
23fd5130
VZ
369 }
370
9dfbf520 371 size_t GetCount() const { return m_count; }
23fd5130 372
9dfbf520
VZ
373 private:
374 size_t m_count;
375 } counter(this, item, recursively);
23fd5130 376
9dfbf520 377 return counter.GetCount();
23fd5130
VZ
378}
379
08b7c251
VZ
380// ----------------------------------------------------------------------------
381// Item access
382// ----------------------------------------------------------------------------
383
384wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
2bda0e17 385{
837e5743 386 wxChar buf[512]; // the size is arbitrary...
02ce7b72 387
08b7c251
VZ
388 wxTreeViewItem tvItem(item, TVIF_TEXT);
389 tvItem.pszText = buf;
390 tvItem.cchTextMax = WXSIZEOF(buf);
391 if ( !DoGetItem(&tvItem) )
392 {
393 // don't return some garbage which was on stack, but an empty string
837e5743 394 buf[0] = _T('\0');
08b7c251 395 }
2bda0e17 396
08b7c251
VZ
397 return wxString(buf);
398}
2bda0e17 399
08b7c251
VZ
400void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
401{
402 wxTreeViewItem tvItem(item, TVIF_TEXT);
837e5743 403 tvItem.pszText = (wxChar *)text.c_str(); // conversion is ok
08b7c251
VZ
404 DoSetItem(&tvItem);
405}
2bda0e17 406
9dfbf520
VZ
407void wxTreeCtrl::DoSetItemImages(const wxTreeItemId& item,
408 int image,
409 int imageSel)
410{
411 wxTreeViewItem tvItem(item, TVIF_IMAGE | TVIF_SELECTEDIMAGE);
412 tvItem.iSelectedImage = imageSel;
413 tvItem.iImage = image;
414 DoSetItem(&tvItem);
415}
416
08b7c251
VZ
417int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
418{
419 wxTreeViewItem tvItem(item, TVIF_IMAGE);
420 DoGetItem(&tvItem);
2bda0e17 421
08b7c251
VZ
422 return tvItem.iImage;
423}
2bda0e17 424
08b7c251
VZ
425void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
426{
9dfbf520
VZ
427 // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
428 // change both normal and selected image - otherwise the change simply
429 // doesn't take place!
430 DoSetItemImages(item, image, GetItemSelectedImage(item));
08b7c251 431}
2bda0e17 432
08b7c251
VZ
433int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
434{
435 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
436 DoGetItem(&tvItem);
2bda0e17 437
08b7c251 438 return tvItem.iSelectedImage;
2bda0e17
KB
439}
440
08b7c251 441void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
2bda0e17 442{
9dfbf520
VZ
443 // NB: at least in version 5.00.0518.9 of comctl32.dll we need to always
444 // change both normal and selected image - otherwise the change simply
445 // doesn't take place!
446 DoSetItemImages(item, GetItemImage(item), image);
2bda0e17
KB
447}
448
08b7c251 449wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
2bda0e17 450{
08b7c251
VZ
451 wxTreeViewItem tvItem(item, TVIF_PARAM);
452 if ( !DoGetItem(&tvItem) )
453 {
454 return NULL;
455 }
2bda0e17 456
3a5a2f56 457 return (wxTreeItemData *)tvItem.lParam;
2bda0e17
KB
458}
459
08b7c251 460void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
2bda0e17 461{
08b7c251
VZ
462 wxTreeViewItem tvItem(item, TVIF_PARAM);
463 tvItem.lParam = (LPARAM)data;
464 DoSetItem(&tvItem);
465}
2bda0e17 466
3a5a2f56
VZ
467void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
468{
469 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
470 tvItem.cChildren = (int)has;
471 DoSetItem(&tvItem);
472}
473
add28c55
VZ
474void wxTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
475{
476 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
477 tvItem.state = bold ? TVIS_BOLD : 0;
478 DoSetItem(&tvItem);
479}
480
58a8ab88
JS
481void wxTreeCtrl::SetItemDropHighlight(const wxTreeItemId& item, bool highlight)
482{
483 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_DROPHILITED);
484 tvItem.state = highlight ? TVIS_DROPHILITED : 0;
485 DoSetItem(&tvItem);
486}
487
08b7c251
VZ
488// ----------------------------------------------------------------------------
489// Item status
490// ----------------------------------------------------------------------------
2bda0e17 491
08b7c251
VZ
492bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
493{
add28c55 494 // Bug in Gnu-Win32 headers, so don't use the macro TreeView_GetItemRect
08b7c251 495 RECT rect;
d220ae32 496 return SendMessage(GetHwnd(), TVM_GETITEMRECT, FALSE, (LPARAM)&rect) != 0;
06e38c8e 497
2bda0e17
KB
498}
499
08b7c251 500bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
2bda0e17 501{
08b7c251
VZ
502 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
503 DoGetItem(&tvItem);
2bda0e17 504
08b7c251 505 return tvItem.cChildren != 0;
2bda0e17
KB
506}
507
08b7c251 508bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
2bda0e17 509{
08b7c251
VZ
510 // probably not a good idea to put it here
511 //wxASSERT( ItemHasChildren(item) );
2bda0e17 512
08b7c251
VZ
513 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
514 DoGetItem(&tvItem);
2bda0e17 515
08b7c251 516 return (tvItem.state & TVIS_EXPANDED) != 0;
2bda0e17
KB
517}
518
08b7c251 519bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
2bda0e17 520{
08b7c251
VZ
521 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
522 DoGetItem(&tvItem);
2bda0e17 523
08b7c251 524 return (tvItem.state & TVIS_SELECTED) != 0;
2bda0e17
KB
525}
526
add28c55
VZ
527bool wxTreeCtrl::IsBold(const wxTreeItemId& item) const
528{
529 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_BOLD);
530 DoGetItem(&tvItem);
531
532 return (tvItem.state & TVIS_BOLD) != 0;
533}
534
08b7c251
VZ
535// ----------------------------------------------------------------------------
536// navigation
537// ----------------------------------------------------------------------------
2bda0e17 538
08b7c251
VZ
539wxTreeItemId wxTreeCtrl::GetRootItem() const
540{
d220ae32 541 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(GetHwnd()));
08b7c251 542}
2bda0e17 543
08b7c251
VZ
544wxTreeItemId wxTreeCtrl::GetSelection() const
545{
9dfbf520
VZ
546 wxCHECK_MSG( !(m_windowStyle & wxTR_MULTIPLE), (WXHTREEITEM)0,
547 _T("this only works with single selection controls") );
548
d220ae32 549 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(GetHwnd()));
2bda0e17
KB
550}
551
08b7c251 552wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
2bda0e17 553{
d220ae32 554 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 555}
2bda0e17 556
08b7c251 557wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
06e38c8e 558 long& _cookie) const
08b7c251
VZ
559{
560 // remember the last child returned in 'cookie'
d220ae32 561 _cookie = (long)TreeView_GetChild(GetHwnd(), (HTREEITEM) (WXHTREEITEM)item);
2bda0e17 562
06e38c8e 563 return wxTreeItemId((WXHTREEITEM)_cookie);
2bda0e17
KB
564}
565
08b7c251 566wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
06e38c8e 567 long& _cookie) const
2bda0e17 568{
d220ae32 569 wxTreeItemId l = wxTreeItemId((WXHTREEITEM)TreeView_GetNextSibling(GetHwnd(),
23fd5130
VZ
570 (HTREEITEM)(WXHTREEITEM)_cookie));
571 _cookie = (long)l;
572
2e5dddb0 573 return l;
08b7c251 574}
2bda0e17 575
978f38c2
VZ
576wxTreeItemId wxTreeCtrl::GetLastChild(const wxTreeItemId& item) const
577{
578 // can this be done more efficiently?
579 long cookie;
580
581 wxTreeItemId childLast,
2165ad93 582 child = GetFirstChild(item, cookie);
978f38c2
VZ
583 while ( child.IsOk() )
584 {
585 childLast = child;
2165ad93 586 child = GetNextChild(item, cookie);
978f38c2
VZ
587 }
588
589 return childLast;
590}
591
08b7c251
VZ
592wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
593{
d220ae32 594 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
595}
596
08b7c251 597wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
2bda0e17 598{
d220ae32 599 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
600}
601
08b7c251 602wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
2bda0e17 603{
d220ae32 604 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(GetHwnd()));
2bda0e17
KB
605}
606
08b7c251 607wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
2bda0e17 608{
837e5743
OK
609 wxASSERT_MSG( IsVisible(item), _T("The item you call GetNextVisible() "
610 "for must be visible itself!"));
02ce7b72 611
d220ae32 612 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 613}
02ce7b72 614
08b7c251
VZ
615wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
616{
837e5743
OK
617 wxASSERT_MSG( IsVisible(item), _T("The item you call GetPrevVisible() "
618 "for must be visible itself!"));
02ce7b72 619
d220ae32 620 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item));
08b7c251 621}
02ce7b72 622
9dfbf520
VZ
623// ----------------------------------------------------------------------------
624// multiple selections emulation
625// ----------------------------------------------------------------------------
626
627bool wxTreeCtrl::IsItemChecked(const wxTreeItemId& item) const
628{
629 // receive the desired information.
630 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
631 DoGetItem(&tvItem);
632
633 // state image indices are 1 based
634 return ((tvItem.state >> 12) - 1) == 1;
635}
636
637void wxTreeCtrl::SetItemCheck(const wxTreeItemId& item, bool check)
638{
639 // receive the desired information.
640 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_STATEIMAGEMASK);
641
642 // state images are one-based
643 tvItem.state = (check ? 2 : 1) << 12;
644
645 DoSetItem(&tvItem);
646}
647
648size_t wxTreeCtrl::GetSelections(wxArrayTreeItemIds& selections) const
649{
650 class TraverseSelections : public wxTreeTraversal
651 {
652 public:
653 TraverseSelections(const wxTreeCtrl *tree,
654 wxArrayTreeItemIds& selections)
655 : wxTreeTraversal(tree), m_selections(selections)
656 {
657 m_selections.Empty();
658
659 DoTraverse(tree->GetRootItem());
660 }
661
662 virtual bool OnVisit(const wxTreeItemId& item)
663 {
664 if ( GetTree()->IsItemChecked(item) )
665 {
666 m_selections.Add(item);
667 }
668
669 return TRUE;
670 }
671
672 private:
673 wxArrayTreeItemIds& m_selections;
674 } selector(this, selections);
675
676 return selections.GetCount();
677}
678
08b7c251
VZ
679// ----------------------------------------------------------------------------
680// Usual operations
681// ----------------------------------------------------------------------------
02ce7b72 682
08b7c251
VZ
683wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
684 wxTreeItemId hInsertAfter,
685 const wxString& text,
686 int image, int selectedImage,
687 wxTreeItemData *data)
688{
689 TV_INSERTSTRUCT tvIns;
06e38c8e
JS
690 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
691 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
58a8ab88
JS
692
693 // This is how we insert the item as the first child: supply a NULL hInsertAfter
694 if (tvIns.hInsertAfter == (HTREEITEM) 0)
695 {
696 tvIns.hInsertAfter = TVI_FIRST;
697 }
698
08b7c251
VZ
699 UINT mask = 0;
700 if ( !text.IsEmpty() )
701 {
702 mask |= TVIF_TEXT;
837e5743 703 tvIns.item.pszText = (wxChar *)text.c_str(); // cast is ok
08b7c251 704 }
02ce7b72 705
08b7c251
VZ
706 if ( image != -1 )
707 {
708 mask |= TVIF_IMAGE;
709 tvIns.item.iImage = image;
3a5a2f56 710
6b037754 711 if ( selectedImage == -1 )
3a5a2f56
VZ
712 {
713 // take the same image for selected icon if not specified
714 selectedImage = image;
715 }
08b7c251 716 }
02ce7b72 717
08b7c251
VZ
718 if ( selectedImage != -1 )
719 {
720 mask |= TVIF_SELECTEDIMAGE;
721 tvIns.item.iSelectedImage = selectedImage;
722 }
02ce7b72 723
08b7c251
VZ
724 if ( data != NULL )
725 {
726 mask |= TVIF_PARAM;
727 tvIns.item.lParam = (LPARAM)data;
728 }
02ce7b72 729
08b7c251 730 tvIns.item.mask = mask;
02ce7b72 731
d220ae32 732 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(GetHwnd(), &tvIns);
08b7c251
VZ
733 if ( id == 0 )
734 {
735 wxLogLastError("TreeView_InsertItem");
736 }
02ce7b72 737
fd3f686c
VZ
738 if ( data != NULL )
739 {
740 // associate the application tree item with Win32 tree item handle
741 data->SetId((WXHTREEITEM)id);
742 }
743
06e38c8e 744 return wxTreeItemId((WXHTREEITEM)id);
2bda0e17
KB
745}
746
08b7c251
VZ
747// for compatibility only
748wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
749 const wxString& text,
750 int image, int selImage,
751 long insertAfter)
2bda0e17 752{
06e38c8e 753 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
08b7c251 754 image, selImage, NULL);
2bda0e17
KB
755}
756
08b7c251
VZ
757wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
758 int image, int selectedImage,
759 wxTreeItemData *data)
2bda0e17 760{
06e38c8e 761 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
08b7c251 762 text, image, selectedImage, data);
2bda0e17
KB
763}
764
08b7c251
VZ
765wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
766 const wxString& text,
767 int image, int selectedImage,
768 wxTreeItemData *data)
2bda0e17 769{
06e38c8e 770 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
08b7c251 771 text, image, selectedImage, data);
2bda0e17
KB
772}
773
08b7c251
VZ
774wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
775 const wxTreeItemId& idPrevious,
776 const wxString& text,
777 int image, int selectedImage,
778 wxTreeItemData *data)
2bda0e17 779{
08b7c251 780 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
2bda0e17
KB
781}
782
08b7c251
VZ
783wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
784 const wxString& text,
785 int image, int selectedImage,
786 wxTreeItemData *data)
2bda0e17 787{
06e38c8e 788 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
08b7c251 789 text, image, selectedImage, data);
2bda0e17
KB
790}
791
08b7c251 792void wxTreeCtrl::Delete(const wxTreeItemId& item)
2bda0e17 793{
d220ae32 794 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item) )
bbcdf8bc 795 {
08b7c251 796 wxLogLastError("TreeView_DeleteItem");
bbcdf8bc 797 }
bbcdf8bc
JS
798}
799
23fd5130
VZ
800// delete all children (but don't delete the item itself)
801void wxTreeCtrl::DeleteChildren(const wxTreeItemId& item)
802{
803 long cookie;
804
805 wxArrayLong children;
806 wxTreeItemId child = GetFirstChild(item, cookie);
807 while ( child.IsOk() )
808 {
809 children.Add((long)(WXHTREEITEM)child);
810
811 child = GetNextChild(item, cookie);
812 }
813
814 size_t nCount = children.Count();
815 for ( size_t n = 0; n < nCount; n++ )
816 {
d220ae32 817 if ( !TreeView_DeleteItem(GetHwnd(), (HTREEITEM)children[n]) )
23fd5130
VZ
818 {
819 wxLogLastError("TreeView_DeleteItem");
820 }
821 }
822}
823
08b7c251 824void wxTreeCtrl::DeleteAllItems()
bbcdf8bc 825{
d220ae32 826 if ( !TreeView_DeleteAllItems(GetHwnd()) )
bbcdf8bc 827 {
08b7c251 828 wxLogLastError("TreeView_DeleteAllItems");
bbcdf8bc 829 }
2bda0e17
KB
830}
831
08b7c251 832void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
2bda0e17 833{
dd3646fd
VZ
834 wxASSERT_MSG( flag == TVE_COLLAPSE ||
835 flag == (TVE_COLLAPSE | TVE_COLLAPSERESET) ||
836 flag == TVE_EXPAND ||
837 flag == TVE_TOGGLE,
837e5743 838 _T("Unknown flag in wxTreeCtrl::DoExpand") );
08b7c251
VZ
839
840 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
d220ae32
VZ
841 // emulate them. This behaviour has changed slightly with comctl32.dll
842 // v 4.70 - now it does send them but only the first time. To maintain
843 // compatible behaviour and also in order to not have surprises with the
844 // future versions, don't rely on this and still do everything ourselves.
845 // To avoid that the messages be sent twice when the item is expanded for
846 // the first time we must clear TVIS_EXPANDEDONCE style manually.
847
848 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDEDONCE);
849 tvItem.state = 0;
850 DoSetItem(&tvItem);
851
852 if ( TreeView_Expand(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
08b7c251
VZ
853 {
854 wxTreeEvent event(wxEVT_NULL, m_windowId);
855 event.m_item = item;
856
857 bool isExpanded = IsExpanded(item);
2bda0e17 858
08b7c251 859 event.SetEventObject(this);
2bda0e17 860
d220ae32 861 // FIXME return value of {EXPAND|COLLAPS}ING event handler is discarded
08b7c251
VZ
862 event.SetEventType(g_events[isExpanded][TRUE]);
863 GetEventHandler()->ProcessEvent(event);
2bda0e17 864
08b7c251
VZ
865 event.SetEventType(g_events[isExpanded][FALSE]);
866 GetEventHandler()->ProcessEvent(event);
867 }
d220ae32 868 //else: change didn't took place, so do nothing at all
2bda0e17
KB
869}
870
08b7c251 871void wxTreeCtrl::Expand(const wxTreeItemId& item)
2bda0e17 872{
08b7c251 873 DoExpand(item, TVE_EXPAND);
2bda0e17 874}
2bda0e17 875
08b7c251 876void wxTreeCtrl::Collapse(const wxTreeItemId& item)
2bda0e17 877{
08b7c251 878 DoExpand(item, TVE_COLLAPSE);
2bda0e17
KB
879}
880
08b7c251 881void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
2bda0e17 882{
dd3646fd 883 DoExpand(item, TVE_COLLAPSE | TVE_COLLAPSERESET);
2bda0e17
KB
884}
885
08b7c251 886void wxTreeCtrl::Toggle(const wxTreeItemId& item)
2bda0e17 887{
08b7c251 888 DoExpand(item, TVE_TOGGLE);
2bda0e17
KB
889}
890
42c5812d
UU
891void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
892{
9dfbf520 893 DoExpand(item, action);
42c5812d
UU
894}
895
08b7c251 896void wxTreeCtrl::Unselect()
2bda0e17 897{
9dfbf520
VZ
898 wxASSERT_MSG( !(m_windowStyle & wxTR_MULTIPLE), _T("doesn't make sense") );
899
900 // just remove the selection
06e38c8e 901 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
08b7c251 902}
02ce7b72 903
9dfbf520 904void wxTreeCtrl::UnselectAll()
08b7c251 905{
9dfbf520 906 if ( m_windowStyle & wxTR_MULTIPLE )
2bda0e17 907 {
9dfbf520
VZ
908 wxArrayTreeItemIds selections;
909 size_t count = GetSelections(selections);
910 for ( size_t n = 0; n < count; n++ )
d220ae32 911 {
9dfbf520 912 SetItemCheck(selections[n], FALSE);
d220ae32 913 }
9dfbf520
VZ
914 }
915 else
916 {
917 // just remove the selection
918 Unselect();
919 }
920}
921
922void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
923{
924 if ( m_windowStyle & wxTR_MULTIPLE )
925 {
926 // selecting the item means checking it
927 SetItemCheck(item);
928 }
929 else
930 {
931 // inspite of the docs (MSDN Jan 99 edition), we don't seem to receive
932 // the notification from the control (i.e. TVN_SELCHANG{ED|ING}), so
933 // send them ourselves
934
935 wxTreeEvent event(wxEVT_NULL, m_windowId);
936 event.m_item = item;
937 event.SetEventObject(this);
938
939 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGING);
940 if ( !GetEventHandler()->ProcessEvent(event) || event.IsAllowed() )
d220ae32 941 {
9dfbf520
VZ
942 if ( !TreeView_SelectItem(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
943 {
944 wxLogLastError("TreeView_SelectItem");
945 }
946 else
947 {
948 event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
949 (void)GetEventHandler()->ProcessEvent(event);
950 }
d220ae32 951 }
9dfbf520 952 //else: program vetoed the change
2bda0e17 953 }
08b7c251 954}
2bda0e17 955
08b7c251
VZ
956void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
957{
958 // no error return
d220ae32 959 TreeView_EnsureVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
08b7c251
VZ
960}
961
962void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
963{
d220ae32 964 if ( !TreeView_SelectSetFirstVisible(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 965 {
08b7c251 966 wxLogLastError("TreeView_SelectSetFirstVisible");
2bda0e17 967 }
08b7c251
VZ
968}
969
970wxTextCtrl* wxTreeCtrl::GetEditControl() const
971{
972 return m_textCtrl;
973}
974
975void wxTreeCtrl::DeleteTextCtrl()
976{
977 if ( m_textCtrl )
2bda0e17 978 {
08b7c251
VZ
979 m_textCtrl->UnsubclassWin();
980 m_textCtrl->SetHWND(0);
981 delete m_textCtrl;
982 m_textCtrl = NULL;
2bda0e17 983 }
08b7c251 984}
2bda0e17 985
08b7c251
VZ
986wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
987 wxClassInfo* textControlClass)
988{
989 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
990
d220ae32 991 HWND hWnd = (HWND) TreeView_EditLabel(GetHwnd(), (HTREEITEM) (WXHTREEITEM) item);
2bda0e17 992
5ea47806
VZ
993 // this is not an error - the TVN_BEGINLABELEDIT handler might have
994 // returned FALSE
995 if ( !hWnd )
996 {
997 return NULL;
998 }
2bda0e17 999
08b7c251 1000 DeleteTextCtrl();
2bda0e17 1001
08b7c251
VZ
1002 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
1003 m_textCtrl->SetHWND((WXHWND)hWnd);
1004 m_textCtrl->SubclassWin((WXHWND)hWnd);
2bda0e17 1005
08b7c251 1006 return m_textCtrl;
2bda0e17
KB
1007}
1008
08b7c251
VZ
1009// End label editing, optionally cancelling the edit
1010void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
2bda0e17 1011{
d220ae32 1012 TreeView_EndEditLabelNow(GetHwnd(), discardChanges);
08b7c251
VZ
1013
1014 DeleteTextCtrl();
2bda0e17
KB
1015}
1016
08b7c251 1017wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
2bda0e17 1018{
08b7c251
VZ
1019 TV_HITTESTINFO hitTestInfo;
1020 hitTestInfo.pt.x = (int)point.x;
1021 hitTestInfo.pt.y = (int)point.y;
2bda0e17 1022
d220ae32 1023 TreeView_HitTest(GetHwnd(), &hitTestInfo);
2bda0e17 1024
08b7c251
VZ
1025 flags = 0;
1026
1027 // avoid repetition
1028 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
1029 flags |= wxTREE_HITTEST_##flag
1030
1031 TRANSLATE_FLAG(ABOVE);
1032 TRANSLATE_FLAG(BELOW);
1033 TRANSLATE_FLAG(NOWHERE);
1034 TRANSLATE_FLAG(ONITEMBUTTON);
1035 TRANSLATE_FLAG(ONITEMICON);
1036 TRANSLATE_FLAG(ONITEMINDENT);
1037 TRANSLATE_FLAG(ONITEMLABEL);
1038 TRANSLATE_FLAG(ONITEMRIGHT);
1039 TRANSLATE_FLAG(ONITEMSTATEICON);
1040 TRANSLATE_FLAG(TOLEFT);
1041 TRANSLATE_FLAG(TORIGHT);
2bda0e17 1042
08b7c251
VZ
1043 #undef TRANSLATE_FLAG
1044
06e38c8e 1045 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
08b7c251
VZ
1046}
1047
f7c832a7
VZ
1048bool wxTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
1049 wxRect& rect,
1050 bool textOnly) const
1051{
1052 RECT rc;
d220ae32 1053 if ( TreeView_GetItemRect(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item,
f7c832a7
VZ
1054 &rc, textOnly) )
1055 {
1056 rect = wxRect(wxPoint(rc.left, rc.top), wxPoint(rc.right, rc.bottom));
1057
1058 return TRUE;
1059 }
1060 else
1061 {
1062 // couldn't retrieve rect: for example, item isn't visible
1063 return FALSE;
1064 }
1065}
1066
23fd5130
VZ
1067// ----------------------------------------------------------------------------
1068// sorting stuff
1069// ----------------------------------------------------------------------------
f7c832a7 1070
23fd5130
VZ
1071static int CALLBACK TreeView_CompareCallback(wxTreeItemData *pItem1,
1072 wxTreeItemData *pItem2,
1073 wxTreeCtrl *tree)
1074{
096c9f9b
VZ
1075 wxCHECK_MSG( pItem1 && pItem2, 0,
1076 _T("sorting tree without data doesn't make sense") );
1077
23fd5130
VZ
1078 return tree->OnCompareItems(pItem1->GetId(), pItem2->GetId());
1079}
1080
95aabccc
VZ
1081int wxTreeCtrl::OnCompareItems(const wxTreeItemId& item1,
1082 const wxTreeItemId& item2)
08b7c251 1083{
837e5743 1084 return wxStrcmp(GetItemText(item1), GetItemText(item2));
95aabccc
VZ
1085}
1086
1087void wxTreeCtrl::SortChildren(const wxTreeItemId& item)
1088{
1089 // rely on the fact that TreeView_SortChildren does the same thing as our
23fd5130
VZ
1090 // default behaviour, i.e. sorts items alphabetically and so call it
1091 // directly if we're not in derived class (much more efficient!)
1092 if ( GetClassInfo() == CLASSINFO(wxTreeCtrl) )
2bda0e17 1093 {
d220ae32 1094 TreeView_SortChildren(GetHwnd(), (HTREEITEM)(WXHTREEITEM)item, 0);
2bda0e17 1095 }
08b7c251 1096 else
2bda0e17 1097 {
62448488 1098 TV_SORTCB tvSort;
23fd5130
VZ
1099 tvSort.hParent = (HTREEITEM)(WXHTREEITEM)item;
1100 tvSort.lpfnCompare = (PFNTVCOMPARE)TreeView_CompareCallback;
1101 tvSort.lParam = (LPARAM)this;
d220ae32 1102 TreeView_SortChildrenCB(GetHwnd(), &tvSort, 0 /* reserved */);
2bda0e17 1103 }
08b7c251 1104}
2bda0e17 1105
08b7c251
VZ
1106// ----------------------------------------------------------------------------
1107// implementation
1108// ----------------------------------------------------------------------------
2bda0e17 1109
08b7c251
VZ
1110bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
1111{
1112 if ( cmd == EN_UPDATE )
2bda0e17 1113 {
08b7c251
VZ
1114 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
1115 event.SetEventObject( this );
1116 ProcessCommand(event);
2bda0e17 1117 }
08b7c251 1118 else if ( cmd == EN_KILLFOCUS )
2bda0e17 1119 {
08b7c251
VZ
1120 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
1121 event.SetEventObject( this );
1122 ProcessCommand(event);
2bda0e17 1123 }
08b7c251 1124 else
2bda0e17 1125 {
08b7c251
VZ
1126 // nothing done
1127 return FALSE;
2bda0e17 1128 }
08b7c251
VZ
1129
1130 // command processed
1131 return TRUE;
1132}
1133
1134// process WM_NOTIFY Windows message
a23fd0e1 1135bool wxTreeCtrl::MSWOnNotify(int idCtrl, WXLPARAM lParam, WXLPARAM *result)
08b7c251
VZ
1136{
1137 wxTreeEvent event(wxEVT_NULL, m_windowId);
1138 wxEventType eventType = wxEVT_NULL;
1139 NMHDR *hdr = (NMHDR *)lParam;
1140
1141 switch ( hdr->code )
2bda0e17 1142 {
08b7c251
VZ
1143 case TVN_BEGINDRAG:
1144 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
1145 // fall through
1146
1147 case TVN_BEGINRDRAG:
1148 {
1149 if ( eventType == wxEVT_NULL )
1150 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
1151 //else: left drag, already set above
1152
1153 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1154
06e38c8e 1155 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
1156 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
1157 break;
1158 }
1159
1160 case TVN_BEGINLABELEDIT:
1161 {
1162 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
1163 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1164
06e38c8e 1165 event.m_item = (WXHTREEITEM) info->item.hItem;
5ea47806 1166 event.m_label = info->item.pszText;
08b7c251
VZ
1167 break;
1168 }
1169
1170 case TVN_DELETEITEM:
1171 {
1172 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
1173 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
1174
06e38c8e 1175 event.m_item = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
1176 break;
1177 }
1178
1179 case TVN_ENDLABELEDIT:
1180 {
1181 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
1182 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1183
5ea47806
VZ
1184 event.m_item = (WXHTREEITEM)info->item.hItem;
1185 event.m_label = info->item.pszText;
08b7c251
VZ
1186 break;
1187 }
1188
1189 case TVN_GETDISPINFO:
1190 eventType = wxEVT_COMMAND_TREE_GET_INFO;
1191 // fall through
1192
1193 case TVN_SETDISPINFO:
1194 {
1195 if ( eventType == wxEVT_NULL )
1196 eventType = wxEVT_COMMAND_TREE_SET_INFO;
1197 //else: get, already set above
1198
1199 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
1200
06e38c8e 1201 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
1202 break;
1203 }
1204
1205 case TVN_ITEMEXPANDING:
1206 event.m_code = FALSE;
1207 // fall through
1208
1209 case TVN_ITEMEXPANDED:
1210 {
1211 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
1212
1213 bool expand = FALSE;
1214 switch ( tv->action )
1215 {
1216 case TVE_EXPAND:
1217 expand = TRUE;
1218 break;
1219
1220 case TVE_COLLAPSE:
1221 expand = FALSE;
1222 break;
1223
1224 default:
837e5743
OK
1225 wxLogDebug(_T("unexpected code %d in TVN_ITEMEXPAND "
1226 "message"), tv->action);
08b7c251
VZ
1227 }
1228
06e38c8e 1229 bool ing = (hdr->code == TVN_ITEMEXPANDING);
08b7c251
VZ
1230 eventType = g_events[expand][ing];
1231
06e38c8e 1232 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
1233 break;
1234 }
1235
1236 case TVN_KEYDOWN:
1237 {
1238 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
1239 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
1240
1241 event.m_code = wxCharCodeMSWToWX(info->wVKey);
23fd5130
VZ
1242
1243 // a separate event for this case
1244 if ( info->wVKey == VK_SPACE || info->wVKey == VK_RETURN )
1245 {
1246 wxTreeEvent event2(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
1247 m_windowId);
1248 event2.SetEventObject(this);
1249
1250 GetEventHandler()->ProcessEvent(event2);
1251 }
08b7c251
VZ
1252 break;
1253 }
1254
1255 case TVN_SELCHANGED:
1256 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
1257 // fall through
1258
1259 case TVN_SELCHANGING:
1260 {
1261 if ( eventType == wxEVT_NULL )
1262 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
1263 //else: already set above
1264
1265 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1266
06e38c8e
JS
1267 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
1268 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
1269 break;
1270 }
1271
1272 default:
a23fd0e1 1273 return wxControl::MSWOnNotify(idCtrl, lParam, result);
2bda0e17 1274 }
08b7c251
VZ
1275
1276 event.SetEventObject(this);
1277 event.SetEventType(eventType);
1278
fd3f686c 1279 bool processed = GetEventHandler()->ProcessEvent(event);
08b7c251
VZ
1280
1281 // post processing
5ea47806 1282 switch ( hdr->code )
2bda0e17 1283 {
5ea47806
VZ
1284 case TVN_DELETEITEM:
1285 {
1286 // NB: we might process this message using wxWindows event
1287 // tables, but due to overhead of wxWin event system we
1288 // prefer to do it here ourself (otherwise deleting a tree
1289 // with many items is just too slow)
1290 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
1291 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
1292 delete data; // may be NULL, ok
08b7c251 1293
5ea47806
VZ
1294 processed = TRUE; // Make sure we don't get called twice
1295 }
1296 break;
1297
1298 case TVN_BEGINLABELEDIT:
1299 // return TRUE to cancel label editing
1300 *result = !event.IsAllowed();
1301 break;
1302
1303 case TVN_ENDLABELEDIT:
1304 // return TRUE to set the label to the new string
1305 *result = event.IsAllowed();
1306
1307 // ensure that we don't have the text ctrl which is going to be
1308 // deleted any more
1309 DeleteTextCtrl();
1310 break;
1311
1312 case TVN_SELCHANGING:
1313 case TVN_ITEMEXPANDING:
1314 // return TRUE to prevent the action from happening
1315 *result = !event.IsAllowed();
1316 break;
1317
1318 //default:
1319 // for the other messages the return value is ignored and there is
1320 // nothing special to do
1321 }
fd3f686c
VZ
1322
1323 return processed;
2bda0e17
KB
1324}
1325
08b7c251 1326// ----------------------------------------------------------------------------
2bda0e17 1327// Tree event
08b7c251
VZ
1328// ----------------------------------------------------------------------------
1329
92976ab6 1330IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
2bda0e17 1331
08b7c251 1332wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
fd3f686c 1333 : wxNotifyEvent(commandType, id)
2bda0e17 1334{
08b7c251
VZ
1335 m_code = 0;
1336 m_itemOld = 0;
2bda0e17
KB
1337}
1338
08b7c251 1339#endif // __WIN95__
2bda0e17 1340