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