]> git.saurik.com Git - wxWidgets.git/blame - src/msw/treectrl.cpp
moved common code from ctor and Create() to a separate Init() function
[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
08b7c251
VZ
57#include "wx/treectrl.h"
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
08b7c251
VZ
257// ----------------------------------------------------------------------------
258// Item access
259// ----------------------------------------------------------------------------
260
261wxString wxTreeCtrl::GetItemText(const wxTreeItemId& item) const
2bda0e17 262{
08b7c251 263 char buf[512]; // the size is arbitrary...
02ce7b72 264
08b7c251
VZ
265 wxTreeViewItem tvItem(item, TVIF_TEXT);
266 tvItem.pszText = buf;
267 tvItem.cchTextMax = WXSIZEOF(buf);
268 if ( !DoGetItem(&tvItem) )
269 {
270 // don't return some garbage which was on stack, but an empty string
271 buf[0] = '\0';
272 }
2bda0e17 273
08b7c251
VZ
274 return wxString(buf);
275}
2bda0e17 276
08b7c251
VZ
277void wxTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
278{
279 wxTreeViewItem tvItem(item, TVIF_TEXT);
280 tvItem.pszText = (char *)text.c_str(); // conversion is ok
281 DoSetItem(&tvItem);
282}
2bda0e17 283
08b7c251
VZ
284int wxTreeCtrl::GetItemImage(const wxTreeItemId& item) const
285{
286 wxTreeViewItem tvItem(item, TVIF_IMAGE);
287 DoGetItem(&tvItem);
2bda0e17 288
08b7c251
VZ
289 return tvItem.iImage;
290}
2bda0e17 291
08b7c251
VZ
292void wxTreeCtrl::SetItemImage(const wxTreeItemId& item, int image)
293{
294 wxTreeViewItem tvItem(item, TVIF_IMAGE);
295 tvItem.iImage = image;
296 DoSetItem(&tvItem);
297}
2bda0e17 298
08b7c251
VZ
299int wxTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
300{
301 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
302 DoGetItem(&tvItem);
2bda0e17 303
08b7c251 304 return tvItem.iSelectedImage;
2bda0e17
KB
305}
306
08b7c251 307void wxTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
2bda0e17 308{
08b7c251
VZ
309 wxTreeViewItem tvItem(item, TVIF_SELECTEDIMAGE);
310 tvItem.iSelectedImage = image;
311 DoSetItem(&tvItem);
2bda0e17
KB
312}
313
08b7c251 314wxTreeItemData *wxTreeCtrl::GetItemData(const wxTreeItemId& item) const
2bda0e17 315{
08b7c251
VZ
316 wxTreeViewItem tvItem(item, TVIF_PARAM);
317 if ( !DoGetItem(&tvItem) )
318 {
319 return NULL;
320 }
2bda0e17 321
3a5a2f56 322 return (wxTreeItemData *)tvItem.lParam;
2bda0e17
KB
323}
324
08b7c251 325void wxTreeCtrl::SetItemData(const wxTreeItemId& item, wxTreeItemData *data)
2bda0e17 326{
08b7c251
VZ
327 wxTreeViewItem tvItem(item, TVIF_PARAM);
328 tvItem.lParam = (LPARAM)data;
329 DoSetItem(&tvItem);
330}
2bda0e17 331
3a5a2f56
VZ
332void wxTreeCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
333{
334 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
335 tvItem.cChildren = (int)has;
336 DoSetItem(&tvItem);
337}
338
08b7c251
VZ
339// ----------------------------------------------------------------------------
340// Item status
341// ----------------------------------------------------------------------------
2bda0e17 342
08b7c251
VZ
343bool wxTreeCtrl::IsVisible(const wxTreeItemId& item) const
344{
345 RECT rect;
06e38c8e
JS
346// return (TreeView_GetItemRect(wxhWnd, (HTREEITEM) (WXHTREEITEM)item, &rect, FALSE) != 0);
347 // Bug in Gnu-Win32 headers, so don't use the macro.
348 return (SendMessage((wxhWnd), TVM_GETITEMRECT, (WPARAM) FALSE, (LPARAM) & rect) != 0);
349
2bda0e17
KB
350}
351
08b7c251 352bool wxTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
2bda0e17 353{
08b7c251
VZ
354 wxTreeViewItem tvItem(item, TVIF_CHILDREN);
355 DoGetItem(&tvItem);
2bda0e17 356
08b7c251 357 return tvItem.cChildren != 0;
2bda0e17
KB
358}
359
08b7c251 360bool wxTreeCtrl::IsExpanded(const wxTreeItemId& item) const
2bda0e17 361{
08b7c251
VZ
362 // probably not a good idea to put it here
363 //wxASSERT( ItemHasChildren(item) );
2bda0e17 364
08b7c251
VZ
365 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_EXPANDED);
366 DoGetItem(&tvItem);
2bda0e17 367
08b7c251 368 return (tvItem.state & TVIS_EXPANDED) != 0;
2bda0e17
KB
369}
370
08b7c251 371bool wxTreeCtrl::IsSelected(const wxTreeItemId& item) const
2bda0e17 372{
08b7c251
VZ
373 wxTreeViewItem tvItem(item, TVIF_STATE, TVIS_SELECTED);
374 DoGetItem(&tvItem);
2bda0e17 375
08b7c251 376 return (tvItem.state & TVIS_SELECTED) != 0;
2bda0e17
KB
377}
378
08b7c251
VZ
379// ----------------------------------------------------------------------------
380// navigation
381// ----------------------------------------------------------------------------
2bda0e17 382
08b7c251
VZ
383wxTreeItemId wxTreeCtrl::GetRootItem() const
384{
a3168196 385 return wxTreeItemId((WXHTREEITEM) TreeView_GetRoot(wxhWnd));
08b7c251 386}
2bda0e17 387
08b7c251
VZ
388wxTreeItemId wxTreeCtrl::GetSelection() const
389{
a3168196 390 return wxTreeItemId((WXHTREEITEM) TreeView_GetSelection(wxhWnd));
2bda0e17
KB
391}
392
08b7c251 393wxTreeItemId wxTreeCtrl::GetParent(const wxTreeItemId& item) const
2bda0e17 394{
06e38c8e 395 return wxTreeItemId((WXHTREEITEM) TreeView_GetParent(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 396}
2bda0e17 397
08b7c251 398wxTreeItemId wxTreeCtrl::GetFirstChild(const wxTreeItemId& item,
06e38c8e 399 long& _cookie) const
08b7c251
VZ
400{
401 // remember the last child returned in 'cookie'
06e38c8e 402 _cookie = (long)TreeView_GetChild(wxhWnd, (HTREEITEM) (WXHTREEITEM)item);
2bda0e17 403
06e38c8e 404 return wxTreeItemId((WXHTREEITEM)_cookie);
2bda0e17
KB
405}
406
08b7c251 407wxTreeItemId wxTreeCtrl::GetNextChild(const wxTreeItemId& WXUNUSED(item),
06e38c8e 408 long& _cookie) const
2bda0e17 409{
2e5dddb0
JS
410 wxTreeItemId l=wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(wxhWnd,
411 (HTREEITEM) (WXHTREEITEM)_cookie));
412 _cookie=(long)l;
413 return l;
08b7c251 414}
2bda0e17 415
08b7c251
VZ
416wxTreeItemId wxTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
417{
a3168196 418 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
419}
420
08b7c251 421wxTreeItemId wxTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
2bda0e17 422{
a3168196 423 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevSibling(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
2bda0e17
KB
424}
425
08b7c251 426wxTreeItemId wxTreeCtrl::GetFirstVisibleItem() const
2bda0e17 427{
a3168196 428 return wxTreeItemId((WXHTREEITEM) TreeView_GetFirstVisible(wxhWnd));
2bda0e17
KB
429}
430
08b7c251 431wxTreeItemId wxTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
2bda0e17 432{
08b7c251
VZ
433 wxASSERT_MSG( IsVisible(item), "The item you call GetNextVisible() "
434 "for must be visible itself!");
02ce7b72 435
a3168196 436 return wxTreeItemId((WXHTREEITEM) TreeView_GetNextVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 437}
02ce7b72 438
08b7c251
VZ
439wxTreeItemId wxTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
440{
441 wxASSERT_MSG( IsVisible(item), "The item you call GetPrevVisible() "
442 "for must be visible itself!");
02ce7b72 443
a3168196 444 return wxTreeItemId((WXHTREEITEM) TreeView_GetPrevVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item));
08b7c251 445}
02ce7b72 446
08b7c251
VZ
447// ----------------------------------------------------------------------------
448// Usual operations
449// ----------------------------------------------------------------------------
02ce7b72 450
08b7c251
VZ
451wxTreeItemId wxTreeCtrl::DoInsertItem(const wxTreeItemId& parent,
452 wxTreeItemId hInsertAfter,
453 const wxString& text,
454 int image, int selectedImage,
455 wxTreeItemData *data)
456{
457 TV_INSERTSTRUCT tvIns;
06e38c8e
JS
458 tvIns.hParent = (HTREEITEM) (WXHTREEITEM)parent;
459 tvIns.hInsertAfter = (HTREEITEM) (WXHTREEITEM) hInsertAfter;
08b7c251
VZ
460 UINT mask = 0;
461 if ( !text.IsEmpty() )
462 {
463 mask |= TVIF_TEXT;
464 tvIns.item.pszText = (char *)text.c_str(); // cast is ok
465 }
02ce7b72 466
08b7c251
VZ
467 if ( image != -1 )
468 {
469 mask |= TVIF_IMAGE;
470 tvIns.item.iImage = image;
3a5a2f56 471
6b037754 472 if ( selectedImage == -1 )
3a5a2f56
VZ
473 {
474 // take the same image for selected icon if not specified
475 selectedImage = image;
476 }
08b7c251 477 }
02ce7b72 478
08b7c251
VZ
479 if ( selectedImage != -1 )
480 {
481 mask |= TVIF_SELECTEDIMAGE;
482 tvIns.item.iSelectedImage = selectedImage;
483 }
02ce7b72 484
08b7c251
VZ
485 if ( data != NULL )
486 {
487 mask |= TVIF_PARAM;
488 tvIns.item.lParam = (LPARAM)data;
489 }
02ce7b72 490
08b7c251 491 tvIns.item.mask = mask;
02ce7b72 492
4fabb575 493 HTREEITEM id = (HTREEITEM) TreeView_InsertItem(wxhWnd, &tvIns);
08b7c251
VZ
494 if ( id == 0 )
495 {
496 wxLogLastError("TreeView_InsertItem");
497 }
02ce7b72 498
fd3f686c
VZ
499 if ( data != NULL )
500 {
501 // associate the application tree item with Win32 tree item handle
502 data->SetId((WXHTREEITEM)id);
503 }
504
06e38c8e 505 return wxTreeItemId((WXHTREEITEM)id);
2bda0e17
KB
506}
507
08b7c251
VZ
508// for compatibility only
509wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
510 const wxString& text,
511 int image, int selImage,
512 long insertAfter)
2bda0e17 513{
06e38c8e 514 return DoInsertItem(parent, (WXHTREEITEM)insertAfter, text,
08b7c251 515 image, selImage, NULL);
2bda0e17
KB
516}
517
08b7c251
VZ
518wxTreeItemId wxTreeCtrl::AddRoot(const wxString& text,
519 int image, int selectedImage,
520 wxTreeItemData *data)
2bda0e17 521{
06e38c8e 522 return DoInsertItem(wxTreeItemId((WXHTREEITEM) 0), (WXHTREEITEM) 0,
08b7c251 523 text, image, selectedImage, data);
2bda0e17
KB
524}
525
08b7c251
VZ
526wxTreeItemId wxTreeCtrl::PrependItem(const wxTreeItemId& parent,
527 const wxString& text,
528 int image, int selectedImage,
529 wxTreeItemData *data)
2bda0e17 530{
06e38c8e 531 return DoInsertItem(parent, (WXHTREEITEM) TVI_FIRST,
08b7c251 532 text, image, selectedImage, data);
2bda0e17
KB
533}
534
08b7c251
VZ
535wxTreeItemId wxTreeCtrl::InsertItem(const wxTreeItemId& parent,
536 const wxTreeItemId& idPrevious,
537 const wxString& text,
538 int image, int selectedImage,
539 wxTreeItemData *data)
2bda0e17 540{
08b7c251 541 return DoInsertItem(parent, idPrevious, text, image, selectedImage, data);
2bda0e17
KB
542}
543
08b7c251
VZ
544wxTreeItemId wxTreeCtrl::AppendItem(const wxTreeItemId& parent,
545 const wxString& text,
546 int image, int selectedImage,
547 wxTreeItemData *data)
2bda0e17 548{
06e38c8e 549 return DoInsertItem(parent, (WXHTREEITEM) TVI_LAST,
08b7c251 550 text, image, selectedImage, data);
2bda0e17
KB
551}
552
08b7c251 553void wxTreeCtrl::Delete(const wxTreeItemId& item)
2bda0e17 554{
08b7c251 555 wxTreeItemData *data = GetItemData(item);
42c5812d
UU
556 if(data!=NULL)
557 delete data; // may be NULL, ok
bbcdf8bc 558
06e38c8e 559 if ( !TreeView_DeleteItem(wxhWnd, (HTREEITEM)(WXHTREEITEM)item) )
bbcdf8bc 560 {
08b7c251 561 wxLogLastError("TreeView_DeleteItem");
bbcdf8bc 562 }
bbcdf8bc
JS
563}
564
08b7c251 565void wxTreeCtrl::DeleteAllItems()
bbcdf8bc 566{
06e38c8e 567 if ( !TreeView_DeleteAllItems(wxhWnd) )
bbcdf8bc 568 {
08b7c251 569 wxLogLastError("TreeView_DeleteAllItems");
bbcdf8bc 570 }
2bda0e17
KB
571}
572
08b7c251 573void wxTreeCtrl::DoExpand(const wxTreeItemId& item, int flag)
2bda0e17 574{
08b7c251
VZ
575 wxASSERT_MSG( flag == TVE_COLLAPSE || flag == TVE_COLLAPSERESET ||
576 flag == TVE_EXPAND || flag == TVE_TOGGLE,
577 "Unknown flag in wxTreeCtrl::DoExpand" );
578
579 // TreeView_Expand doesn't send TVN_ITEMEXPAND(ING) messages, so we must
580 // emulate them
06e38c8e 581 if ( TreeView_Expand(wxhWnd, (HTREEITEM) (WXHTREEITEM) item, flag) != 0 )
08b7c251
VZ
582 {
583 wxTreeEvent event(wxEVT_NULL, m_windowId);
584 event.m_item = item;
585
586 bool isExpanded = IsExpanded(item);
2bda0e17 587
08b7c251 588 event.SetEventObject(this);
2bda0e17 589
08b7c251
VZ
590 // @@@ return values of {EXPAND|COLLAPS}ING event handler is discarded
591 event.SetEventType(g_events[isExpanded][TRUE]);
592 GetEventHandler()->ProcessEvent(event);
2bda0e17 593
08b7c251
VZ
594 event.SetEventType(g_events[isExpanded][FALSE]);
595 GetEventHandler()->ProcessEvent(event);
596 }
597 else
598 {
599 // I wonder if it really ever happens...
600 wxLogDebug("TreeView_Expand: change didn't took place.");
601 }
2bda0e17
KB
602}
603
08b7c251 604void wxTreeCtrl::Expand(const wxTreeItemId& item)
2bda0e17 605{
08b7c251 606 DoExpand(item, TVE_EXPAND);
2bda0e17 607}
2bda0e17 608
08b7c251 609void wxTreeCtrl::Collapse(const wxTreeItemId& item)
2bda0e17 610{
08b7c251 611 DoExpand(item, TVE_COLLAPSE);
2bda0e17
KB
612}
613
08b7c251 614void wxTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
2bda0e17 615{
08b7c251 616 DoExpand(item, TVE_COLLAPSERESET);
2bda0e17
KB
617}
618
08b7c251 619void wxTreeCtrl::Toggle(const wxTreeItemId& item)
2bda0e17 620{
08b7c251 621 DoExpand(item, TVE_TOGGLE);
2bda0e17
KB
622}
623
42c5812d
UU
624void wxTreeCtrl::ExpandItem(const wxTreeItemId& item, int action)
625{
626 DoExpand(item, action);
627}
628
08b7c251 629void wxTreeCtrl::Unselect()
2bda0e17 630{
06e38c8e 631 SelectItem(wxTreeItemId((WXHTREEITEM) 0));
08b7c251 632}
02ce7b72 633
08b7c251
VZ
634void wxTreeCtrl::SelectItem(const wxTreeItemId& item)
635{
06e38c8e 636 if ( !TreeView_SelectItem(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 637 {
08b7c251 638 wxLogLastError("TreeView_SelectItem");
2bda0e17 639 }
08b7c251 640}
2bda0e17 641
08b7c251
VZ
642void wxTreeCtrl::EnsureVisible(const wxTreeItemId& item)
643{
644 // no error return
06e38c8e 645 TreeView_EnsureVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
08b7c251
VZ
646}
647
648void wxTreeCtrl::ScrollTo(const wxTreeItemId& item)
649{
06e38c8e 650 if ( !TreeView_SelectSetFirstVisible(wxhWnd, (HTREEITEM) (WXHTREEITEM) item) )
2bda0e17 651 {
08b7c251 652 wxLogLastError("TreeView_SelectSetFirstVisible");
2bda0e17 653 }
08b7c251
VZ
654}
655
656wxTextCtrl* wxTreeCtrl::GetEditControl() const
657{
658 return m_textCtrl;
659}
660
661void wxTreeCtrl::DeleteTextCtrl()
662{
663 if ( m_textCtrl )
2bda0e17 664 {
08b7c251
VZ
665 m_textCtrl->UnsubclassWin();
666 m_textCtrl->SetHWND(0);
667 delete m_textCtrl;
668 m_textCtrl = NULL;
2bda0e17 669 }
08b7c251 670}
2bda0e17 671
08b7c251
VZ
672wxTextCtrl* wxTreeCtrl::EditLabel(const wxTreeItemId& item,
673 wxClassInfo* textControlClass)
674{
675 wxASSERT( textControlClass->IsKindOf(CLASSINFO(wxTextCtrl)) );
676
06e38c8e 677 HWND hWnd = (HWND) TreeView_EditLabel(wxhWnd, (HTREEITEM) (WXHTREEITEM) item);
2bda0e17 678
08b7c251 679 wxCHECK_MSG( hWnd, NULL, "Can't edit tree ctrl label" );
2bda0e17 680
08b7c251 681 DeleteTextCtrl();
2bda0e17 682
08b7c251
VZ
683 m_textCtrl = (wxTextCtrl *)textControlClass->CreateObject();
684 m_textCtrl->SetHWND((WXHWND)hWnd);
685 m_textCtrl->SubclassWin((WXHWND)hWnd);
2bda0e17 686
08b7c251 687 return m_textCtrl;
2bda0e17
KB
688}
689
08b7c251
VZ
690// End label editing, optionally cancelling the edit
691void wxTreeCtrl::EndEditLabel(const wxTreeItemId& item, bool discardChanges)
2bda0e17 692{
06e38c8e 693 TreeView_EndEditLabelNow(wxhWnd, discardChanges);
08b7c251
VZ
694
695 DeleteTextCtrl();
2bda0e17
KB
696}
697
08b7c251 698wxTreeItemId wxTreeCtrl::HitTest(const wxPoint& point, int& flags)
2bda0e17 699{
08b7c251
VZ
700 TV_HITTESTINFO hitTestInfo;
701 hitTestInfo.pt.x = (int)point.x;
702 hitTestInfo.pt.y = (int)point.y;
2bda0e17 703
06e38c8e 704 TreeView_HitTest(wxhWnd, &hitTestInfo);
2bda0e17 705
08b7c251
VZ
706 flags = 0;
707
708 // avoid repetition
709 #define TRANSLATE_FLAG(flag) if ( hitTestInfo.flags & TVHT_##flag ) \
710 flags |= wxTREE_HITTEST_##flag
711
712 TRANSLATE_FLAG(ABOVE);
713 TRANSLATE_FLAG(BELOW);
714 TRANSLATE_FLAG(NOWHERE);
715 TRANSLATE_FLAG(ONITEMBUTTON);
716 TRANSLATE_FLAG(ONITEMICON);
717 TRANSLATE_FLAG(ONITEMINDENT);
718 TRANSLATE_FLAG(ONITEMLABEL);
719 TRANSLATE_FLAG(ONITEMRIGHT);
720 TRANSLATE_FLAG(ONITEMSTATEICON);
721 TRANSLATE_FLAG(TOLEFT);
722 TRANSLATE_FLAG(TORIGHT);
2bda0e17 723
08b7c251
VZ
724 #undef TRANSLATE_FLAG
725
06e38c8e 726 return wxTreeItemId((WXHTREEITEM) hitTestInfo.hItem);
08b7c251
VZ
727}
728
729void wxTreeCtrl::SortChildren(const wxTreeItemId& item,
730 wxTreeItemCmpFunc *cmpFunction)
731{
732 if ( cmpFunction == NULL )
2bda0e17 733 {
06e38c8e 734 TreeView_SortChildren(wxhWnd, (HTREEITEM) (WXHTREEITEM) item, 0);
2bda0e17 735 }
08b7c251 736 else
2bda0e17 737 {
08b7c251
VZ
738 // TODO: use TreeView_SortChildrenCB
739 wxFAIL_MSG("wxTreeCtrl::SortChildren not implemented");
2bda0e17 740 }
08b7c251 741}
2bda0e17 742
4fabb575
JS
743// TODO
744size_t wxTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recursively)
745{
746 return 0;
747}
748
08b7c251
VZ
749// ----------------------------------------------------------------------------
750// implementation
751// ----------------------------------------------------------------------------
2bda0e17 752
08b7c251
VZ
753bool wxTreeCtrl::MSWCommand(WXUINT cmd, WXWORD id)
754{
755 if ( cmd == EN_UPDATE )
2bda0e17 756 {
08b7c251
VZ
757 wxCommandEvent event(wxEVT_COMMAND_TEXT_UPDATED, id);
758 event.SetEventObject( this );
759 ProcessCommand(event);
2bda0e17 760 }
08b7c251 761 else if ( cmd == EN_KILLFOCUS )
2bda0e17 762 {
08b7c251
VZ
763 wxCommandEvent event(wxEVT_KILL_FOCUS, id);
764 event.SetEventObject( this );
765 ProcessCommand(event);
2bda0e17 766 }
08b7c251 767 else
2bda0e17 768 {
08b7c251
VZ
769 // nothing done
770 return FALSE;
2bda0e17 771 }
08b7c251
VZ
772
773 // command processed
774 return TRUE;
775}
776
777// process WM_NOTIFY Windows message
fd3f686c 778bool wxTreeCtrl::MSWNotify(WXWPARAM wParam, WXLPARAM lParam, WXLPARAM *result)
08b7c251
VZ
779{
780 wxTreeEvent event(wxEVT_NULL, m_windowId);
781 wxEventType eventType = wxEVT_NULL;
782 NMHDR *hdr = (NMHDR *)lParam;
783
784 switch ( hdr->code )
2bda0e17 785 {
08b7c251
VZ
786 case TVN_BEGINDRAG:
787 eventType = wxEVT_COMMAND_TREE_BEGIN_DRAG;
788 // fall through
789
790 case TVN_BEGINRDRAG:
791 {
792 if ( eventType == wxEVT_NULL )
793 eventType = wxEVT_COMMAND_TREE_BEGIN_RDRAG;
794 //else: left drag, already set above
795
796 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
797
06e38c8e 798 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
799 event.m_pointDrag = wxPoint(tv->ptDrag.x, tv->ptDrag.y);
800 break;
801 }
802
803 case TVN_BEGINLABELEDIT:
804 {
805 eventType = wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT;
806 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
807
06e38c8e 808 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
809 break;
810 }
811
812 case TVN_DELETEITEM:
813 {
814 eventType = wxEVT_COMMAND_TREE_DELETE_ITEM;
815 NM_TREEVIEW *tv = (NM_TREEVIEW *)lParam;
816
06e38c8e 817 event.m_item = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
818 break;
819 }
820
821 case TVN_ENDLABELEDIT:
822 {
823 eventType = wxEVT_COMMAND_TREE_END_LABEL_EDIT;
824 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
825
06e38c8e 826 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
827 break;
828 }
829
830 case TVN_GETDISPINFO:
831 eventType = wxEVT_COMMAND_TREE_GET_INFO;
832 // fall through
833
834 case TVN_SETDISPINFO:
835 {
836 if ( eventType == wxEVT_NULL )
837 eventType = wxEVT_COMMAND_TREE_SET_INFO;
838 //else: get, already set above
839
840 TV_DISPINFO *info = (TV_DISPINFO *)lParam;
841
06e38c8e 842 event.m_item = (WXHTREEITEM) info->item.hItem;
08b7c251
VZ
843 break;
844 }
845
846 case TVN_ITEMEXPANDING:
847 event.m_code = FALSE;
848 // fall through
849
850 case TVN_ITEMEXPANDED:
851 {
852 NM_TREEVIEW* tv = (NM_TREEVIEW*)lParam;
853
854 bool expand = FALSE;
855 switch ( tv->action )
856 {
857 case TVE_EXPAND:
858 expand = TRUE;
859 break;
860
861 case TVE_COLLAPSE:
862 expand = FALSE;
863 break;
864
865 default:
866 wxLogDebug("unexpected code %d in TVN_ITEMEXPAND "
867 "message", tv->action);
868 }
869
06e38c8e 870 bool ing = (hdr->code == TVN_ITEMEXPANDING);
08b7c251
VZ
871 eventType = g_events[expand][ing];
872
06e38c8e 873 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
08b7c251
VZ
874 break;
875 }
876
877 case TVN_KEYDOWN:
878 {
879 eventType = wxEVT_COMMAND_TREE_KEY_DOWN;
880 TV_KEYDOWN *info = (TV_KEYDOWN *)lParam;
881
882 event.m_code = wxCharCodeMSWToWX(info->wVKey);
883 break;
884 }
885
886 case TVN_SELCHANGED:
887 eventType = wxEVT_COMMAND_TREE_SEL_CHANGED;
888 // fall through
889
890 case TVN_SELCHANGING:
891 {
892 if ( eventType == wxEVT_NULL )
893 eventType = wxEVT_COMMAND_TREE_SEL_CHANGING;
894 //else: already set above
895
896 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
897
06e38c8e
JS
898 event.m_item = (WXHTREEITEM) tv->itemNew.hItem;
899 event.m_itemOld = (WXHTREEITEM) tv->itemOld.hItem;
08b7c251
VZ
900 break;
901 }
902
903 default:
fd3f686c 904 return wxControl::MSWNotify(wParam, lParam, result);
2bda0e17 905 }
08b7c251
VZ
906
907 event.SetEventObject(this);
908 event.SetEventType(eventType);
909
fd3f686c 910 bool processed = GetEventHandler()->ProcessEvent(event);
08b7c251
VZ
911
912 // post processing
fd3f686c 913 if ( hdr->code == TVN_DELETEITEM )
2bda0e17 914 {
08b7c251
VZ
915 // NB: we might process this message using wxWindows event tables, but
916 // due to overhead of wxWin event system we prefer to do it here
917 // (otherwise deleting a tree with many items is just too slow)
fd3f686c
VZ
918 NM_TREEVIEW* tv = (NM_TREEVIEW *)lParam;
919 wxTreeItemData *data = (wxTreeItemData *)tv->itemOld.lParam;
920 delete data; // may be NULL, ok
2bda0e17 921 }
08b7c251 922
fd3f686c
VZ
923 *result = !event.IsAllowed();
924
925 return processed;
2bda0e17
KB
926}
927
08b7c251 928// ----------------------------------------------------------------------------
2bda0e17 929// Tree event
08b7c251
VZ
930// ----------------------------------------------------------------------------
931
2bda0e17
KB
932IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxCommandEvent)
933
08b7c251 934wxTreeEvent::wxTreeEvent(wxEventType commandType, int id)
fd3f686c 935 : wxNotifyEvent(commandType, id)
2bda0e17 936{
08b7c251
VZ
937 m_code = 0;
938 m_itemOld = 0;
2bda0e17
KB
939}
940
08b7c251 941#endif // __WIN95__
2bda0e17 942