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