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