1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        treelistctrl.cpp
3 // Purpose:     multi column tree control implementation
4 // Created:     01/02/97
5 // Author:      Robert Roebling
6 // Maintainer:  Ronan Chartois (pgriddev)
7 // Version:     $Id: treelistctrl.cpp 3062 2012-09-23 13:48:23Z pgriddev $
8 // Copyright:   (c) 2004-2011 Robert Roebling, Julian Smart, Alberto Griggio,
9 //              Vadim Zeitlin, Otto Wyss, Ronan Chartois
10 // Licence:     wxWindows
11 /////////////////////////////////////////////////////////////////////////////
12 
13 // ===========================================================================
14 // declarations
15 // ===========================================================================
16 
17 // ---------------------------------------------------------------------------
18 // headers
19 // ---------------------------------------------------------------------------
20 
21 #if defined(__GNUG__) && !defined(__APPLE__)
22   #pragma implementation "treelistctrl.h"
23 #endif
24 
25 // For compilers that support precompilation, includes "wx.h".
26 #include "wx/wxprec.h"
27 
28 #ifdef __BORLANDC__
29     #pragma hdrstop
30 #endif
31 
32 
33 #include <wx/app.h>
34 #include <wx/treebase.h>
35 #include <wx/timer.h>
36 #include <wx/textctrl.h>
37 #include <wx/imaglist.h>
38 #include <wx/settings.h>
39 #include <wx/dcclient.h>
40 #include <wx/dcscreen.h>
41 #include <wx/scrolwin.h>
42 #include <wx/dcmemory.h>
43 #include <wx/renderer.h>
44 #include <wx/apptrait.h>
45 #include <wx/dcbuffer.h>
46 #include <wx/tooltip.h>
47 #include <wx/hashmap.h>
48 #include <wx/dynarray.h>
49 #include <wx/arrimpl.cpp>
50 #if wxCHECK_VERSION(3,1,1)
51 #include <wx/itemattr.h>
52 // wxTreeItemAttr was renamed to wxItemAttr
53 // instead of replacing all occurances, create this placeholder
54 class wxTreeItemAttr : public wxItemAttr
55 {};
56 #endif
57 
58 #if defined(__WXMAC__) && defined(__WXOSX__)
59 #include "wx/osx/private.h"
60 #elif defined(__WXMAC__)
61 #include "wx/mac/private.h"
62 #endif
63 
64 #include "treelistctrl.h"
65 
66 #include <wx/log.h>  // only required for debugging purpose
67 #include <wx/msgdlg.h>  // only required for debugging purpose
68 #include <algorithm>
69 
70 
71 namespace wxcode {
72 
73 // ---------------------------------------------------------------------------
74 // array types
75 // ---------------------------------------------------------------------------
76 
77 class wxTreeListItem;
78 class wxTreeListItemCellAttr;
79 
80 WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
81 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
82 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
83 
84 
85 WX_DECLARE_HASH_MAP( int, wxTreeListItemCellAttr *, wxIntegerHash, wxIntegerEqual, wxTreeListItemCellAttrHash );
86 
87 // --------------------------------------------------------------------------
88 // constants
89 // --------------------------------------------------------------------------
90 
91 static const int NO_IMAGE = -1;
92 
93 static const int LINEHEIGHT = 10;
94 static const int LINEATROOT = 5;
95 static const int MARGIN = 2;
96 static const int MININDENT = 16;
97 static const int BTNWIDTH = 9;
98 static const int BTNHEIGHT = 9;
99 static const int EXTRA_WIDTH = 4;
100 static const int EXTRA_HEIGHT = 4;
101 static const int HEADER_OFFSET_X = 0;  // changed from 1 to 0 on 2009.03.10 for Windows (other OS untested)
102 static const int HEADER_OFFSET_Y = 1;
103 
104 static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
105 static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
106 static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
107 
108 const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
109 
110 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
111 
112 
113 // ---------------------------------------------------------------------------
114 // private classes
115 // ---------------------------------------------------------------------------
116 
117 class  wxTreeListHeaderWindow : public wxWindow
118 {
119 protected:
120     wxTreeListMainWindow *m_owner;
121     const wxCursor *m_currentCursor;
122     const wxCursor *m_resizeCursor;
123     bool m_isDragging;
124 
125     // column being resized
126     int m_column;
127 
128     // divider line position in logical (unscrolled) coords
129     int m_currentX;
130 
131     // minimal position beyond which the divider line can't be dragged in
132     // logical coords
133     int m_minX;
134 
135     wxArrayTreeListColumnInfo m_columns;
136 
137     // total width of the columns
138     int m_total_col_width;
139 
140     // which col header is currently highlighted with mouse-over
141     int m_hotTrackCol;
142     int XToCol(int x);
143     void RefreshColLabel(int col);
144 
145 public:
146     wxTreeListHeaderWindow();
147 
148     wxTreeListHeaderWindow( wxWindow *win,
149                             wxWindowID id,
150                             wxTreeListMainWindow *owner,
151                             const wxPoint &pos = wxDefaultPosition,
152                             const wxSize &size = wxDefaultSize,
153                             long style = 0,
154                             const wxString &name = _T("wxtreelistctrlcolumntitles") );
155 
156     virtual ~wxTreeListHeaderWindow();
157 
158     void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
159     void DrawCurrent();
160     void AdjustDC(wxDC& dc);
161 
162     void OnPaint( wxPaintEvent &event );
OnEraseBackground(wxEraseEvent & WXUNUSED (event))163     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // reduce flicker
164     void OnMouse( wxMouseEvent &event );
165     void OnSetFocus( wxFocusEvent &event );
166 
167     // total width of all columns
GetWidth() const168     int GetWidth() const { return m_total_col_width; }
169 
170     // column manipulation
GetColumnCount() const171     int GetColumnCount() const { return (int)m_columns.GetCount(); }
172 
173     void AddColumn (const wxTreeListColumnInfo& colInfo);
174 
175     void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
176 
177     void RemoveColumn (int column);
178 
179     // column information manipulation
GetColumn(int column) const180     const wxTreeListColumnInfo& GetColumn (int column) const{
181         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
182                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
183         return m_columns[column];
184     }
GetColumn(int column)185     wxTreeListColumnInfo& GetColumn (int column) {
186         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
187                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
188         return m_columns[column];
189     }
190     void SetColumn (int column, const wxTreeListColumnInfo& info);
191 
GetColumnText(int column) const192     wxString GetColumnText (int column) const {
193         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
194                      wxEmptyString, _T("Invalid column"));
195         return m_columns[column].GetText();
196     }
SetColumnText(int column,const wxString & text)197     void SetColumnText (int column, const wxString& text) {
198         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
199                      _T("Invalid column"));
200         m_columns[column].SetText (text);
201     }
202 
GetColumnAlignment(int column) const203     int GetColumnAlignment (int column) const {
204         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
205                      wxALIGN_LEFT, _T("Invalid column"));
206         return m_columns[column].GetAlignment();
207     }
SetColumnAlignment(int column,int flag)208     void SetColumnAlignment (int column, int flag) {
209         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
210                      _T("Invalid column"));
211         m_columns[column].SetAlignment (flag);
212     }
213 
GetColumnWidth(int column) const214     int GetColumnWidth (int column) const {
215         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
216                      -1, _T("Invalid column"));
217         return m_columns[column].GetWidth();
218     }
219     void SetColumnWidth (int column, int width);
220 
IsColumnEditable(int column) const221     bool IsColumnEditable (int column) const {
222         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
223                      false, _T("Invalid column"));
224         return m_columns[column].IsEditable();
225     }
226 
IsColumnShown(int column) const227     bool IsColumnShown (int column) const {
228         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
229                      true, _T("Invalid column"));
230         return m_columns[column].IsShown();
231     }
232 
233     // needs refresh
234     bool m_dirty;
235 
236 private:
237     // common part of all ctors
238     void Init();
239 
240     void SendListEvent(wxEventType type, wxPoint pos);
241 
242     DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
243     DECLARE_EVENT_TABLE()
244 };
245 
246 
247 //-----------------------------------------------------------------------------
248 
249 class wxEditTextCtrl;
250 
251 
252 // this is the "true" control
253 class  wxTreeListMainWindow: public wxScrolledWindow
254 {
255 friend class wxTreeListItem;
256 friend class wxTreeListRenameTimer;
257 friend class wxEditTextCtrl;
258 
259 public:
260     // creation
261     // --------
wxTreeListMainWindow()262     wxTreeListMainWindow() { Init(); }
263 
wxTreeListMainWindow(wxTreeListCtrl * parent,wxWindowID id=-1,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize,long style=wxTR_DEFAULT_STYLE,const wxValidator & validator=wxDefaultValidator,const wxString & name=_T ("wxtreelistmainwindow"))264     wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
265                const wxPoint& pos = wxDefaultPosition,
266                const wxSize& size = wxDefaultSize,
267                long style = wxTR_DEFAULT_STYLE,
268                const wxValidator &validator = wxDefaultValidator,
269                const wxString& name = _T("wxtreelistmainwindow"))
270     {
271         Init();
272         Create (parent, id, pos, size, style, validator, name);
273     }
274 
275     virtual ~wxTreeListMainWindow();
276 
277     bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
278                 const wxPoint& pos = wxDefaultPosition,
279                 const wxSize& size = wxDefaultSize,
280                 long style = wxTR_DEFAULT_STYLE,
281                 const wxValidator &validator = wxDefaultValidator,
282                 const wxString& name = _T("wxtreelistctrl"));
283 
284     // accessors
285     // ---------
286 
287     // return true if this is a virtual list control
IsVirtual() const288     bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
289 
290     // get the total number of items in the control
291     size_t GetCount() const;
292 
293     // indent is the number of pixels the children are indented relative to
294     // the parents position. SetIndent() also redraws the control
295     // immediately.
GetIndent() const296     unsigned int GetIndent() const { return m_indent; }
297     void SetIndent(unsigned int indent);
298 
299     // see wxTreeListCtrl for the meaning
GetLineSpacing() const300     unsigned int GetLineSpacing() const { return m_linespacing; }
301     void SetLineSpacing(unsigned int spacing);
302 
303     // image list: these functions allow to associate an image list with
304     // the control and retrieve it. Note that when assigned with
305     // SetImageList, the control does _not_ delete
306     // the associated image list when it's deleted in order to allow image
307     // lists to be shared between different controls. If you use
308     // AssignImageList, the control _does_ delete the image list.
309 
310     // The normal image list is for the icons which correspond to the
311     // normal tree item state (whether it is selected or not).
312     // Additionally, the application might choose to show a state icon
313     // which corresponds to an app-defined item state (for example,
314     // checked/unchecked) which are taken from the state image list.
GetImageList() const315     wxImageList *GetImageList() const { return m_imageListNormal; }
GetStateImageList() const316     wxImageList *GetStateImageList() const { return m_imageListState; }
GetButtonsImageList() const317     wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
318 
319     void SetImageList(wxImageList *imageList);
320     void SetStateImageList(wxImageList *imageList);
321     void SetButtonsImageList(wxImageList *imageList);
322     void AssignImageList(wxImageList *imageList);
323     void AssignStateImageList(wxImageList *imageList);
324     void AssignButtonsImageList(wxImageList *imageList);
325 
326     void SetToolTip(const wxString& tip);
327     void SetToolTip(wxToolTip *tip);
328     void SetItemToolTip(const wxTreeItemId& item, const wxString &tip);
329 
330     // Functions to work with tree ctrl items.
331 
332 
333 
334     // accessors (most props have a default at row/item level *and* a default at cell level)
335     // ---------
336 
337     wxString GetItemText (const wxTreeItemId& item, int column) const;
338     wxString GetItemText (wxTreeItemData* item, int column) const;
339 
340     // ItemImage is special: main col has multiple images
GetItemImage(const wxTreeItemId & item,wxTreeItemIcon which=wxTreeItemIcon_Normal) const341     int GetItemImage (const wxTreeItemId& item,             wxTreeItemIcon which = wxTreeItemIcon_Normal) const  { return GetItemImage (item, GetMainColumn(), which); }
342     int GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
343 
344     // ItemData is special, there is a separate default at row/item level
345     wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
346     wxTreeItemData *GetItemData(const wxTreeItemId& item, int column) const;
347 
348     bool GetItemBold(const wxTreeItemId& item)             const;
349     bool GetItemBold(const wxTreeItemId& item, int column) const;
350 
351     wxColour GetItemTextColour(const wxTreeItemId& item)             const;
352     wxColour GetItemTextColour(const wxTreeItemId& item, int column) const;
353 
354     wxColour GetItemBackgroundColour(const wxTreeItemId& item)             const;
355     wxColour GetItemBackgroundColour(const wxTreeItemId& item, int column) const;
356 
357     wxFont GetItemFont(const wxTreeItemId& item) const;
358     wxFont GetItemFont(const wxTreeItemId& item, int column) const;
359 
360 
361 
362     // modifiers (most properties have a default at row/item level *and* a default at cell level)
363     // ---------
364 
365     // force appearance of [+] button near the item. This is useful to
366     // allow the user to expand the items which don't have any children now
367     // - but instead add them only when needed, thus minimizing memory
368     // usage and loading time.
369     void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
370 
371     // set item's label
372     void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
373 
374     // get one of the images associated with the item (normal by default)
SetItemImage(const wxTreeItemId & item,int image,wxTreeItemIcon which=wxTreeItemIcon_Normal)375     void SetItemImage (const wxTreeItemId& item,             int image, wxTreeItemIcon which = wxTreeItemIcon_Normal) { SetItemImage (item, GetMainColumn(), image, which); }
376     void SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal);
377 
378     // associate some data with the item
379     void SetItemData(const wxTreeItemId& item,             wxTreeItemData *data);
380     void SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data);
381 
382     // the item will be shown in bold
383     void SetItemBold(const wxTreeItemId& item,             bool bold = true);
384     void SetItemBold(const wxTreeItemId& item, int column, bool bold = true);
385 
386     // set the item's text colour
387     void SetItemTextColour(const wxTreeItemId& item,             const wxColour& colour);
388     void SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour);
389 
390     // set the item's background colour
391     void SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour);
392     void SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour);
393 
394     // set the item's font (should be of the same height for all items)
395     void SetItemFont(const wxTreeItemId& item,             const wxFont& font);
396     void SetItemFont(const wxTreeItemId& item, int column, const wxFont& font);
397 
398 
399 
400     // item status inquiries
401     // ---------------------
402 
403     // is the item visible (it might be outside the view or not expanded)?
404     bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const;
405     // does the item has any children?
406     bool HasChildren(const wxTreeItemId& item) const;
407     // is the item expanded (only makes sense if HasChildren())?
408     bool IsExpanded(const wxTreeItemId& item) const;
409     // is this item currently selected (the same as has focus)?
410     bool IsSelected(const wxTreeItemId& item) const;
411     // is item text in bold font?
412     bool IsBold(const wxTreeItemId& item)             const;
413     bool IsBold(const wxTreeItemId& item, int column) const;
414 
415 
416 
417     // set the window font
418     virtual bool SetFont( const wxFont &font );
419 
420     // set the styles.  No need to specify a GetWindowStyle here since
421     // the base wxWindow member function will do it for us
422     void SetWindowStyle(const long styles);
423 
424     // number of children
425     // ------------------
426 
427     // if 'recursively' is false, only immediate children count, otherwise
428     // the returned number is the number of all items in this branch
429     size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
430 
431     // navigation
432     // ----------
433 
434     // wxTreeItemId.IsOk() will return false if there is no such item
435 
436     // get the root tree item
GetRootItem() const437     wxTreeItemId GetRootItem() const { return m_rootItem; }  // implict cast from wxTreeListItem *
438 
439     // get the item currently selected, only if a single item is selected
GetSelection() const440     wxTreeItemId GetSelection() const { return m_selectItem; }
441 
442     // get all the items currently selected, return count of items
443     size_t GetSelections(wxArrayTreeItemIds&) const;
444 
445     // get the parent of this item (may return NULL if root)
446     wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
447 
448     // for this enumeration function you must pass in a "cookie" parameter
449     // which is opaque for the application but is necessary for the library
450     // to make these functions reentrant (i.e. allow more than one
451     // enumeration on one and the same object simultaneously). Of course,
452     // the "cookie" passed to GetFirstChild() and GetNextChild() should be
453     // the same!
454 
455     // get child of this item
456     wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
457     wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
458     wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
459     wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
460 
461     // get sibling of this item
462     wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
463     wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
464 
465     // get item in the full tree (currently only for internal use)
466     wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
467     wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
468 
469     // get expanded item, see IsExpanded()
470     wxTreeItemId GetFirstExpandedItem() const;
471     wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
472     wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
473 
474     // get visible item, see IsVisible()
475     wxTreeItemId GetFirstVisible(                          bool fullRow, bool within) const;
476     wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
477     wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
478     wxTreeItemId GetLastVisible (                          bool fullRow, bool within) const;
479 
480     // operations
481     // ----------
482 
483     // add the root node to the tree
484     wxTreeItemId AddRoot (const wxString& text,
485                           int image = -1, int selectedImage = -1,
486                           wxTreeItemData *data = NULL);
487 
488     // insert a new item in as the first child of the parent
489     wxTreeItemId PrependItem(const wxTreeItemId& parent,
490                              const wxString& text,
491                              int image = -1, int selectedImage = -1,
492                              wxTreeItemData *data = NULL);
493 
494     // insert a new item after a given one
495     wxTreeItemId InsertItem(const wxTreeItemId& parent,
496                             const wxTreeItemId& idPrevious,
497                             const wxString& text,
498                             int image = -1, int selectedImage = -1,
499                             wxTreeItemData *data = NULL);
500 
501     // insert a new item before the one with the given index
502     wxTreeItemId InsertItem(const wxTreeItemId& parent,
503                             size_t index,
504                             const wxString& text,
505                             int image = -1, int selectedImage = -1,
506                             wxTreeItemData *data = NULL);
507 
508     // insert a new item in as the last child of the parent
509     wxTreeItemId AppendItem(const wxTreeItemId& parent,
510                             const wxString& text,
511                             int image = -1, int selectedImage = -1,
512                             wxTreeItemData *data = NULL);
513 
514     // delete this item and associated data if any
515     void Delete(const wxTreeItemId& item);
516     // delete all children (but don't delete the item itself)
517     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
518     void DeleteChildren(const wxTreeItemId& item);
519     // delete the root and all its children from the tree
520     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
521     void DeleteRoot();
522 
523     void SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item);
524 
525     // expand this item
526     void Expand(const wxTreeItemId& item);
527     // expand this item and all subitems recursively
528     void ExpandAll(const wxTreeItemId& item);
529     // collapse the item without removing its children
530     void Collapse(const wxTreeItemId& item);
531     // collapse the item and remove all children
532     void CollapseAndReset(const wxTreeItemId& item);
533     // toggles the current state
534     void Toggle(const wxTreeItemId& item);
535 
536     // set cursor item (indicated by black rectangle)
537     void SetCurrentItem(const wxTreeItemId& item);
538 
539     // remove the selection from currently selected item (if any)
540     void Unselect();
541     void UnselectAll();
542     // select this item
543     bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
544                     bool unselect_others = true);
545     void SelectAll();
546     // make sure this item is visible (expanding the parent item and/or
547     // scrolling to this item if necessary)
548     void EnsureVisible(const wxTreeItemId& item);
549     // scroll to this item (but don't expand its parent)
550     void ScrollTo(const wxTreeItemId& item);
551     void AdjustMyScrollbars();
552 
553     // The first function is more portable (because easier to implement
554     // on other platforms), but the second one returns some extra info.
HitTest(const wxPoint & point)555     wxTreeItemId HitTest (const wxPoint& point)
556         { int flags; int column; return HitTest (point, flags, column); }
HitTest(const wxPoint & point,int & flags)557     wxTreeItemId HitTest (const wxPoint& point, int& flags)
558         { int column; return HitTest (point, flags, column); }
559     wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
560 
561 
562     // get the bounding rectangle of the item (or of its label only)
563     bool GetBoundingRect(const wxTreeItemId& item,
564                          wxRect& rect,
565                          bool textOnly = false) const;
566 
567     // Start editing the item label: this (temporarily) replaces the item
568     // with a one line edit control. The item will be selected if it hadn't
569     // been before.
570     void EditLabel (const wxTreeItemId& item, int column);
571     void EndEdit(bool isCancelled);
572 
573     // sorting
574     // this function is called to compare 2 items and should return -1, 0
575     // or +1 if the first item is less than, equal to or greater than the
576     // second one. The base class version performs alphabetic comparaison
577     // of item labels (GetText)
578     virtual int OnCompareItems(const wxTreeItemId& item1,
579                                const wxTreeItemId& item2);
580     // sort the children of this item using OnCompareItems
581     //
582     // NB: this function is not reentrant and not MT-safe (TODO)!
583     void SortChildren(const wxTreeItemId& item, int column, bool reverseOrder);
584 
585     // searching
586     bool MatchItemText (const wxString &itemText, const wxString &pattern, int mode);
587     wxTreeItemId FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode = 0);
588 
589     // implementation only from now on
590 
591     // overridden base class virtuals
592     virtual bool SetBackgroundColour(const wxColour& colour);
593     virtual bool SetForegroundColour(const wxColour& colour);
594 
595     // drop over item
596     void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
597 
598     // callbacks
599     void OnPaint( wxPaintEvent &event );
OnEraseBackground(wxEraseEvent & WXUNUSED (event))600     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // to reduce flicker
601     void OnSetFocus( wxFocusEvent &event );
602     void OnKillFocus( wxFocusEvent &event );
603     void OnChar( wxKeyEvent &event );
604     void OnMouse( wxMouseEvent &event );
605     void OnIdle( wxIdleEvent &event );
606     void OnScroll(wxScrollWinEvent& event);
OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))607     void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; }
608 
609     // implementation helpers
GetColumnCount() const610     int GetColumnCount() const
611     { return m_owner->GetHeaderWindow()->GetColumnCount(); }
612 
SetMainColumn(int column)613     void SetMainColumn (int column)
614     { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
615 
GetMainColumn() const616     int GetMainColumn() const { return m_main_column; }
GetCurrentColumn() const617     int GetCurrentColumn() const { return m_curColumn >= 0 ? m_curColumn : m_main_column; }
618 
619     int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
620     int GetItemWidth (int column, wxTreeListItem *item);
621 
622     void SetFocus();
623 
624 protected:
625     wxTreeListCtrl* m_owner;
626 
627     wxFont               m_normalFont;
628     wxFont               m_boldFont;
629 
630     wxTreeListItem       *m_rootItem; // root item
631     wxTreeListItem       *m_curItem; // current item, either selected or marked
632     wxTreeListItem       *m_shiftItem; // item, where the shift key was pressed
633     wxTreeListItem       *m_selectItem; // current selected item, not with wxTR_MULTIPLE
634 
635     int                  m_main_column;
636     int                  m_curColumn;
637     int                  m_sortColumn;
638     bool                 m_ReverseSortOrder;
639 
640     int                  m_btnWidth, m_btnWidth2;
641     int                  m_btnHeight, m_btnHeight2;
642     int                  m_imgWidth, m_imgWidth2;
643     int                  m_imgHeight, m_imgHeight2;
644     unsigned short       m_indent;
645     int                  m_lineHeight;
646     unsigned short       m_linespacing;
647     wxPen                m_dottedPen;
648     wxBrush             *m_hilightBrush,
649                         *m_hilightUnfocusedBrush;
650     bool                 m_hasFocus;
651 public:
652     bool                 m_dirty;
653 protected:
654     bool                 m_ownsImageListNormal,
655                          m_ownsImageListState,
656                          m_ownsImageListButtons;
657     bool                 m_lastOnSame;  // last click on the same item as prev
658     bool                 m_left_down_selection;
659 
660     wxImageList         *m_imageListNormal,
661                         *m_imageListState,
662                         *m_imageListButtons;
663 
664     bool                 m_isDragStarted;  // set at the very beginning of dragging
665     bool                 m_isDragging; // set once a drag begin event was fired
666     wxPoint              m_dragStartPos;  // set whenever m_isDragStarted is set to true
667     wxTreeListItem      *m_dragItem;
668     int                  m_dragCol;
669 
670     wxTreeListItem       *m_editItem; // item, which is currently edited
671     wxTimer             *m_editTimer;
672     bool                 m_editAccept;  // currently unused, OnRenameAccept() argument makes it redundant
673     wxString             m_editRes;
674     int                  m_editCol;
675     wxEditTextCtrl      *m_editControl;
676 
677     // char navigation
678     wxTimer             *m_findTimer;
679     wxString             m_findStr;
680 
681     bool                 m_isItemToolTip;  // true if individual item tooltips were set (disable global tooltip)
682     wxString             m_toolTip;  // global tooltip
683     wxTreeListItem      *m_toolTipItem;  // item whose tip is currently shown (NULL==global, -1==not displayed)
684 
685     // the common part of all ctors
686     void Init();
687 
688     // misc helpers
689     wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
690                               size_t previous,
691                               const wxString& text,
692                               int image, int selectedImage,
693                               wxTreeItemData *data);
694     void DoDeleteItem (wxTreeListItem *item);
695     void SetCurrentItem(wxTreeListItem *item);
HasButtons(void) const696     bool HasButtons(void) const
697         { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
698 
699     void CalculateLineHeight();
700     int  GetLineHeight(wxTreeListItem *item) const;
701     void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
702                      int x_maincol);
703     void PaintItem( wxTreeListItem *item, wxDC& dc);
704 
705     void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
706                          int x_maincol);
707     void CalculatePositions();
708     void CalculateSize( wxTreeListItem *item, wxDC &dc );
709 
710     void RefreshSubtree (wxTreeListItem *item);
711     void RefreshLine (wxTreeListItem *item);
712     // redraw all selected items
713     void RefreshSelected();
714     // RefreshSelected() recursive helper
715     void RefreshSelectedUnder (wxTreeListItem *item);
716 
717     void OnRenameTimer();
718     void OnRenameAccept(bool isCancelled);
719 
720     void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
721     bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
722     bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
723     void UnselectAllChildren (wxTreeListItem *item );
724     bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL);  // returns true if processed
725 
726 #if wxCHECK_VERSION(3,1,3)
727     void OnDpiChanged(wxDPIChangedEvent& e);
728 #endif
729 
730 private:
731     DECLARE_EVENT_TABLE()
732     DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
733 };
734 
735 
736 //-----------------------------------------------------------------------------
737 
738 // timer used for enabling in-place edit
739 class  wxTreeListRenameTimer: public wxTimer
740 {
741 public:
742     wxTreeListRenameTimer( wxTreeListMainWindow *owner );
743 
744     void Notify();
745 
746 private:
747     wxTreeListMainWindow   *m_owner;
748 };
749 
750 
751 //-----------------------------------------------------------------------------
752 
753 // control used for in-place edit
754 class  wxEditTextCtrl: public wxTextCtrl
755 {
756 public:
757     wxEditTextCtrl (wxWindow *parent,
758                     const wxWindowID id,
759                     bool *accept,
760                     wxString *res,
761                     wxTreeListMainWindow *owner,
762                     const wxString &value = wxEmptyString,
763                     const wxPoint &pos = wxDefaultPosition,
764                     const wxSize &size = wxDefaultSize,
765                     long style = 0,
766                     const wxValidator& validator = wxDefaultValidator,
767                     const wxString &name = wxTextCtrlNameStr );
768     ~wxEditTextCtrl();
769 
770     virtual bool Destroy();  // wxWindow override
771     void EndEdit(bool isCancelled);
SetOwner(wxTreeListMainWindow * owner)772     void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; }
773 
774     void OnChar( wxKeyEvent &event );
775     void OnKeyUp( wxKeyEvent &event );
776     void OnKillFocus( wxFocusEvent &event );
777 
778 
779 private:
780     wxTreeListMainWindow  *m_owner;
781     bool               *m_accept;
782     wxString           *m_res;
783     wxString            m_startValue;
784     bool                m_finished;  // true==deleting, don't process events anymore
785 
786     DECLARE_EVENT_TABLE()
787 };
788 
789 
790 //-----------------------------------------------------------------------------
791 
792 // list of per-column attributes for an item (wxTreeListItem)
793 // since there can be very many of these, we save size by chosing
794 // the smallest representation for the elements and by ordering
795 // the members to avoid padding.
796 class  wxTreeListItemCellAttr
797 {
798 public:
wxTreeListItemCellAttr()799     wxTreeListItemCellAttr() {
800         m_attr = NULL;
801         m_data = NULL;
802         m_isBold = 0;
803         m_isBoldSet = 0;
804         m_ownsAttr = 0;
805         m_image = NO_IMAGE;
806     };
~wxTreeListItemCellAttr()807     ~wxTreeListItemCellAttr() {
808         if (m_ownsAttr) delete m_attr;
809     };
810 
811     // generic attribute from wxWidgets lib
812     wxTreeItemAttr      *m_attr;
813 
814     // other attributes
815     wxTreeItemData      *m_data;        // user-provided data
816     short                m_image;       // images for the various columns (!= main)
817     int                  m_isBold :1;   // render the label in bold font
818     int                  m_isBoldSet :1;   // was 'm_isBold' set ?
819     int                  m_ownsAttr :1; // delete attribute when done
820 };
821 
822 
823 //-----------------------------------------------------------------------------
824 
825 // a tree item (NOTE: this class is storage only, does not generate events)
826 class  wxTreeListItem
827 {
828 public:
829     // ctors & dtor
830     // ------------
wxTreeListItem()831     wxTreeListItem() { m_toolTip = NULL; }
832     wxTreeListItem( wxTreeListMainWindow *owner,
833                     wxTreeListItem *parent,
834                     const wxArrayString& text,
835                     int image,
836                     int selImage,
837                     wxTreeItemData *data );
838 
839     ~wxTreeListItem();
840 
841 
842     // accessors (most properties have a default at row/item level)
843     // ---------
GetChildren()844     wxArrayTreeListItems& GetChildren() { return m_children; }
845 
846 //    const wxString GetText (          ) const { return GetText(m_owner->GetMainColumn());  }
GetText(int column) const847     const wxString GetText (int column) const
848     {
849         if ( IsVirtual() )   return m_owner->GetItemText( m_props_row.m_data, column );
850         if (column < (signed)m_text.GetCount()) return m_text[column];
851         return wxEmptyString;
852     };
853 
GetImage(wxTreeItemIcon which=wxTreeItemIcon_Normal) const854     int GetImage (            wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; };
GetImage(int column,wxTreeItemIcon which=wxTreeItemIcon_Normal) const855     int GetImage (int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const
856     {
857         // main column is special, more images available
858         if(column == m_owner->GetMainColumn()) return m_images[which];
859 
860         // other columns ignore the 'which' parameter
861         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
862         if (entry == m_props_cell.end()) return NO_IMAGE;
863         return entry->second->m_image;
864     };
865 
866     // data is special: it has a default value at row/item level
GetData() const867     wxTreeItemData *GetData()           const { return m_props_row.m_data; };
GetData(int column) const868     wxTreeItemData *GetData(int column) const {
869         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
870         if (entry == m_props_cell.end()) return NULL;
871         return entry->second->m_data;
872     };
873 
GetToolTip() const874     const wxString * GetToolTip() const  {  return m_toolTip;  };
875 
876     // returns the current image for the item (depending on its
877     // selected/expanded/whatever state)
878     int GetCurrentImage() const;
879 
880 
881     // modifiers (most properties have a default at row/item level)
882     // ---------
SetHasPlus(bool has=true)883     void SetHasPlus(bool has = true) { m_hasPlus = has; };
884 
SetText(int column,const wxString & text)885     void SetText (int column, const wxString& text)
886     {
887         if (column < (int)m_text.GetCount()) {
888             m_text[column] = text;
889         } else if (column < m_owner->GetColumnCount()) {
890             int howmany = m_owner->GetColumnCount();
891             for (int i = (int)m_text.GetCount(); i < howmany; ++i)
892             {
893                 m_text.Add(wxEmptyString);
894                 m_text_x.Add(0);
895             };
896             m_text[column] = text;
897         }
898     };
SetImage(int image,wxTreeItemIcon which)899     void SetImage (            int image, wxTreeItemIcon which) { m_images[which] = image; };
SetImage(int column,int image,wxTreeItemIcon which)900     void SetImage (int column, int image, wxTreeItemIcon which)
901     {
902         // main column is special, more images available
903         if (column == m_owner->GetMainColumn()) m_images[which] = image;
904         // other columns ignore the 'which' parameter
905         else {
906             wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
907             if (entry == m_props_cell.end()) {
908                 m_props_cell[column] = new wxTreeListItemCellAttr();
909                 m_props_cell[column]->m_image = image;
910             } else {
911                 entry->second->m_image = image;
912             }
913         }
914     };
915 
916     // data is special: it has a default value at row/item level
SetData(wxTreeItemData * data)917     void SetData(            wxTreeItemData *data) { m_props_row.m_data = data; };
SetData(int column,wxTreeItemData * data)918     void SetData(int column, wxTreeItemData *data)
919     {
920         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
921         if (entry == m_props_cell.end()) {
922             m_props_cell[column] = new wxTreeListItemCellAttr();
923             m_props_cell[column]->m_data = data;
924         } else {
925             entry->second->m_data = data;
926         }
927     }
928 
SetBold(bool bold)929     void SetBold(            bool bold) { m_props_row.m_isBold = bold; }
SetBold(int column,bool bold)930     void SetBold(int column, bool bold)
931     {
932         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
933         if (entry == m_props_cell.end()) {
934             m_props_cell[column] = new wxTreeListItemCellAttr();
935             m_props_cell[column]->m_isBold = bold;
936             m_props_cell[column]->m_isBoldSet = 1;
937         } else {
938             entry->second->m_isBold = bold;
939             entry->second->m_isBoldSet = 1;
940         }
941     }
942 
943 
SetToolTip(const wxString & tip)944     void SetToolTip(const wxString &tip) {
945         if (m_toolTip)  { delete m_toolTip; m_toolTip = NULL; }
946         if (tip.length() > 0) { m_toolTip = new wxString(tip); }
947     };
948 
949 
950     // status inquiries
951     // ----------------
HasChildren() const952     bool HasChildren() const        { return !m_children.IsEmpty(); }
IsSelected() const953     bool IsSelected()  const        { return m_hasHilight != 0; }
IsExpanded() const954     bool IsExpanded()  const        { return !m_isCollapsed; }
HasPlus() const955     bool HasPlus()     const        { return m_hasPlus || HasChildren(); }
IsBold() const956     bool IsBold()      const        { return m_props_row.m_isBold != 0; }
IsBold(int column) const957     bool IsBold(int column) const
958     {
959         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
960         if (entry == m_props_cell.end() || ! entry->second->m_isBoldSet) return IsBold();
961         return (entry->second->m_isBold != 0);
962     }
IsVirtual() const963     bool IsVirtual()   const        { return m_owner->IsVirtual(); }
964 
965 
966 
GetX() const967     int GetX() const { return m_x; }
GetY() const968     int GetY() const { return m_y; }
969 
SetX(int x)970     void SetX (int x) { m_x = x; }
SetY(int y)971     void SetY (int y) { m_y = y; }
972 
GetHeight() const973     int  GetHeight() const { return m_height; }
GetWidth() const974     int  GetWidth()  const { return m_width; }
975 
SetHeight(int height)976     void SetHeight (int height) { m_height = height; }
SetWidth(int width)977     void SetWidth (int width) { m_width = width; }
978 
GetTextX(int column) const979     int GetTextX(int column) const
980     {
981         if (column >=0 && column < (signed)m_text_x.GetCount())
982         {
983             return m_text_x[column];
984         };
985         return 0;
986     }
SetTextX(int column,int text_x)987     void SetTextX (int column, int text_x) { if (column >=0 && column < (signed)m_text_x.GetCount()) m_text_x[column] = text_x; }
988 
GetItemParent() const989     wxTreeListItem *GetItemParent() const { return m_parent; }
SetItemParent(wxTreeListItem * parent)990     void SetItemParent(wxTreeListItem *parent) { m_parent = parent; }
991 
992     // get count of all children (and grand children if 'recursively')
993     size_t GetChildrenCount(bool recursively = true) const;
994 
995     void GetSize( int &x, int &y, const wxTreeListMainWindow* );
996 
997     // return the item at given position (or NULL if no item), onButton is
998     // true if the point belongs to the item's button, otherwise it lies
999     // on the button's label
1000     wxTreeListItem *HitTest (const wxPoint& point,
1001                              const wxTreeListMainWindow *,
1002                              int &flags, int& column, int level);
1003 
1004 
1005     // operations
1006     // ----------
1007     // deletes all children
1008     void DeleteChildren();
1009 
Insert(wxTreeListItem * child,size_t index)1010     void Insert(wxTreeListItem *child, size_t index)
1011     { m_children.Insert(child, index); }
1012 
Expand()1013     void Expand() { m_isCollapsed = false; }
Collapse()1014     void Collapse() { m_isCollapsed = true; }
1015 
SetHilight(bool set=true)1016     void SetHilight( bool set = true ) { m_hasHilight = set; }
1017 
1018 
1019     // attributes
1020     // ----------
1021 
1022     // get them - may be NULL (used to read attributes)
1023     // NOTE: fall back on default at row/item level is not defined for cell
GetAttributes(int column) const1024     wxTreeItemAttr *GetAttributes(int column) const
1025     {
1026         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1027         if (entry == m_props_cell.end()) return GetAttributes();
1028         return entry->second->m_attr;
1029     }
GetAttributes() const1030     wxTreeItemAttr *GetAttributes() const { return m_props_row.m_attr; }
1031 
1032     // get them ensuring that the pointer is not NULL (used to write attributes)
Attr(int column)1033     wxTreeItemAttr& Attr(int column) {
1034         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
1035         if (entry == m_props_cell.end()) {
1036             m_props_cell[column] = new wxTreeListItemCellAttr();
1037             m_props_cell[column]->m_attr = new wxTreeItemAttr;
1038             m_props_cell[column]->m_ownsAttr = 1;
1039             return *(m_props_cell[column]->m_attr);
1040         } else {
1041             return *(entry->second->m_attr);
1042         }
1043     }
Attr()1044     wxTreeItemAttr& Attr()
1045     {
1046         if ( !m_props_row.m_attr )
1047         {
1048             m_props_row.m_attr = new wxTreeItemAttr;
1049             m_props_row.m_ownsAttr = 1;
1050         }
1051         return *m_props_row.m_attr;
1052     }
1053 /* ----- unused -----
1054     // set them
1055     void SetAttributes(wxTreeItemAttr *attr)
1056     {
1057         if ( m_props_row.m_ownsAttr ) delete m_props_row.m_attr;
1058         m_props_row.m_attr = attr;
1059         m_props_row.m_ownsAttr = 0;
1060     }
1061     // set them and delete when done
1062     void AssignAttributes(wxTreeItemAttr *attr)
1063     {
1064         SetAttributes(attr);
1065         m_props_row.m_ownsAttr = 1;
1066     }
1067 */
1068 
1069 private:
1070     wxTreeListMainWindow       *m_owner;        // control the item belongs to
1071 
1072     wxArrayTreeListItems        m_children;     // list of children
1073     wxTreeListItem             *m_parent;       // parent of this item
1074 
1075     // main column item positions
1076     wxCoord                     m_x;            // (virtual) offset from left (vertical line)
1077     wxCoord                     m_y;            // (virtual) offset from top
1078     short                       m_width;        // width of this item
1079     unsigned char               m_height;       // height of this item
1080 
1081     // for the normal, selected, expanded and expanded+selected states
1082     short                       m_images[wxTreeItemIcon_Max];
1083     // currently there is no tooltip at cell level
1084     wxString                   *m_toolTip;
1085 
1086     // use bitfields to save size
1087     int                         m_isCollapsed :1;
1088     int                         m_hasHilight  :1; // same as focused
1089     int                         m_hasPlus     :1; // used for item which doesn't have
1090                                                     // children but has a [+] button
1091 
1092     // here are all the properties which can be set per column
1093     wxArrayString               m_text;        // labels to be rendered for item
1094     wxArrayLong                 m_text_x;
1095     wxTreeListItemCellAttr      m_props_row;   // default at row/item level for: data, attr
1096     wxTreeListItemCellAttrHash  m_props_cell;
1097 };
1098 
1099 
1100 // ===========================================================================
1101 // implementation
1102 // ===========================================================================
1103 
1104 // ---------------------------------------------------------------------------
1105 // wxTreeListRenameTimer (internal)
1106 // ---------------------------------------------------------------------------
1107 
wxTreeListRenameTimer(wxTreeListMainWindow * owner)1108 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
1109 {
1110     m_owner = owner;
1111 }
1112 
Notify()1113 void wxTreeListRenameTimer::Notify()
1114 {
1115     m_owner->OnRenameTimer();
1116 }
1117 
1118 //-----------------------------------------------------------------------------
1119 // wxEditTextCtrl (internal)
1120 //-----------------------------------------------------------------------------
1121 
BEGIN_EVENT_TABLE(wxEditTextCtrl,wxTextCtrl)1122 BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
1123     EVT_CHAR           (wxEditTextCtrl::OnChar)
1124     EVT_KEY_UP         (wxEditTextCtrl::OnKeyUp)
1125     EVT_KILL_FOCUS     (wxEditTextCtrl::OnKillFocus)
1126 END_EVENT_TABLE()
1127 
1128 wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
1129                                 const wxWindowID id,
1130                                 bool *accept,
1131                                 wxString *res,
1132                                 wxTreeListMainWindow *owner,
1133                                 const wxString &value,
1134                                 const wxPoint &pos,
1135                                 const wxSize &size,
1136                                 long style,
1137                                 const wxValidator& validator,
1138                                 const wxString &name)
1139     : wxTextCtrl (parent, id, value, pos, size, style | wxSIMPLE_BORDER | wxTE_PROCESS_ENTER, validator, name)
1140 {
1141     m_res = res;
1142     m_accept = accept;
1143     m_owner = owner;
1144     (*m_accept) = false;
1145     (*m_res) = wxEmptyString;
1146     m_startValue = value;
1147     m_finished = false;
1148 }
1149 
~wxEditTextCtrl()1150 wxEditTextCtrl::~wxEditTextCtrl() {
1151     EndEdit(true); // cancelled
1152 }
1153 
EndEdit(bool isCancelled)1154 void wxEditTextCtrl::EndEdit(bool isCancelled) {
1155     if (m_finished) return;
1156     m_finished = true;
1157 
1158     if (m_owner) {
1159         (*m_accept) = ! isCancelled;
1160         (*m_res) = isCancelled ? m_startValue : GetValue();
1161         m_owner->OnRenameAccept(*m_res == m_startValue);
1162         m_owner->m_editControl = NULL;
1163         m_owner->m_editItem = NULL;
1164         m_owner->SetFocus(); // This doesn't work. TODO.
1165         m_owner = NULL;
1166     }
1167 
1168     Destroy();
1169 }
1170 
Destroy()1171 bool wxEditTextCtrl::Destroy() {
1172     Hide();
1173     wxTheApp->ScheduleForDestruction(this);
1174     return true;
1175 }
1176 
OnChar(wxKeyEvent & event)1177 void wxEditTextCtrl::OnChar( wxKeyEvent &event )
1178 {
1179     if (m_finished)
1180     {
1181         event.Skip();
1182         return;
1183     }
1184     if (event.GetKeyCode() == WXK_RETURN)
1185     {
1186         EndEdit(false);  // not cancelled
1187         return;
1188     }
1189     if (event.GetKeyCode() == WXK_ESCAPE)
1190     {
1191         EndEdit(true);  // cancelled
1192         return;
1193     }
1194     event.Skip();
1195 }
1196 
OnKeyUp(wxKeyEvent & event)1197 void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
1198 {
1199     if (m_finished)
1200     {
1201         event.Skip();
1202         return;
1203     }
1204 
1205     // auto-grow the textctrl:
1206     wxSize parentSize = m_owner->GetSize();
1207     wxPoint myPos = GetPosition();
1208     wxSize mySize = GetSize();
1209     int sx, sy;
1210     GetTextExtent(GetValue() + _T("M"), &sx, &sy);
1211     if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
1212     if (mySize.x > sx) sx = mySize.x;
1213     SetSize(sx, -1);
1214 
1215     event.Skip();
1216 }
1217 
OnKillFocus(wxFocusEvent & event)1218 void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
1219 {
1220     if (m_finished)
1221     {
1222         event.Skip();
1223         return;
1224     }
1225 
1226     EndEdit(false);  // not cancelled
1227 }
1228 
1229 //-----------------------------------------------------------------------------
1230 //  wxTreeListHeaderWindow
1231 //-----------------------------------------------------------------------------
1232 
1233 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow);
1234 
BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)1235 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
1236     EVT_PAINT         (wxTreeListHeaderWindow::OnPaint)
1237     EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground) // reduce flicker
1238     EVT_MOUSE_EVENTS  (wxTreeListHeaderWindow::OnMouse)
1239     EVT_SET_FOCUS     (wxTreeListHeaderWindow::OnSetFocus)
1240 END_EVENT_TABLE()
1241 
1242 
1243 void wxTreeListHeaderWindow::Init()
1244 {
1245     m_currentCursor = (wxCursor *) NULL;
1246     m_isDragging = false;
1247     m_dirty = false;
1248     m_total_col_width = 0;
1249     m_hotTrackCol = -1;
1250 
1251     // prevent any background repaint in order to reducing flicker
1252     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1253 }
1254 
wxTreeListHeaderWindow()1255 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
1256 {
1257     Init();
1258 
1259     m_owner = (wxTreeListMainWindow *) NULL;
1260     m_resizeCursor = (wxCursor *) NULL;
1261 }
1262 
wxTreeListHeaderWindow(wxWindow * win,wxWindowID id,wxTreeListMainWindow * owner,const wxPoint & pos,const wxSize & size,long style,const wxString & name)1263 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
1264                                                 wxWindowID id,
1265                                                 wxTreeListMainWindow *owner,
1266                                                 const wxPoint& pos,
1267                                                 const wxSize& size,
1268                                                 long style,
1269                                                 const wxString &name )
1270     : wxWindow( win, id, pos, size, style, name )
1271 {
1272     Init();
1273 
1274     m_owner = owner;
1275     m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
1276 
1277     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
1278 }
1279 
~wxTreeListHeaderWindow()1280 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
1281 {
1282     delete m_resizeCursor;
1283 }
1284 
DoDrawRect(wxDC * dc,int x,int y,int w,int h)1285 void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
1286 {
1287     wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxPENSTYLE_SOLID);
1288     const int m_corner = 1;
1289 
1290     dc->SetBrush( *wxTRANSPARENT_BRUSH );
1291 #if defined( __WXMAC__  )
1292     dc->SetPen (pen);
1293 #else // !GTK, !Mac
1294     dc->SetPen( *wxBLACK_PEN );
1295 #endif
1296     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
1297     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
1298 
1299 #if defined( __WXMAC__  )
1300     pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
1301 #endif
1302     dc->SetPen( pen );
1303     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
1304     dc->DrawRectangle( x+1, y+h-1, w-2, 1 );      // bottom (inner)
1305 
1306     dc->SetPen( *wxWHITE_PEN );
1307     dc->DrawRectangle( x, y, w-m_corner+1, 1 );   // top (outer)
1308     dc->DrawRectangle( x, y, 1, h );              // left (outer)
1309     dc->DrawLine( x, y+h-1, x+1, y+h-1 );
1310     dc->DrawLine( x+w-1, y, x+w-1, y+1 );
1311 }
1312 
1313 // shift the DC origin to match the position of the main window horz
1314 // scrollbar: this allows us to always use logical coords
AdjustDC(wxDC & dc)1315 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
1316 {
1317     int xpix;
1318     m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
1319     int x;
1320     m_owner->GetViewStart( &x, NULL );
1321 
1322     // account for the horz scrollbar offset
1323     dc.SetDeviceOrigin( -x * xpix, 0 );
1324 }
1325 
OnPaint(wxPaintEvent & WXUNUSED (event))1326 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
1327 {
1328     wxAutoBufferedPaintDC dc( this );
1329     AdjustDC( dc );
1330 
1331     int x = HEADER_OFFSET_X;
1332 
1333     // width and height of the entire header window
1334     int w, h;
1335     GetClientSize( &w, &h );
1336     m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1337     dc.SetBackgroundMode(wxTRANSPARENT);
1338 
1339     int numColumns = GetColumnCount();
1340     for ( int i = 0; i < numColumns && x < w; i++ )
1341     {
1342         if (!IsColumnShown (i)) continue; // do next column if not shown
1343 
1344         wxHeaderButtonParams params;
1345 
1346         // TODO: columnInfo should have label colours...
1347         params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
1348         params.m_labelFont = GetFont();
1349 
1350         wxTreeListColumnInfo& column = GetColumn(i);
1351         int wCol = column.GetWidth();
1352         int flags = 0;
1353         wxRect rect(x, 0, wCol, h);
1354         x += wCol;
1355 
1356         if ( i == m_hotTrackCol)
1357             flags |= wxCONTROL_CURRENT;
1358 
1359         params.m_labelText = column.GetText();
1360         params.m_labelAlignment = column.GetAlignment();
1361 
1362         int image = column.GetImage();
1363         wxImageList* imageList = m_owner->GetImageList();
1364         if ((image != -1) && imageList)
1365             params.m_labelBitmap = imageList->GetBitmap(image);
1366 
1367         wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, &params);
1368     }
1369 
1370     if (x < w) {
1371         wxRect rect(x, 0, w-x, h);
1372         wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
1373     }
1374 
1375 }
1376 
DrawCurrent()1377 void wxTreeListHeaderWindow::DrawCurrent()
1378 {
1379     int x1 = m_currentX;
1380     int y1 = 0;
1381     ClientToScreen (&x1, &y1);
1382 
1383     int x2 = m_currentX-1;
1384 #ifdef __WXMSW__
1385     ++x2; // but why ????
1386 #endif
1387     int y2 = 0;
1388     m_owner->GetClientSize( NULL, &y2 );
1389     m_owner->ClientToScreen( &x2, &y2 );
1390 
1391     wxScreenDC dc;
1392     dc.SetLogicalFunction (wxINVERT);
1393     dc.SetPen (wxPen (*wxBLACK, 2, wxPENSTYLE_SOLID));
1394     dc.SetBrush (*wxTRANSPARENT_BRUSH);
1395 
1396     AdjustDC(dc);
1397     dc.DrawLine (x1, y1, x2, y2);
1398     dc.SetLogicalFunction (wxCOPY);
1399     dc.SetPen (wxNullPen);
1400     dc.SetBrush (wxNullBrush);
1401 }
1402 
XToCol(int x)1403 int wxTreeListHeaderWindow::XToCol(int x)
1404 {
1405     int colLeft = 0;
1406     int numColumns = GetColumnCount();
1407     for ( int col = 0; col < numColumns; col++ )
1408     {
1409         if (!IsColumnShown(col)) continue;
1410         wxTreeListColumnInfo& column = GetColumn(col);
1411 
1412         if ( x < (colLeft + column.GetWidth()) )
1413              return col;
1414 
1415         colLeft += column.GetWidth();
1416     }
1417     return -1;
1418 }
1419 
RefreshColLabel(int col)1420 void wxTreeListHeaderWindow::RefreshColLabel(int col)
1421 {
1422     if ( col > GetColumnCount() )
1423         return;
1424 
1425     int x = 0;
1426     int width = 0;
1427     int idx = 0;
1428     do {
1429         if (!IsColumnShown(idx)) continue;
1430         wxTreeListColumnInfo& column = GetColumn(idx);
1431         x += width;
1432         width = column.GetWidth();
1433     } while (++idx <= col);
1434 
1435     m_owner->CalcScrolledPosition(x, 0, &x, NULL);
1436     RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
1437 }
1438 
OnMouse(wxMouseEvent & event)1439 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
1440 
1441     // we want to work with logical coords
1442     int x;
1443     m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
1444 
1445     const int col = XToCol(x);
1446     if(col>=0 && col<GetColumnCount())
1447     {
1448         SetToolTip(m_columns[col].GetTooltip());
1449     }
1450     else
1451     {
1452         SetToolTip(wxEmptyString);
1453     };
1454     if ( event.Moving() )
1455     {
1456         if ( col != m_hotTrackCol )
1457         {
1458             // Refresh the col header so it will be painted with hot tracking
1459             // (if supported by the native renderer.)
1460             RefreshColLabel(col);
1461 
1462             // Also refresh the old hot header
1463             if ( m_hotTrackCol >= 0 )
1464                 RefreshColLabel(m_hotTrackCol);
1465 
1466             m_hotTrackCol = col;
1467         }
1468     }
1469 
1470     if ( event.Leaving() && m_hotTrackCol >= 0 )
1471     {
1472         // Leaving the window so clear any hot tracking indicator that may be present
1473         RefreshColLabel(m_hotTrackCol);
1474         m_hotTrackCol = -1;
1475     }
1476 
1477     if (m_isDragging) {
1478 
1479         SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
1480 
1481         // we don't draw the line beyond our window, but we allow dragging it
1482         // there
1483         int w = 0;
1484         GetClientSize( &w, NULL );
1485         m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
1486         w -= 6;
1487 
1488         // erase the line if it was drawn
1489         if (m_currentX < w) DrawCurrent();
1490 
1491         if (event.ButtonUp()) {
1492             m_isDragging = false;
1493             if (HasCapture()) ReleaseMouse();
1494             m_dirty = true;
1495             SetColumnWidth (m_column, m_currentX - m_minX);
1496             Refresh();
1497             SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
1498         }else{
1499             m_currentX = wxMax (m_minX + 7, x);
1500 
1501             // draw in the new location
1502             if (m_currentX < w) DrawCurrent();
1503         }
1504 
1505     }else{ // not dragging
1506 
1507         m_minX = 0;
1508         bool hit_border = false;
1509 
1510         // end of the current column
1511         int xpos = 0;
1512 
1513         // find the column where this event occurred
1514         int countCol = GetColumnCount();
1515         for (int column = 0; column < countCol; column++) {
1516             if (!IsColumnShown (column)) continue; // do next if not shown
1517 
1518             xpos += GetColumnWidth (column);
1519             m_column = column;
1520             if (abs (x-xpos) < 3) {
1521                 // near the column border
1522                 hit_border = true;
1523                 break;
1524             }
1525 
1526             if (x < xpos) {
1527                 // inside the column
1528                 break;
1529             }
1530 
1531             m_minX = xpos;
1532         }
1533 
1534         if (event.LeftDown() || event.RightUp()) {
1535             m_owner->EndEdit(true);  // cancelled
1536 
1537             if (hit_border && event.LeftDown()) {
1538                 m_isDragging = true;
1539                 CaptureMouse();
1540                 m_currentX = x;
1541                 DrawCurrent();
1542                 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
1543             }else{ // click on a column
1544                 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
1545                                                     wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
1546                 SendListEvent (evt, event.GetPosition());
1547             }
1548         }else if (event.LeftDClick() && hit_border) {
1549             SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
1550             Refresh();
1551 
1552         }else if (event.Moving()) {
1553             bool setCursor;
1554             if (hit_border) {
1555                 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
1556                 m_currentCursor = m_resizeCursor;
1557             }else{
1558                 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
1559                 m_currentCursor = wxSTANDARD_CURSOR;
1560             }
1561             if (setCursor) SetCursor (*m_currentCursor);
1562         }
1563 
1564     }
1565 }
1566 
OnSetFocus(wxFocusEvent & WXUNUSED (event))1567 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
1568     m_owner->SetFocus();
1569 }
1570 
SendListEvent(wxEventType type,wxPoint pos)1571 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
1572     wxWindow *parent = GetParent();
1573     wxListEvent le (type, parent->GetId());
1574     le.SetEventObject (parent);
1575     le.m_pointDrag = pos;
1576 
1577     // the position should be relative to the parent window, not
1578     // this one for compatibility with MSW and common sense: the
1579     // user code doesn't know anything at all about this header
1580     // window, so why should it get positions relative to it?
1581     le.m_pointDrag.y -= GetSize().y;
1582     le.m_col = m_column;
1583     parent->GetEventHandler()->ProcessEvent (le);
1584 }
1585 
AddColumn(const wxTreeListColumnInfo & colInfo)1586 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
1587     m_columns.Add (colInfo);
1588     m_total_col_width += colInfo.GetWidth();
1589     m_owner->AdjustMyScrollbars();
1590     m_owner->m_dirty = true;
1591 }
1592 
SetColumnWidth(int column,int width)1593 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
1594     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1595     m_total_col_width -= m_columns[column].GetWidth();
1596     m_columns[column].SetWidth(width);
1597     m_total_col_width += m_columns[column].GetWidth();
1598     m_owner->AdjustMyScrollbars();
1599     m_owner->m_dirty = true;
1600 }
1601 
InsertColumn(int before,const wxTreeListColumnInfo & colInfo)1602 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
1603     wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
1604     m_columns.Insert (colInfo, before);
1605     m_total_col_width += colInfo.GetWidth();
1606     m_owner->AdjustMyScrollbars();
1607     m_owner->m_dirty = true;
1608 }
1609 
RemoveColumn(int column)1610 void wxTreeListHeaderWindow::RemoveColumn (int column) {
1611     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1612     m_total_col_width -= m_columns[column].GetWidth();
1613     m_columns.RemoveAt (column);
1614     m_owner->AdjustMyScrollbars();
1615     m_owner->m_dirty = true;
1616 }
1617 
SetColumn(int column,const wxTreeListColumnInfo & info)1618 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
1619     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
1620     int w = m_columns[column].GetWidth();
1621     m_columns[column] = info;
1622     if (w != info.GetWidth()) {
1623         m_total_col_width -= w;
1624         m_total_col_width += info.GetWidth();
1625         m_owner->AdjustMyScrollbars();
1626     }
1627     m_owner->m_dirty = true;
1628 }
1629 
1630 // ---------------------------------------------------------------------------
1631 // wxTreeListItem
1632 // ---------------------------------------------------------------------------
1633 
wxTreeListItem(wxTreeListMainWindow * owner,wxTreeListItem * parent,const wxArrayString & text,int image,int selImage,wxTreeItemData * data)1634 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
1635                                 wxTreeListItem *parent,
1636                                 const wxArrayString& text,
1637                                 int image, int selImage,
1638                                 wxTreeItemData *data)
1639               : m_text (text) {
1640 
1641     m_images[wxTreeItemIcon_Normal] = image;
1642     m_images[wxTreeItemIcon_Selected] = selImage;
1643     m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
1644     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
1645 
1646     m_props_row.m_data = data;
1647     m_toolTip = NULL;
1648     m_x = 0;
1649     m_y = 0;
1650     m_text_x.resize(m_text.GetCount(), 0);
1651 
1652     m_isCollapsed = true;
1653     m_hasHilight = false;
1654     m_hasPlus = false;
1655 
1656     m_owner = owner;
1657     m_parent = parent;
1658 
1659     // We don't know the height here yet.
1660     m_width = 0;
1661     m_height = 0;
1662 }
1663 
~wxTreeListItem()1664 wxTreeListItem::~wxTreeListItem() {
1665     if (m_toolTip) delete m_toolTip;
1666 
1667     wxTreeListItemCellAttrHash::iterator entry = m_props_cell.begin();
1668     while (entry != m_props_cell.end()) {
1669         if (entry->second) delete entry->second;
1670         ++entry;
1671     }
1672 
1673     wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
1674 }
1675 
DeleteChildren()1676 void wxTreeListItem::DeleteChildren () {
1677     m_children.Empty();
1678 }
1679 
GetChildrenCount(bool recursively) const1680 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
1681     size_t count = m_children.Count();
1682     if (!recursively) return count;
1683 
1684     size_t total = count;
1685     for (size_t n = 0; n < count; ++n) {
1686         total += m_children[n]->GetChildrenCount();
1687     }
1688     return total;
1689 }
1690 
GetSize(int & x,int & y,const wxTreeListMainWindow * theButton)1691 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
1692     int bottomY = m_y + theButton->GetLineHeight (this);
1693     if (y < bottomY) y = bottomY;
1694     int width = m_x +  GetWidth();
1695     if ( x < width ) x = width;
1696 
1697     if (IsExpanded()) {
1698         size_t count = m_children.Count();
1699         for (size_t n = 0; n < count; ++n ) {
1700             m_children[n]->GetSize (x, y, theButton);
1701         }
1702     }
1703 }
1704 
HitTest(const wxPoint & point,const wxTreeListMainWindow * theCtrl,int & flags,int & column,int level)1705 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
1706                                          const wxTreeListMainWindow *theCtrl,
1707                                          int &flags, int& column, int level) {
1708 
1709     // reset any previous hit infos
1710     flags = 0;
1711     column = -1;
1712 
1713     // for a hidden root node, don't evaluate it, but do evaluate children
1714     if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
1715 
1716         wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
1717 
1718         // check for right of all columns (outside)
1719         if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
1720         // else find column
1721         for (int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) {
1722             if (!header_win->IsColumnShown(j)) continue;
1723             int w = header_win->GetColumnWidth (j);
1724             if (point.x >= x && point.x < x+w) {
1725                 column = j;
1726                 break;
1727             }
1728             x += w;
1729         }
1730 
1731         // evaluate if y-pos is okay
1732         int h = theCtrl->GetLineHeight (this);
1733         if ((point.y >= m_y) && (point.y <= m_y + h)) {
1734 
1735             // check for above/below middle
1736             int y_mid = m_y + h/2;
1737             if (point.y < y_mid) {
1738                 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
1739             }else{
1740                 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
1741             }
1742 
1743             // check for button hit
1744             if (HasPlus() && theCtrl->HasButtons()) {
1745                 int bntX = m_x - theCtrl->m_btnWidth2;
1746                 int bntY = y_mid - theCtrl->m_btnHeight2;
1747                 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
1748                     (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
1749                     flags |= wxTREE_HITTEST_ONITEMBUTTON;
1750                     return this;
1751                 }
1752             }
1753 
1754             // check for image hit
1755             if (theCtrl->m_imgWidth > 0) {
1756                 int imgX = GetTextX(column) - theCtrl->m_imgWidth - MARGIN;
1757                 int imgY = y_mid - theCtrl->m_imgHeight2;
1758                 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
1759                     (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
1760                     flags |= wxTREE_HITTEST_ONITEMICON;
1761                     return this;
1762                 }
1763             }
1764 
1765             // check for label hit
1766             if ((point.x >= GetTextX(column)) && (point.x <= (GetTextX(column) + GetWidth()))) {
1767                 flags |= wxTREE_HITTEST_ONITEMLABEL;
1768                 return this;
1769             }
1770 
1771             // check for indent hit after button and image hit
1772             if (point.x < m_x) {
1773                 flags |= wxTREE_HITTEST_ONITEMINDENT;
1774                 return this;
1775             }
1776 
1777             // check for right of label
1778             int end = 0;
1779             for (int i = 0; i <= theCtrl->GetMainColumn(); ++i) end += header_win->GetColumnWidth (i);
1780             if ((point.x > (GetTextX(column) + GetWidth())) && (point.x <= end)) {
1781                 flags |= wxTREE_HITTEST_ONITEMRIGHT;
1782                 return this;
1783             }
1784 
1785             // else check for each column except main
1786             if (column >= 0 && column != theCtrl->GetMainColumn()) {
1787                 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
1788                 return this;
1789             }
1790 
1791             // no special flag or column found
1792             return this;
1793 
1794         }
1795 
1796         // if children not expanded, return no item
1797         if (!IsExpanded()) return (wxTreeListItem*) NULL;
1798     }
1799 
1800     // in any case evaluate children
1801     wxTreeListItem *child;
1802     size_t count = m_children.Count();
1803     for (size_t n = 0; n < count; n++) {
1804         child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
1805         if (child) return child;
1806     }
1807 
1808     // not found
1809     return (wxTreeListItem*) NULL;
1810 }
1811 
GetCurrentImage() const1812 int wxTreeListItem::GetCurrentImage() const {
1813     int image = NO_IMAGE;
1814     if (IsExpanded()) {
1815         if (IsSelected()) {
1816             image = GetImage (wxTreeItemIcon_SelectedExpanded);
1817         }else{
1818             image = GetImage (wxTreeItemIcon_Expanded);
1819         }
1820     }else{ // not expanded
1821         if (IsSelected()) {
1822             image = GetImage (wxTreeItemIcon_Selected);
1823         }else{
1824             image = GetImage (wxTreeItemIcon_Normal);
1825         }
1826     }
1827 
1828     // maybe it doesn't have the specific image, try the default one instead
1829     if (image == NO_IMAGE) image = GetImage();
1830 
1831     return image;
1832 }
1833 
1834 // ---------------------------------------------------------------------------
1835 // wxTreeListMainWindow implementation
1836 // ---------------------------------------------------------------------------
1837 
IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow,wxScrolledWindow)1838 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
1839 
1840 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
1841     EVT_PAINT          (wxTreeListMainWindow::OnPaint)
1842     EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground) // to reduce flicker
1843     EVT_MOUSE_EVENTS   (wxTreeListMainWindow::OnMouse)
1844     EVT_CHAR           (wxTreeListMainWindow::OnChar)
1845     EVT_SET_FOCUS      (wxTreeListMainWindow::OnSetFocus)
1846     EVT_KILL_FOCUS     (wxTreeListMainWindow::OnKillFocus)
1847     EVT_IDLE           (wxTreeListMainWindow::OnIdle)
1848     EVT_SCROLLWIN      (wxTreeListMainWindow::OnScroll)
1849     EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost)
1850 #if wxCHECK_VERSION(3,1,3)
1851     EVT_DPI_CHANGED(wxTreeListMainWindow::OnDpiChanged)
1852 #endif
1853 END_EVENT_TABLE()
1854 
1855 
1856 // ---------------------------------------------------------------------------
1857 // construction/destruction
1858 // ---------------------------------------------------------------------------
1859 
1860 
1861 void wxTreeListMainWindow::Init() {
1862 
1863     m_rootItem = (wxTreeListItem*)NULL;
1864     m_curItem = (wxTreeListItem*)NULL;
1865     m_shiftItem = (wxTreeListItem*)NULL;
1866     m_editItem = (wxTreeListItem*)NULL;
1867     m_selectItem = (wxTreeListItem*)NULL;
1868 
1869     m_curColumn = -1; // no current column
1870 
1871     m_hasFocus = false;
1872     m_dirty = false;
1873 
1874     m_lineHeight = LINEHEIGHT;
1875     m_indent = MININDENT; // min. indent
1876     m_linespacing = 4;
1877 
1878     m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxBRUSHSTYLE_SOLID);
1879     m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxBRUSHSTYLE_SOLID);
1880 
1881     m_imageListNormal = (wxImageList *) NULL;
1882     m_imageListButtons = (wxImageList *) NULL;
1883     m_imageListState = (wxImageList *) NULL;
1884     m_ownsImageListNormal = m_ownsImageListButtons =
1885     m_ownsImageListState = false;
1886 
1887     m_imgWidth = 0, m_imgWidth2 = 0;
1888     m_imgHeight = 0, m_imgHeight2 = 0;
1889     m_btnWidth = 0, m_btnWidth2 = 0;
1890     m_btnHeight = 0, m_btnHeight2 = 0;
1891 
1892     m_isDragStarted = m_isDragging = false;
1893     m_dragItem = NULL;
1894     m_dragCol = -1;
1895 
1896     m_editTimer = new wxTreeListRenameTimer (this);
1897     m_editControl = NULL;
1898 
1899     m_lastOnSame = false;
1900     m_left_down_selection = false;
1901 
1902     m_findTimer = new wxTimer (this, -1);
1903 
1904 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
1905     m_normalFont.MacCreateThemeFont (kThemeViewsFont);
1906 #else
1907     m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
1908 #endif
1909     m_boldFont = wxFont( m_normalFont.GetPointSize(),
1910                          m_normalFont.GetFamily(),
1911                          m_normalFont.GetStyle(),
1912                          wxFONTWEIGHT_BOLD,
1913                          m_normalFont.GetUnderlined(),
1914                          m_normalFont.GetFaceName(),
1915                          m_normalFont.GetEncoding());
1916     m_toolTip.clear();
1917     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed
1918     m_isItemToolTip = false;  // so far no item-specific tooltip
1919 }
1920 
Create(wxTreeListCtrl * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)1921 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
1922                                    wxWindowID id,
1923                                    const wxPoint& pos,
1924                                    const wxSize& size,
1925                                    long style,
1926                                    const wxValidator &validator,
1927                                    const wxString& name) {
1928 
1929     wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
1930 
1931 #if wxUSE_VALIDATORS
1932     SetValidator(validator);
1933 #endif
1934 
1935     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
1936     // prevent any background repaint in order to reducing flicker
1937     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
1938 
1939 #ifdef __WXMSW__
1940     {
1941         int i, j;
1942         wxBitmap bmp(8, 8);
1943         wxMemoryDC bdc;
1944         bdc.SelectObject(bmp);
1945         bdc.SetPen(*wxGREY_PEN);
1946         bdc.DrawRectangle(-1, -1, 10, 10);
1947         for (i = 0; i < 8; i++) {
1948             for (j = 0; j < 8; j++) {
1949                 if (!((i + j) & 1)) {
1950                     bdc.DrawPoint(i, j);
1951                 }
1952             }
1953         }
1954 
1955         m_dottedPen = wxPen(bmp, 1);
1956     }
1957 #else
1958 //?    m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT );  // too slow under XFree86
1959     m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
1960 #endif
1961 
1962     m_owner = parent;
1963     m_main_column = 0;
1964 
1965     return true;
1966 }
1967 
~wxTreeListMainWindow()1968 wxTreeListMainWindow::~wxTreeListMainWindow() {
1969     delete m_hilightBrush;
1970     delete m_hilightUnfocusedBrush;
1971 
1972     delete m_editTimer;
1973     delete m_findTimer;
1974     if (m_ownsImageListNormal) delete m_imageListNormal;
1975     if (m_ownsImageListState) delete m_imageListState;
1976     if (m_ownsImageListButtons) delete m_imageListButtons;
1977 
1978     if (m_editControl) {
1979         m_editControl->SetOwner(NULL);    // prevent control from calling us during delete
1980         delete m_editControl;
1981     }
1982 
1983     DeleteRoot();
1984 }
1985 
1986 
1987 //-----------------------------------------------------------------------------
1988 // accessors
1989 //-----------------------------------------------------------------------------
1990 
GetCount() const1991 size_t wxTreeListMainWindow::GetCount() const {
1992     return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
1993 }
1994 
SetIndent(unsigned int indent)1995 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
1996     m_indent = wxMax ((unsigned)MININDENT, indent);
1997     m_dirty = true;
1998 }
1999 
SetLineSpacing(unsigned int spacing)2000 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
2001     m_linespacing = spacing;
2002     m_dirty = true;
2003     CalculateLineHeight();
2004 }
2005 
GetChildrenCount(const wxTreeItemId & item,bool recursively)2006 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
2007                                                bool recursively) {
2008     wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
2009     return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
2010 }
2011 
SetWindowStyle(const long styles)2012 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
2013     // change to selection mode, reset selection
2014     if ((styles ^ m_windowStyle) & wxTR_MULTIPLE) { UnselectAll(); }
2015     // right now, just sets the styles.  Eventually, we may
2016     // want to update the inherited styles, but right now
2017     // none of the parents has updatable styles
2018     m_windowStyle = styles;
2019     m_dirty = true;
2020 }
2021 
SetToolTip(const wxString & tip)2022 void wxTreeListMainWindow::SetToolTip(const wxString& tip) {
2023     m_isItemToolTip = false;
2024     m_toolTip = tip;
2025     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2026 }
SetToolTip(wxToolTip * tip)2027 void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) {
2028     m_isItemToolTip = false;
2029     m_toolTip = (tip == NULL) ? wxString() : tip->GetTip();
2030     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2031 }
2032 
SetItemToolTip(const wxTreeItemId & item,const wxString & tip)2033 void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
2034     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2035     m_isItemToolTip = true;
2036     ((wxTreeListItem*) item.m_pItem)->SetToolTip(tip);
2037     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
2038 }
2039 
2040 
2041 //-----------------------------------------------------------------------------
2042 // functions to work with tree items
2043 //-----------------------------------------------------------------------------
2044 
GetItemImage(const wxTreeItemId & item,int column,wxTreeItemIcon which) const2045 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which) const {
2046     wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
2047     return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
2048 }
2049 
GetItemData(const wxTreeItemId & item) const2050 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
2051     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2052     return ((wxTreeListItem*) item.m_pItem)->GetData();
2053 }
GetItemData(const wxTreeItemId & item,int column) const2054 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item, int column) const {
2055     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
2056     return ((wxTreeListItem*) item.m_pItem)->GetData(column);
2057 }
2058 
GetItemBold(const wxTreeItemId & item) const2059 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
2060     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2061     return ((wxTreeListItem *)item.m_pItem)->IsBold();
2062 }
GetItemBold(const wxTreeItemId & item,int column) const2063 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item, int column) const {
2064     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
2065     return ((wxTreeListItem *)item.m_pItem)->IsBold(column);
2066 }
2067 
GetItemTextColour(const wxTreeItemId & item) const2068 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
2069     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2070     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2071     wxTreeItemAttr *attr = pItem->GetAttributes();
2072     if (attr && attr->HasTextColour()) {
2073         return attr->GetTextColour();
2074     } else {
2075         return GetForegroundColour();
2076     }
2077 }
GetItemTextColour(const wxTreeItemId & item,int column) const2078 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item, int column) const {
2079     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2080     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2081     wxTreeItemAttr *attr = pItem->GetAttributes(column);
2082     if (attr && attr->HasTextColour()) {
2083         return attr->GetTextColour();
2084     } else {
2085         return GetItemTextColour(item);
2086     }
2087 }
2088 
GetItemBackgroundColour(const wxTreeItemId & item) const2089 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
2090     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2091     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2092     wxTreeItemAttr *attr = pItem->GetAttributes();
2093     if (attr && attr->HasBackgroundColour()) {
2094         return attr->GetBackgroundColour();
2095     } else {
2096         return GetBackgroundColour();
2097     }
2098 }
GetItemBackgroundColour(const wxTreeItemId & item,int column) const2099 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item, int column) const {
2100     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
2101     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2102     wxTreeItemAttr *attr = pItem->GetAttributes(column);
2103     if (attr && attr->HasBackgroundColour()) {
2104         return attr->GetBackgroundColour();
2105     } else {
2106         return GetItemBackgroundColour(item);
2107     }
2108 }
2109 
GetItemFont(const wxTreeItemId & item) const2110 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
2111     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2112     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2113     wxTreeItemAttr *attr = pItem->GetAttributes();
2114     if (attr && attr->HasFont()) {
2115         return attr->GetFont();
2116     }else if (pItem->IsBold()) {
2117         return m_boldFont;
2118     } else {
2119         return m_normalFont;
2120     }
2121 }
GetItemFont(const wxTreeItemId & item,int column) const2122 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item, int column) const {
2123     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
2124     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2125     wxTreeItemAttr *attr_cell = pItem->GetAttributes(column);
2126     wxTreeItemAttr *attr_row = pItem->GetAttributes();
2127     if (attr_cell && attr_cell->HasFont()) {
2128         return attr_cell->GetFont();
2129     } else if (attr_row && attr_row->HasFont()) {
2130         return attr_row->GetFont();
2131     } else if (pItem->IsBold(column)) {
2132         return m_boldFont;
2133     } else {
2134         return m_normalFont;
2135     }
2136 }
2137 
SetItemHasChildren(const wxTreeItemId & item,bool has)2138 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item, bool has) {
2139     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2140     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2141     pItem->SetHasPlus (has);
2142     RefreshLine (pItem);
2143 }
2144 
SetItemImage(const wxTreeItemId & item,int column,int image,wxTreeItemIcon which)2145 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which) {
2146     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2147     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2148     if(pItem->GetImage(column, which) != image)
2149     {
2150       pItem->SetImage (column, image, which);
2151       if(!IsFrozen())
2152       {
2153         wxClientDC dc (this);
2154         CalculateSize (pItem, dc);
2155         RefreshLine (pItem);
2156       };
2157     };
2158 }
2159 
SetItemData(const wxTreeItemId & item,wxTreeItemData * data)2160 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,             wxTreeItemData *data) {
2161     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2162     ((wxTreeListItem*) item.m_pItem)->SetData(data);
2163 }
SetItemData(const wxTreeItemId & item,int column,wxTreeItemData * data)2164 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, int column, wxTreeItemData *data) {
2165     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2166     ((wxTreeListItem*) item.m_pItem)->SetData(column, data);
2167 }
2168 
SetItemBold(const wxTreeItemId & item,bool bold)2169 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item,             bool bold) {
2170     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2171     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2172     if (pItem->IsBold() != bold) { // avoid redrawing if no real change
2173         pItem->SetBold (bold);
2174         RefreshLine (pItem);
2175     }
2176 }
SetItemBold(const wxTreeItemId & item,int column,bool bold)2177 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, int column, bool bold) {
2178     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2179     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2180 //    if (pItem->IsBold(column) != bold) { // avoid redrawing if no real change
2181         pItem->SetBold (column, bold);
2182         RefreshLine (pItem);
2183 //    }
2184 }
2185 
SetItemTextColour(const wxTreeItemId & item,const wxColour & colour)2186 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,             const wxColour& colour) {
2187     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2188     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2189     pItem->Attr().SetTextColour (colour);
2190     RefreshLine (pItem);
2191 }
SetItemTextColour(const wxTreeItemId & item,int column,const wxColour & colour)2192 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2193     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2194     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2195     pItem->Attr(column).SetTextColour (colour);
2196     RefreshLine (pItem);
2197 }
2198 
SetItemBackgroundColour(const wxTreeItemId & item,const wxColour & colour)2199 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,             const wxColour& colour) {
2200     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2201     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2202     pItem->Attr().SetBackgroundColour (colour);
2203     RefreshLine (pItem);
2204 }
SetItemBackgroundColour(const wxTreeItemId & item,int column,const wxColour & colour)2205 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, int column, const wxColour& colour) {
2206     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2207     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2208     pItem->Attr(column).SetBackgroundColour (colour);
2209     RefreshLine (pItem);
2210 }
2211 
SetItemFont(const wxTreeItemId & item,const wxFont & font)2212 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,             const wxFont& font) {
2213     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2214     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2215     pItem->Attr().SetFont (font);
2216     RefreshLine (pItem);
2217 }
SetItemFont(const wxTreeItemId & item,int column,const wxFont & font)2218 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, int column, const wxFont& font) {
2219     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2220     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2221     pItem->Attr(column).SetFont (font);
2222     RefreshLine (pItem);
2223 }
2224 
2225 
SetFont(const wxFont & font)2226 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
2227     wxScrolledWindow::SetFont (font);
2228     m_normalFont = font;
2229     m_boldFont = wxFont (m_normalFont.GetPointSize(),
2230                          m_normalFont.GetFamily(),
2231                          m_normalFont.GetStyle(),
2232                          wxFONTWEIGHT_BOLD,
2233                          m_normalFont.GetUnderlined(),
2234                          m_normalFont.GetFaceName());
2235     CalculateLineHeight();
2236     return true;
2237 }
2238 
2239 
2240 // ----------------------------------------------------------------------------
2241 // item status inquiries
2242 // ----------------------------------------------------------------------------
2243 
IsVisible(const wxTreeItemId & item,bool fullRow,bool within) const2244 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2245     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2246 
2247     // An item is only visible if it's not a descendant of a collapsed item
2248     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
2249     wxTreeListItem* parent = pItem->GetItemParent();
2250     while (parent) {
2251         if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
2252         if (!parent->IsExpanded()) return false;
2253         parent = parent->GetItemParent();
2254     }
2255 
2256     // and the item is only visible if it is currently (fully) within the view
2257     if (within) {
2258         wxSize clientSize = GetClientSize();
2259         wxRect rect;
2260         if ((!GetBoundingRect (item, rect)) ||
2261             ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
2262             (rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) ||
2263             (!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x))) return false;
2264     }
2265 
2266     return true;
2267 }
2268 
HasChildren(const wxTreeItemId & item) const2269 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
2270     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2271 
2272     // consider that the item does have children if it has the "+" button: it
2273     // might not have them (if it had never been expanded yet) but then it
2274     // could have them as well and it's better to err on this side rather than
2275     // disabling some operations which are restricted to the items with
2276     // children for an item which does have them
2277     return ((wxTreeListItem*) item.m_pItem)->HasPlus();
2278 }
2279 
IsExpanded(const wxTreeItemId & item) const2280 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
2281     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2282     return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
2283 }
2284 
IsSelected(const wxTreeItemId & item) const2285 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
2286     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2287     return ((wxTreeListItem*) item.m_pItem)->IsSelected();
2288 }
2289 
IsBold(const wxTreeItemId & item,int column) const2290 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item, int column) const {
2291     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
2292     return ((wxTreeListItem*) item.m_pItem)->IsBold(column);
2293 }
2294 
2295 // ----------------------------------------------------------------------------
2296 // navigation
2297 // ----------------------------------------------------------------------------
2298 
GetItemParent(const wxTreeItemId & item) const2299 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
2300     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2301     return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
2302 }
2303 
GetFirstChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2304 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
2305                                                   wxTreeItemIdValue& cookie) const {
2306     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2307     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2308     cookie = 0;
2309     return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
2310 }
2311 
GetNextChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2312 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
2313                                                  wxTreeItemIdValue& cookie) const {
2314     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2315     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2316     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2317     long *pIndex = ((long*)&cookie);
2318     return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
2319 }
2320 
GetPrevChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2321 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
2322                                                  wxTreeItemIdValue& cookie) const {
2323     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2324     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2325     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2326     long *pIndex = (long*)&cookie;
2327     return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
2328 }
2329 
GetLastChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const2330 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
2331                                                  wxTreeItemIdValue& cookie) const {
2332     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2333     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
2334     // it's ok to cast cookie to long, we never have indices which overflow "void*"
2335     long *pIndex = ((long*)&cookie);
2336     (*pIndex) = (long)children.Count();
2337     return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
2338 }
2339 
GetNextSibling(const wxTreeItemId & item) const2340 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
2341     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2342 
2343     // get parent
2344     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2345     wxTreeListItem *parent = i->GetItemParent();
2346     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2347 
2348     // get index
2349     wxArrayTreeListItems& siblings = parent->GetChildren();
2350     size_t index = siblings.Index (i);
2351     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2352     return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
2353 }
2354 
GetPrevSibling(const wxTreeItemId & item) const2355 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
2356     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2357 
2358     // get parent
2359     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
2360     wxTreeListItem *parent = i->GetItemParent();
2361     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
2362 
2363     // get index
2364     wxArrayTreeListItems& siblings = parent->GetChildren();
2365     size_t index = siblings.Index(i);
2366     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2367     return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
2368 }
2369 
2370 // Only for internal use right now, but should probably be public
GetNext(const wxTreeItemId & item,bool fulltree) const2371 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
2372     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2373 
2374     // if there are any children, return first child
2375     if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
2376         wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
2377         if (children.GetCount() > 0) return children.Item (0);
2378     }
2379 
2380     // get sibling of this item or of the ancestors instead
2381     wxTreeItemId next;
2382     wxTreeItemId parent = item;
2383     do {
2384         next = GetNextSibling (parent);
2385         parent = GetItemParent (parent);
2386     } while (!next.IsOk() && parent.IsOk());
2387     return next;
2388 }
2389 
2390 // Only for internal use right now, but should probably be public
GetPrev(const wxTreeItemId & item,bool fulltree) const2391 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
2392     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2393 
2394     // if there are no previous sibling get parent
2395     wxTreeItemId prev = GetPrevSibling (item);
2396     if (! prev.IsOk()) return GetItemParent (item);
2397 
2398     // while previous sibling has children, return last
2399     while (fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) {
2400         wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren();
2401         if (children.GetCount() == 0) break;
2402         prev = children.Item (children.GetCount() - 1);
2403     }
2404 
2405     return prev;
2406 }
2407 
GetFirstExpandedItem() const2408 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
2409     return GetNextExpanded (GetRootItem());
2410 }
2411 
GetNextExpanded(const wxTreeItemId & item) const2412 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
2413     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2414     return GetNext (item, false);
2415 }
2416 
GetPrevExpanded(const wxTreeItemId & item) const2417 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
2418     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2419     return GetPrev (item, false);
2420 }
2421 
GetFirstVisible(bool fullRow,bool within) const2422 wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const {
2423     if (HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within)) {
2424         return GetNextVisible (GetRootItem(), fullRow, within);
2425     } else {
2426         return GetRootItem();
2427     }
2428 }
2429 
GetNextVisible(const wxTreeItemId & item,bool fullRow,bool within) const2430 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2431     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2432     wxTreeItemId id = GetNext (item, false);
2433     while (id.IsOk()) {
2434         if (IsVisible (id, fullRow, within)) return id;
2435         id = GetNext (id, false);
2436     }
2437     return wxTreeItemId();
2438 }
2439 
GetLastVisible(bool fullRow,bool within) const2440 wxTreeItemId wxTreeListMainWindow::GetLastVisible ( bool fullRow, bool within) const {
2441     wxCHECK_MSG (GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item"));
2442     wxTreeItemId id = GetRootItem();
2443     wxTreeItemId res = id;
2444     while ((id = GetNext (id, false)).IsOk()) {
2445         if (IsVisible (id, fullRow, within)) res = id;
2446     }
2447     return res;
2448 }
2449 
GetPrevVisible(const wxTreeItemId & item,bool fullRow,bool within) const2450 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
2451     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
2452     wxTreeItemId id = GetPrev (item, true);
2453     while (id.IsOk()) {
2454         if (IsVisible (id, fullRow, within)) return id;
2455         id = GetPrev(id, true);
2456     }
2457     return wxTreeItemId();
2458 }
2459 
2460 // ----------------------------------------------------------------------------
2461 // operations
2462 // ----------------------------------------------------------------------------
2463 
2464 // ----------------------------  ADD OPERATION  -------------------------------
2465 
DoInsertItem(const wxTreeItemId & parentId,size_t previous,const wxString & text,int image,int selImage,wxTreeItemData * data)2466 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
2467                                                  size_t previous,
2468                                                  const wxString& text,
2469                                                  int image, int selImage,
2470                                                  wxTreeItemData *data) {
2471     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2472     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2473     m_dirty = true; // do this first so stuff below doesn't cause flicker
2474 
2475     wxArrayString arr;
2476     arr.Alloc (GetColumnCount());
2477     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2478     arr[m_main_column] = text;
2479     wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
2480     if (data != NULL) {
2481         data->SetId (item);
2482     }
2483     parent->Insert (item, previous);
2484 
2485     return item;
2486 }
2487 
AddRoot(const wxString & text,int image,int selImage,wxTreeItemData * data)2488 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
2489                                             int image, int selImage,
2490                                             wxTreeItemData *data) {
2491     wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
2492     wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
2493     m_dirty = true; // do this first so stuff below doesn't cause flicker
2494 
2495     wxArrayString arr;
2496     arr.Alloc (GetColumnCount());
2497     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
2498     arr[m_main_column] = text;
2499     m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
2500     if (data != NULL) {
2501         data->SetId(m_rootItem);
2502     }
2503     if (HasFlag(wxTR_HIDE_ROOT)) {
2504         // if we will hide the root, make sure children are visible
2505         m_rootItem->SetHasPlus();
2506         m_rootItem->Expand();
2507         wxTreeItemIdValue cookie = 0;
2508         SetCurrentItem(GetFirstChild(m_rootItem, cookie));
2509     }
2510     return m_rootItem;
2511 }
2512 
PrependItem(const wxTreeItemId & parent,const wxString & text,int image,int selImage,wxTreeItemData * data)2513 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
2514                                                 const wxString& text,
2515                                                 int image, int selImage,
2516                                                 wxTreeItemData *data) {
2517     return DoInsertItem (parent, 0u, text, image, selImage, data);
2518 }
2519 
InsertItem(const wxTreeItemId & parentId,const wxTreeItemId & idPrevious,const wxString & text,int image,int selImage,wxTreeItemData * data)2520 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2521                                                const wxTreeItemId& idPrevious,
2522                                                const wxString& text,
2523                                                int image, int selImage,
2524                                                wxTreeItemData *data) {
2525     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2526     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2527 
2528     int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
2529     wxASSERT_MSG( index != wxNOT_FOUND,
2530                   _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
2531 
2532     return DoInsertItem (parentId, ++index, text, image, selImage, data);
2533 }
2534 
InsertItem(const wxTreeItemId & parentId,size_t before,const wxString & text,int image,int selImage,wxTreeItemData * data)2535 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
2536                                                size_t before,
2537                                                const wxString& text,
2538                                                int image, int selImage,
2539                                                wxTreeItemData *data) {
2540     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
2541     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2542 
2543     return DoInsertItem (parentId, before, text, image, selImage, data);
2544 }
2545 
AppendItem(const wxTreeItemId & parentId,const wxString & text,int image,int selImage,wxTreeItemData * data)2546 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
2547                                                const wxString& text,
2548                                                int image, int selImage,
2549                                                wxTreeItemData *data) {
2550     wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
2551     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
2552 
2553     return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
2554 }
2555 
2556 
2557 // --------------------------  DELETE OPERATION  ------------------------------
2558 
Delete(const wxTreeItemId & itemId)2559 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
2560     if (! itemId.IsOk()) return;
2561     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2562     wxTreeListItem *parent = item->GetItemParent();
2563     wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
2564 
2565     // recursive delete
2566     DoDeleteItem(item);
2567 
2568     // update parent --CAUTION: must come after delete itself, so that item's
2569     //  siblings may be found
2570     if (parent) {
2571         parent->GetChildren().Remove (item);  // remove by value
2572     }
2573 }
2574 
2575 
DeleteRoot()2576 void wxTreeListMainWindow::DeleteRoot() {
2577     if (! m_rootItem) return;
2578 
2579     SetCurrentItem((wxTreeListItem*)NULL);
2580     m_selectItem = (wxTreeListItem*)NULL;
2581     m_shiftItem = (wxTreeListItem*)NULL;
2582 
2583     DeleteChildren (m_rootItem);
2584     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem);
2585     delete m_rootItem; m_rootItem = NULL;
2586 }
2587 
2588 
DeleteChildren(const wxTreeItemId & itemId)2589 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
2590     if (! itemId.IsOk()) return;
2591     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2592 
2593     // recursive delete on all children, starting from the right to prevent
2594     //  multiple selection changes (see m_curItem handling in DoDeleteItem() )
2595     wxArrayTreeListItems& children = item->GetChildren();
2596     for (size_t n = children.GetCount(); n>0; n--) {
2597         DoDeleteItem(children[n-1]);
2598         // immediately remove child from array, otherwise it might get selected
2599         // as current item (see m_curItem handling in DoDeleteItem() )
2600         children.RemoveAt(n-1);
2601     }
2602 }
2603 
2604 
DoDeleteItem(wxTreeListItem * item)2605 void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) {
2606     wxCHECK_RET (item, _T("invalid item for delete!"));
2607 
2608     m_dirty = true; // do this first so stuff below doesn't cause flicker
2609 
2610     // cancel any editing
2611 
2612     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
2613 
2614     // cancel any dragging
2615     if (item == m_dragItem) {
2616         // stop dragging
2617         m_isDragStarted = m_isDragging = false;
2618         if (HasCapture()) ReleaseMouse();
2619     }
2620 
2621     // don't stay with invalid m_curItem: take next sibling or reset to NULL
2622     // NOTE: this might be slighty inefficient when deleting a whole tree
2623     //  but has the advantage that all deletion side-effects are handled here
2624     if (item == m_curItem) {
2625         SetCurrentItem(item->GetItemParent());
2626         if (m_curItem) {
2627             wxArrayTreeListItems& siblings = m_curItem->GetChildren();
2628             size_t index = siblings.Index (item);
2629             wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
2630             SetCurrentItem(index < siblings.Count()-1 ? siblings[index+1]: (wxTreeListItem*)NULL);
2631         }
2632     }
2633     // don't stay with invalid m_shiftItem: reset it to NULL
2634     if (item == m_shiftItem) m_shiftItem = (wxTreeListItem*)NULL;
2635     // don't stay with invalid m_selectItem: default to current item
2636     if (item == m_selectItem) {
2637         m_selectItem = m_curItem;
2638         SelectItem(m_selectItem, (wxTreeItemId*)NULL, true);  // unselect others
2639     }
2640 
2641     // recurse children, starting from the right to prevent multiple selection
2642     //  changes (see m_curItem handling above)
2643     wxArrayTreeListItems& children = item->GetChildren();
2644     for (size_t n = children.GetCount(); n>0; n--) {
2645         DoDeleteItem(children[n-1]);
2646         // immediately remove child from array, otherwise it might get selected
2647         // as current item (see m_curItem handling above)
2648         children.RemoveAt(n-1);
2649     }
2650 
2651     // delete item itself
2652     wxTreeItemData* data = GetItemData(item);
2653     if (data != NULL)
2654     {
2655         delete data;
2656     };
2657     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
2658     delete item;
2659 }
2660 
2661 
2662 // ----------------------------------------------------------------------------
2663 
SetItemParent(const wxTreeItemId & parentId,const wxTreeItemId & itemId)2664 void wxTreeListMainWindow::SetItemParent(const wxTreeItemId& parentId, const wxTreeItemId& itemId) {
2665 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2666 wxTreeListItem *parent_new = (wxTreeListItem*) parentId.m_pItem;
2667 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::SetItemParent") );
2668 wxCHECK_RET (parent_new, _T("invalid parent in wxTreeListMainWindow::SetItemParent") );
2669 wxCHECK_RET (item != m_rootItem, _T("invalid root as item in wxTreeListMainWindow::SetItemParent!") );
2670 wxTreeListItem *parent_old = item->GetItemParent();
2671 
2672     m_dirty = true; // do this first so stuff below doesn't cause flicker
2673 
2674     parent_old->GetChildren().Remove (item);
2675     parent_new->Insert(item, parent_new->GetChildren().Count());
2676     item->SetItemParent(parent_new);
2677     // new parent was a leaf, show its new child
2678     if (parent_new->GetChildren().Count() == 1) parent_new->Expand();
2679 }
2680 
2681 
2682 // ----------------------------------------------------------------------------
2683 
SetCurrentItem(const wxTreeItemId & itemId)2684 void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
2685   SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
2686 }
SetCurrentItem(wxTreeListItem * item)2687 void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
2688 wxTreeListItem *old_item;
2689 
2690     old_item = m_curItem; m_curItem = item;
2691 
2692     // change of item, redraw previous
2693     if (old_item != NULL && old_item != item) {
2694         RefreshLine(old_item);
2695     }
2696 
2697 }
2698 
2699 // ----------------------------------------------------------------------------
2700 
Expand(const wxTreeItemId & itemId)2701 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
2702     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2703     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
2704 
2705     if (!item->HasPlus() || item->IsExpanded()) return;
2706 
2707     // send event to user code
2708     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
2709     event.SetInt(m_curColumn);
2710     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled
2711 
2712     item->Expand();
2713     m_dirty = true;
2714 
2715     // send event to user code
2716     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
2717     SendEvent(0, NULL, &event);
2718 }
2719 
ExpandAll(const wxTreeItemId & itemId)2720 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
2721     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2722 
2723     Expand (itemId);
2724     if (!IsExpanded (itemId)) return;
2725     wxTreeItemIdValue cookie;
2726     wxTreeItemId child = GetFirstChild (itemId, cookie);
2727     while (child.IsOk()) {
2728         ExpandAll (child);
2729         child = GetNextChild (itemId, cookie);
2730     }
2731 }
2732 
Collapse(const wxTreeItemId & itemId)2733 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
2734     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
2735     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
2736 
2737     if (!item->HasPlus() || !item->IsExpanded()) return;
2738 
2739     // send event to user code
2740     wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 );
2741     event.SetInt(m_curColumn);
2742     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled
2743 
2744     item->Collapse();
2745     m_dirty = true;
2746 
2747     // send event to user code
2748     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
2749     SendEvent(0, NULL, &event);
2750 }
2751 
CollapseAndReset(const wxTreeItemId & item)2752 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
2753     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
2754 
2755     Collapse (item);
2756     DeleteChildren (item);
2757 }
2758 
Toggle(const wxTreeItemId & itemId)2759 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
2760     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
2761 
2762     if (IsExpanded (itemId)) {
2763         Collapse (itemId);
2764     }else{
2765         Expand (itemId);
2766     }
2767 }
2768 
Unselect()2769 void wxTreeListMainWindow::Unselect() {
2770     if (m_selectItem) {
2771         m_selectItem->SetHilight (false);
2772         RefreshLine (m_selectItem);
2773         m_selectItem = (wxTreeListItem*)NULL;
2774     }
2775 }
2776 
UnselectAllChildren(wxTreeListItem * item)2777 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
2778     wxCHECK_RET (item, _T("invalid tree item"));
2779 
2780     if (item->IsSelected()) {
2781         item->SetHilight (false);
2782         RefreshLine (item);
2783         if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
2784         if (item != m_curItem) m_lastOnSame = false;  // selection change, so reset edit marker
2785     }
2786     if (item->HasChildren()) {
2787         wxArrayTreeListItems& children = item->GetChildren();
2788         size_t count = children.Count();
2789         for (size_t n = 0; n < count; ++n) {
2790             UnselectAllChildren (children[n]);
2791         }
2792     }
2793 }
2794 
UnselectAll()2795 void wxTreeListMainWindow::UnselectAll() {
2796     UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
2797 }
2798 
2799 // Recursive function !
2800 // To stop we must have crt_item<last_item
2801 // Algorithm :
2802 // Tag all next children, when no more children,
2803 // Move to parent (not to tag)
2804 // Keep going... if we found last_item, we stop.
TagNextChildren(wxTreeListItem * crt_item,wxTreeListItem * last_item)2805 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
2806                                             wxTreeListItem *last_item) {
2807     wxTreeListItem *parent = crt_item->GetItemParent();
2808 
2809     if (!parent) {// This is root item
2810         return TagAllChildrenUntilLast (crt_item, last_item);
2811     }
2812 
2813     wxArrayTreeListItems& children = parent->GetChildren();
2814     int index = children.Index(crt_item);
2815     wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
2816 
2817     if ((parent->HasChildren() && parent->IsExpanded()) ||
2818         ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
2819         size_t count = children.Count();
2820         for (size_t n = (index+1); n < count; ++n) {
2821             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2822         }
2823     }
2824 
2825     return TagNextChildren (parent, last_item);
2826 }
2827 
TagAllChildrenUntilLast(wxTreeListItem * crt_item,wxTreeListItem * last_item)2828 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
2829                                                     wxTreeListItem *last_item) {
2830     crt_item->SetHilight (true);
2831     RefreshLine(crt_item);
2832 
2833     if (crt_item==last_item) return true;
2834 
2835     if (crt_item->HasChildren() && crt_item->IsExpanded()) {
2836         wxArrayTreeListItems& children = crt_item->GetChildren();
2837         size_t count = children.Count();
2838         for (size_t n = 0; n < count; ++n) {
2839             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
2840         }
2841     }
2842 
2843     return false;
2844 }
2845 
SelectItem(const wxTreeItemId & itemId,const wxTreeItemId & lastId,bool unselect_others)2846 bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
2847                                        const wxTreeItemId& lastId,
2848                                        bool unselect_others) {
2849 
2850     wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
2851 
2852     // send selecting event to the user code
2853     wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
2854     event.SetInt(m_curColumn);
2855     event.SetOldItem (m_curItem);
2856     if (SendEvent(0, item, &event) && !event.IsAllowed()) return false;  // veto on selection change
2857 
2858     // unselect all if unselect other items
2859     bool bUnselectedAll = false; // see that UnselectAll is done only once
2860     if (unselect_others) {
2861         if (HasFlag(wxTR_MULTIPLE)) {
2862             UnselectAll(); bUnselectedAll = true;
2863         }else{
2864             Unselect(); // to speed up thing
2865         }
2866     }
2867 
2868     // select item range
2869     if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
2870 
2871         if (! bUnselectedAll) UnselectAll();
2872         wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
2873 
2874         // ensure that the position of the item it calculated in any case
2875         if (m_dirty) CalculatePositions();
2876 
2877         // select item range according Y-position
2878         if (last->GetY() < item->GetY()) {
2879             if (!TagAllChildrenUntilLast (last, item)) {
2880                 TagNextChildren (last, item);
2881             }
2882         }else{
2883             if (!TagAllChildrenUntilLast (item, last)) {
2884                 TagNextChildren (item, last);
2885             }
2886         }
2887 
2888     // or select single item
2889     }else if (itemId.IsOk()) {
2890 
2891         // select item according its old selection
2892         item->SetHilight (!item->IsSelected());
2893         RefreshLine (item);
2894         if (unselect_others) {
2895             m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
2896         }
2897 
2898     // or select nothing
2899     } else {
2900         if (! bUnselectedAll) UnselectAll();
2901     }
2902 
2903     // send event to user code
2904     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
2905     SendEvent(0, NULL, &event);
2906 
2907     return true;
2908 }
2909 
SelectAll()2910 void wxTreeListMainWindow::SelectAll() {
2911     wxTreeItemId root = GetRootItem();
2912     wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
2913     wxCHECK_RET (root.IsOk(), _T("no tree"));
2914 
2915     // send event to user code
2916     wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
2917     event.SetOldItem (m_curItem);
2918     event.SetInt (-1); // no colum clicked
2919     if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return;  // selection change vetoed
2920 
2921     wxTreeItemIdValue cookie = 0;
2922     wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
2923     wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
2924     if (!TagAllChildrenUntilLast (first, last)) {
2925         TagNextChildren (first, last);
2926     }
2927 
2928     // send event to user code
2929     event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
2930     SendEvent(0, NULL, &event);
2931 }
2932 
FillArray(wxTreeListItem * item,wxArrayTreeItemIds & array) const2933 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
2934                                       wxArrayTreeItemIds &array) const {
2935     if (item->IsSelected()) array.Add (wxTreeItemId(item));
2936 
2937     if (item->HasChildren()) {
2938         wxArrayTreeListItems& children = item->GetChildren();
2939         size_t count = children.GetCount();
2940         for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
2941     }
2942 }
2943 
GetSelections(wxArrayTreeItemIds & array) const2944 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
2945     array.Empty();
2946     wxTreeItemId idRoot = GetRootItem();
2947     if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
2948     return array.Count();
2949 }
2950 
EnsureVisible(const wxTreeItemId & item)2951 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
2952     if (!item.IsOk()) return; // do nothing if no item
2953 
2954     // first expand all parent branches
2955     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2956     wxTreeListItem *parent = gitem->GetItemParent();
2957     while (parent) {
2958         Expand (parent);
2959         parent = parent->GetItemParent();
2960     }
2961 
2962     ScrollTo (item);
2963     RefreshLine (gitem);
2964 }
2965 
ScrollTo(const wxTreeItemId & item)2966 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
2967     if (!item.IsOk()) return; // do nothing if no item
2968 
2969     // ensure that the position of the item it calculated in any case
2970     if (m_dirty) CalculatePositions();
2971 
2972     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
2973 
2974     // now scroll to the item
2975     int item_y = gitem->GetY();
2976 
2977     int xUnit, yUnit;
2978     GetScrollPixelsPerUnit (&xUnit, &yUnit);
2979     int start_x = 0;
2980     int start_y = 0;
2981     GetViewStart (&start_x, &start_y);
2982     start_y *= yUnit;
2983 
2984     int client_h = 0;
2985     int client_w = 0;
2986     GetClientSize (&client_w, &client_h);
2987 
2988     int x = 0;
2989     int y = 0;
2990     m_rootItem->GetSize (x, y, this);
2991     x = m_owner->GetHeaderWindow()->GetWidth();
2992     y += yUnit + 2; // one more scrollbar unit + 2 pixels
2993     int x_pos = GetScrollPos( wxHORIZONTAL );
2994 
2995     if (item_y < start_y+3) {
2996         // going down, item should appear at top
2997         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
2998     }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
2999         // going up, item should appear at bottom
3000         item_y += yUnit + 2;
3001         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
3002     }
3003 }
3004 
3005 // TODO: tree sorting functions are not reentrant and not MT-safe!
3006 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
3007 
tree_ctrl_compare_func(wxTreeListItem ** item1,wxTreeListItem ** item2)3008 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2)
3009 {
3010     wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
3011     return s_treeBeingSorted->OnCompareItems(*item1, *item2);
3012 }
3013 
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2)3014 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
3015 {
3016     return (m_sortColumn == -1
3017         ? m_owner->OnCompareItems (item1, item2)
3018         : (m_ReverseSortOrder
3019             ? m_owner->OnCompareItems (item2, item1, m_sortColumn)
3020             : m_owner->OnCompareItems (item1, item2, m_sortColumn)
3021         )
3022     );
3023 }
3024 
SortChildren(const wxTreeItemId & itemId,int column,bool reverseOrder)3025 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId, int column, bool reverseOrder) {
3026     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
3027 
3028     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3029 
3030     wxCHECK_RET (!s_treeBeingSorted,
3031                  _T("wxTreeListMainWindow::SortChildren is not reentrant") );
3032 
3033     wxArrayTreeListItems& children = item->GetChildren();
3034     if ( children.Count() > 1 ) {
3035         m_dirty = true;
3036         s_treeBeingSorted = this;
3037         m_sortColumn = column;  // -1 indicates legacy mode
3038         m_ReverseSortOrder = reverseOrder;
3039         children.Sort(tree_ctrl_compare_func);
3040         s_treeBeingSorted = NULL;
3041     }
3042 }
3043 
MatchItemText(const wxString & itemText,const wxString & pattern,int mode)3044 bool wxTreeListMainWindow::MatchItemText(const wxString &itemText, const wxString &pattern, int mode) {
3045 wxString searchText;
3046 
3047    if (mode & wxTL_MODE_FIND_PARTIAL) {
3048        searchText = itemText.Mid (0, pattern.Length());
3049    }else{
3050        searchText = itemText;
3051    }
3052    if (mode & wxTL_MODE_FIND_NOCASE) {
3053        if (searchText.CmpNoCase (pattern) == 0) return true;
3054    }else{
3055        if (searchText.Cmp (pattern) == 0) return true;
3056    }
3057 
3058    return false;
3059 }
3060 
3061 
FindItem(const wxTreeItemId & item,int column,const wxString & str,int mode)3062 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode) {
3063     wxTreeItemIdValue cookie = 0;
3064     wxTreeItemId next = item;
3065 
3066     // start checking the next items
3067     wxString itemText;
3068     int col, col_start, col_end;
3069     if (column >= 0) { col_start = col_end = column; }
3070     else { col_start = 0; col_end = GetColumnCount() - 1; }
3071 
3072     // navigate tree
3073     while (true) {
3074         // go to next item
3075         if (next.IsOk()) {
3076             if (mode & wxTL_MODE_NAV_LEVEL) {
3077                 next = GetNextSibling (next);
3078             }else if (mode & wxTL_MODE_NAV_VISIBLE) {
3079                 next = GetNextVisible (next, false, true);
3080             }else if (mode & wxTL_MODE_NAV_EXPANDED) {
3081                 next = GetNextExpanded (next);
3082             }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
3083                 next = GetNext (next, true);
3084             }
3085         // not a valid item, start at the top of the tree
3086         } else {
3087             next = GetRootItem();
3088             if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) {
3089                 next = GetFirstChild (GetRootItem(), cookie);
3090             }
3091         }
3092         // end of tree (or back to beginning) ?
3093         if (! next.IsOk() || next == item) return (wxTreeItemId*)NULL;
3094         // check for a match
3095         for (col=col_start; col<=col_end; col++) {
3096             if (MatchItemText(GetItemText (next, col),str, mode)) return next;
3097         }
3098     }
3099     // should never get here
3100     return (wxTreeItemId*)NULL;
3101 }
3102 
SetDragItem(const wxTreeItemId & item)3103 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
3104     wxTreeListItem *prevItem = m_dragItem;
3105     m_dragItem = (wxTreeListItem*) item.m_pItem;
3106     if (prevItem) RefreshLine (prevItem);
3107     if (m_dragItem) RefreshLine (m_dragItem);
3108 }
3109 
CalculateLineHeight()3110 void wxTreeListMainWindow::CalculateLineHeight() {
3111     wxClientDC dc (this);
3112     dc.SetFont (m_normalFont);
3113     m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
3114 
3115     if (m_imageListNormal) {
3116         // Calculate a m_lineHeight value from the normal Image sizes.
3117         // May be toggle off. Then wxTreeListMainWindow will spread when
3118         // necessary (which might look ugly).
3119         int n = m_imageListNormal->GetImageCount();
3120         for (int i = 0; i < n ; i++) {
3121             int width = 0, height = 0;
3122             m_imageListNormal->GetSize(i, width, height);
3123             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3124         }
3125     }
3126 
3127     if (m_imageListButtons) {
3128         // Calculate a m_lineHeight value from the Button image sizes.
3129         // May be toggle off. Then wxTreeListMainWindow will spread when
3130         // necessary (which might look ugly).
3131         int n = m_imageListButtons->GetImageCount();
3132         for (int i = 0; i < n ; i++) {
3133             int width = 0, height = 0;
3134             m_imageListButtons->GetSize(i, width, height);
3135             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
3136         }
3137     }
3138 
3139     if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
3140         m_lineHeight += 2; // minimal 2 pixel space
3141     }else{
3142         m_lineHeight += m_lineHeight / 10; // otherwise 10% space
3143     }
3144 }
3145 
SetImageList(wxImageList * imageList)3146 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
3147     if (m_ownsImageListNormal) delete m_imageListNormal;
3148     m_imageListNormal = imageList;
3149     m_ownsImageListNormal = false;
3150     m_dirty = true;
3151     CalculateLineHeight();
3152 }
3153 
SetStateImageList(wxImageList * imageList)3154 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
3155     if (m_ownsImageListState) delete m_imageListState;
3156     m_imageListState = imageList;
3157     m_ownsImageListState = false;
3158 }
3159 
SetButtonsImageList(wxImageList * imageList)3160 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
3161     if (m_ownsImageListButtons) delete m_imageListButtons;
3162     m_imageListButtons = imageList;
3163     m_ownsImageListButtons = false;
3164     m_dirty = true;
3165     CalculateLineHeight();
3166 }
3167 
AssignImageList(wxImageList * imageList)3168 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
3169     SetImageList(imageList);
3170     m_ownsImageListNormal = true;
3171 }
3172 
AssignStateImageList(wxImageList * imageList)3173 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
3174     SetStateImageList(imageList);
3175     m_ownsImageListState = true;
3176 }
3177 
AssignButtonsImageList(wxImageList * imageList)3178 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
3179     SetButtonsImageList(imageList);
3180     m_ownsImageListButtons = true;
3181 }
3182 
3183 // ----------------------------------------------------------------------------
3184 // helpers
3185 // ----------------------------------------------------------------------------
3186 
AdjustMyScrollbars()3187 void wxTreeListMainWindow::AdjustMyScrollbars() {
3188     if (m_rootItem) {
3189         int xUnit, yUnit;
3190         GetScrollPixelsPerUnit (&xUnit, &yUnit);
3191         if (xUnit == 0) xUnit = GetCharWidth();
3192         if (yUnit == 0) yUnit = m_lineHeight;
3193         int x = 0, y = 0;
3194         m_rootItem->GetSize (x, y, this);
3195         y += yUnit + 2; // one more scrollbar unit + 2 pixels
3196         int x_pos = GetScrollPos (wxHORIZONTAL);
3197         int y_pos = GetScrollPos (wxVERTICAL);
3198         x = m_owner->GetHeaderWindow()->GetWidth() + 2;
3199         if (x < GetClientSize().GetWidth()) x_pos = 0;
3200         SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
3201     }else{
3202         SetScrollbars (0, 0, 0, 0);
3203     }
3204 }
3205 
GetLineHeight(wxTreeListItem * item) const3206 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
3207     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
3208         return item->GetHeight();
3209     }else{
3210         return m_lineHeight;
3211     }
3212 }
3213 
PaintItem(wxTreeListItem * item,wxDC & dc)3214 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
3215 
3216 // read attributes constant for all item cells
3217     wxColour colText = GetItemTextColour(item);
3218     wxColour colBg = GetItemBackgroundColour(item);
3219     wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
3220     int total_w = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetMainWindow()->GetClientSize().GetWidth());
3221     int total_h = GetLineHeight(item);
3222     int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
3223     int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
3224     wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
3225     // compute text height based on main col
3226     int text_h = 0;
3227     dc.GetTextExtent( !item->GetText(GetMainColumn()).empty()
3228             ? item->GetText(GetMainColumn())
3229             : _T("M"),  // dummy text to avoid zero height and no highlight width
3230         NULL, &text_h );
3231 
3232 // determine background and show it
3233 // in wxTR_FULL_ROW_HIGHLIGHT mode, some drawing can be done already now
3234     dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
3235     dc.SetPen (*wxTRANSPARENT_PEN);
3236     if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3237         if (item->IsSelected()) {
3238             if (! m_isDragging && m_hasFocus) {
3239                 dc.SetBrush (*m_hilightBrush);
3240 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3241                 dc.SetPen (*wxBLACK_PEN);
3242 #endif // !__WXMAC__
3243             }else{
3244                 dc.SetBrush (*m_hilightUnfocusedBrush);
3245 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3246                 dc.SetPen (*wxTRANSPARENT_PEN);
3247 #endif // !__WXMAC__
3248             }
3249             dc.SetTextForeground (colTextHilight);
3250         }else {
3251             dc.SetTextForeground (GetItemTextColour(item));
3252             if (item == m_curItem) {
3253                 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
3254             }
3255         }
3256         dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
3257     }
3258 
3259 // iterate through all cells
3260     int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
3261     int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
3262     int x_colstart = 0;
3263     for (int i = 0; i < GetColumnCount(); ++i ) {
3264         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3265         int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
3266         if (col_w <= 0) continue;  // workaround for probable GTK2 bug [wxCode-Bugs-#3061215]
3267         wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
3268 
3269         // read variable attributes
3270         dc.SetFont (GetItemFont (item, i));
3271         colText = GetItemTextColour(item, i);
3272         colBg = GetItemBackgroundColour(item, i);
3273 
3274         //
3275         int x = 0;
3276         int image = NO_IMAGE;
3277         int image_w = 0;
3278         if(i == GetMainColumn()) {
3279             x = item->GetX() + MARGIN;
3280             if (HasButtons()) {
3281                 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
3282             }else{
3283                 x -= m_indent/2;
3284             }
3285             if (m_imageListNormal) image = item->GetCurrentImage();
3286         }else{
3287             x = x_colstart + MARGIN;
3288             image = item->GetImage(i);
3289         }
3290         if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
3291 
3292         // honor text alignment
3293         int w = 0, text_w = 0;
3294         wxString text = item->GetText(i);
3295         dc.GetTextExtent (text, &text_w, NULL);
3296         switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
3297         case wxALIGN_LEFT:
3298             // nothing to do, already left aligned
3299             break;
3300         case wxALIGN_RIGHT:
3301             w = col_w - (image_w + text_w + off_w + MARGIN);
3302             x += (w > 0)? w: 0;
3303             break;
3304         case wxALIGN_CENTER:
3305             w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
3306             x += (w > 0)? w: 0;
3307             break;
3308         }
3309         int text_x = x + image_w;
3310         item->SetTextX (i, text_x);
3311 
3312         // draw background (in non wxTR_FULL_ROW_HIGHLIGHT mode)
3313         // cell-specific settings are used --excepted for selection:
3314         if ( ! HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
3315             // cursor: indicate current cell
3316             bool drawCursor = false;
3317 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
3318             drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
3319 #endif // !__WXMAC__
3320             // selection: main col only, overrides colors + separate draw
3321             if (item->IsSelected() && i == GetMainColumn()) {
3322                 // draw normal background
3323                 dc.SetPen (*wxTRANSPARENT_PEN);
3324                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
3325                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3326                 // draw selection & optionally cursor
3327                 dc.SetPen (drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3328                 dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
3329                 dc.SetTextForeground (colTextHilight);
3330                 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3331             // normal FG / BG from attributes
3332             } else {
3333                 // draw normal background & optionally cursor
3334                 dc.SetPen (drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
3335                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
3336                 dc.SetTextForeground (colText);
3337                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
3338                 // on main col draw a separate cursor
3339                 if (drawCursor && i == GetMainColumn()) {
3340                     dc.SetPen (*wxBLACK_PEN);
3341                     dc.SetBackgroundMode (wxTRANSPARENT);
3342                     dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
3343                 }
3344             }
3345         }
3346 
3347         // draw vertical column lines
3348         if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
3349             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxPENSTYLE_SOLID);
3350             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
3351             dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
3352         }
3353 
3354         dc.SetBackgroundMode (wxTRANSPARENT);
3355 
3356         // draw image
3357         if (image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
3358             int y = item->GetY() + img_extraH;
3359             m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
3360         }
3361 
3362         // draw text
3363         int text_y = item->GetY() + text_extraH;
3364         dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
3365 
3366         x_colstart += col_w;
3367     }
3368 
3369     // restore normal font
3370     dc.SetFont( m_normalFont );
3371 }
3372 
3373 // Now y stands for the top of the item, whereas it used to stand for middle !
PaintLevel(wxTreeListItem * item,wxDC & dc,int level,int & y,int x_maincol)3374 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
3375                                        int level, int &y, int x_maincol) {
3376 
3377     // Handle hide root (only level 0)
3378     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
3379         wxArrayTreeListItems& children = item->GetChildren();
3380         for (size_t n = 0; n < children.Count(); n++) {
3381             PaintLevel (children[n], dc, 1, y, x_maincol);
3382         }
3383         // end after expanding root
3384         return;
3385     }
3386 
3387     // calculate position of vertical lines
3388     int x = x_maincol + MARGIN; // start of column
3389     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
3390     if (HasButtons()) {
3391         x += (m_btnWidth-m_btnWidth2); // half button space
3392     }else{
3393         x += (m_indent-m_indent/2);
3394     }
3395     if (HasFlag(wxTR_HIDE_ROOT)) {
3396         x += m_indent * (level-1); // indent but not level 1
3397     }else{
3398         x += m_indent * level; // indent according to level
3399     }
3400 
3401     // set position of vertical line
3402     item->SetX (x);
3403     item->SetY (y);
3404 
3405     int h = GetLineHeight (item);
3406     int y_top = y;
3407     int y_mid = y_top + (h/2);
3408     y += h;
3409 
3410     int exposed_x = dc.LogicalToDeviceX(0);
3411     int exposed_y = dc.LogicalToDeviceY(y_top);
3412 
3413     if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
3414 
3415         if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
3416             //dc.DestroyClippingRegion();
3417             int total_width = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetClientSize().GetWidth());
3418             dc.SetPen(wxPen(wxSystemSettings::GetColour(wxSYS_COLOUR_3DLIGHT), 1, wxPENSTYLE_SOLID));
3419             dc.DrawLine (0, y_top, total_width, y_top);
3420             dc.DrawLine (0, y_top+h, total_width, y_top+h);
3421         }
3422 
3423         // draw item
3424         PaintItem (item, dc);
3425 
3426         // restore DC objects
3427         dc.SetBrush(*wxWHITE_BRUSH);
3428         dc.SetPen(m_dottedPen);
3429 
3430         // clip to the column width
3431         int clip_width = m_owner->GetHeaderWindow()->
3432                             GetColumn(m_main_column).GetWidth();
3433         wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3434 
3435         if (!HasFlag(wxTR_NO_LINES)) { // connection lines
3436 
3437             // draw the horizontal line here
3438             dc.SetPen(m_dottedPen);
3439             int x2 = x - m_indent;
3440             if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
3441             int x3 = x + (m_btnWidth-m_btnWidth2);
3442             if (HasButtons()) {
3443                 if (item->HasPlus()) {
3444                     dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
3445                     dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
3446                 }else{
3447                     dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
3448                 }
3449             }else{
3450                 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
3451             }
3452         }
3453 
3454         if (item->HasPlus() && HasButtons()) { // should the item show a button?
3455 
3456             if (m_imageListButtons) {
3457 
3458                 // draw the image button here
3459                 int image = wxTreeItemIcon_Normal;
3460                 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
3461                 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
3462                 int xx = x - m_btnWidth2 + MARGIN;
3463                 int yy = y_mid - m_btnHeight2;
3464                 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
3465                 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
3466                 dc.DestroyClippingRegion();
3467 
3468             }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
3469 
3470                 // draw the twisty button here
3471                 dc.SetPen(*wxBLACK_PEN);
3472                 dc.SetBrush(*m_hilightBrush);
3473                 wxPoint button[3];
3474                 if (item->IsExpanded()) {
3475                     button[0].x = x - (m_btnWidth2+1);
3476                     button[0].y = y_mid - (m_btnHeight/3);
3477                     button[1].x = x + (m_btnWidth2+1);
3478                     button[1].y = button[0].y;
3479                     button[2].x = x;
3480                     button[2].y = button[0].y + (m_btnHeight2+1);
3481                 }else{
3482                     button[0].x = x - (m_btnWidth/3);
3483                     button[0].y = y_mid - (m_btnHeight2+1);
3484                     button[1].x = button[0].x;
3485                     button[1].y = y_mid + (m_btnHeight2+1);
3486                     button[2].x = button[0].x + (m_btnWidth2+1);
3487                     button[2].y = y_mid;
3488                 }
3489                 dc.DrawPolygon(3, button);
3490 
3491             }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
3492 
3493                 // draw the plus sign here
3494                 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
3495                 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
3496                 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
3497             }
3498 
3499         }
3500 
3501     }
3502 
3503     // restore DC objects
3504     dc.SetBrush(*wxWHITE_BRUSH);
3505     dc.SetPen(m_dottedPen);
3506     dc.SetTextForeground(*wxBLACK);
3507 
3508     if (item->IsExpanded())
3509     {
3510         wxArrayTreeListItems& children = item->GetChildren();
3511 
3512         // clip to the column width
3513         int clip_width = m_owner->GetHeaderWindow()->
3514                             GetColumn(m_main_column).GetWidth();
3515 
3516         // process lower levels
3517         int oldY;
3518         if (m_imgWidth > 0) {
3519             oldY = y_mid + m_imgHeight2;
3520         }else{
3521             oldY = y_mid + h/2;
3522         }
3523         int y2;
3524         for (size_t n = 0; n < children.Count(); ++n) {
3525 
3526             y2 = y + h/2;
3527             PaintLevel (children[n], dc, level+1, y, x_maincol);
3528 
3529             // draw vertical line
3530             wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
3531             if (!HasFlag (wxTR_NO_LINES)) {
3532                 x = item->GetX();
3533                 dc.DrawLine (x, oldY, x, y2);
3534                 oldY = y2;
3535             }
3536         }
3537     }
3538 }
3539 
3540 
3541 // ----------------------------------------------------------------------------
3542 // wxWindows callbacks
3543 // ----------------------------------------------------------------------------
3544 
OnPaint(wxPaintEvent & WXUNUSED (event))3545 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
3546 
3547     // init device context, clear background (BEFORE changing DC origin...)
3548     wxAutoBufferedPaintDC dc (this);
3549     wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
3550     dc.SetBackground(brush);
3551     dc.Clear();
3552     DoPrepareDC (dc);
3553 
3554     if (!m_rootItem || (GetColumnCount() <= 0)) return;
3555 
3556     // calculate button size
3557     if (m_imageListButtons) {
3558         m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
3559     }else if (HasButtons()) {
3560         m_btnWidth = BTNWIDTH;
3561         m_btnHeight = BTNHEIGHT;
3562     }
3563     m_btnWidth2 = m_btnWidth/2;
3564     m_btnHeight2 = m_btnHeight/2;
3565 
3566     // calculate image size
3567     if (m_imageListNormal) {
3568         m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
3569     }
3570     m_imgWidth2 = m_imgWidth/2;
3571     m_imgHeight2 = m_imgHeight/2;
3572 
3573     // calculate indent size
3574     if (m_imageListButtons) {
3575         m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
3576     }else if (HasButtons()) {
3577         m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
3578     }
3579 
3580     // set default values
3581     dc.SetFont( m_normalFont );
3582     dc.SetPen( m_dottedPen );
3583 
3584     // calculate column start and paint
3585     int x_maincol = 0;
3586     int i = 0;
3587     for (i = 0; i < (int)GetMainColumn(); ++i) {
3588         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
3589         x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
3590     }
3591     int y = 0;
3592     PaintLevel (m_rootItem, dc, 0, y, x_maincol);
3593 }
3594 
OnSetFocus(wxFocusEvent & event)3595 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
3596     m_hasFocus = true;
3597     RefreshSelected();
3598     if (m_curItem) RefreshLine (m_curItem);
3599     event.Skip();
3600 }
3601 
OnKillFocus(wxFocusEvent & event)3602 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
3603 {
3604     m_hasFocus = false;
3605     RefreshSelected();
3606     if (m_curItem) RefreshLine (m_curItem);
3607     event.Skip();
3608 }
3609 
OnChar(wxKeyEvent & event)3610 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
3611     // send event to user code
3612     wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 );
3613     nevent.SetInt(m_curColumn);
3614     nevent.SetKeyEvent (event);
3615     // store modifiers in extra long for Mac
3616     nevent.SetExtraLong(event.GetModifiers());
3617     if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
3618 
3619     // if no item current, select root
3620     bool curItemSet = false;
3621     if (!m_curItem) {
3622         if (! GetRootItem().IsOk()) return;
3623         SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
3624         if (HasFlag(wxTR_HIDE_ROOT)) {
3625             wxTreeItemIdValue cookie = 0;
3626             SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
3627         }
3628         SelectItem(m_curItem, (wxTreeItemId*)NULL, true);  // unselect others
3629         curItemSet = true;
3630     }
3631 
3632     // remember item at shift down
3633     if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
3634         if (!m_shiftItem) m_shiftItem = m_curItem;
3635     }else{
3636         m_shiftItem = (wxTreeListItem*)NULL;
3637     }
3638 
3639     if (curItemSet) return;  // if no item was current until now, do nothing more
3640 
3641     // process all cases
3642     wxTreeItemId newItem = (wxTreeItemId*)NULL;
3643     switch (event.GetKeyCode()) {
3644 
3645         // '+': Expand subtree
3646         case '+':
3647         case WXK_ADD: {
3648             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
3649         }break;
3650 
3651         // '-': collapse subtree
3652         case '-':
3653         case WXK_SUBTRACT: {
3654             if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
3655         }break;
3656 
3657         // '*': expand/collapse all subtrees // TODO: Mak it more useful
3658         case '*':
3659         case WXK_MULTIPLY: {
3660             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3661                 ExpandAll (m_curItem);
3662             }else if (m_curItem->HasPlus()) {
3663                 Collapse (m_curItem); // TODO: CollapseAll
3664             }
3665         }break;
3666 
3667         // ' ': toggle current item
3668         case ' ': {
3669             SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
3670         }break;
3671 
3672         // <RETURN>: activate current item
3673         case WXK_RETURN: {
3674             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
3675 
3676                 // if the user code didn't process the activate event,
3677                 // handle it ourselves by toggling the item when it is
3678                 // double clicked
3679                 if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
3680             }
3681         }break;
3682 
3683         // <BKSP>: go to the parent without collapsing
3684         case WXK_BACK: {
3685             newItem = GetItemParent (m_curItem);
3686             if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3687                 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
3688             }
3689         }break;
3690 
3691         // <HOME>: go to first visible
3692         case WXK_HOME: {
3693             newItem = GetFirstVisible(false, false);
3694         }break;
3695 
3696         // <PAGE-UP>: go to the top of the page, or if we already are then one page back
3697         case WXK_PAGEUP: {
3698         int flags = 0;
3699         int col = 0;
3700         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
3701         // PAGE-UP: first go the the first visible row
3702             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3703             newItem = GetFirstVisible(false, true);
3704         // if we are already there then scroll back one page
3705             if (newItem == m_curItem) {
3706                 abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
3707                 if (abs_p.y < 0) abs_p.y = 0;
3708                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3709             }
3710             // newItem should never be NULL
3711         } break;
3712 
3713         // <UP>: go to the previous sibling or for the last of its children, to the parent
3714         case WXK_UP: {
3715             newItem = GetPrevSibling (m_curItem);
3716             if (newItem) {
3717                 wxTreeItemIdValue cookie = 0;
3718                 while (IsExpanded (newItem) && HasChildren (newItem)) {
3719                     newItem = GetLastChild (newItem, cookie);
3720                 }
3721             }else {
3722                 newItem = GetItemParent (m_curItem);
3723                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3724                     newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
3725                 }
3726             }
3727         }break;
3728 
3729         // <LEFT>: if expanded collapse subtree, else go to the parent
3730         case WXK_LEFT: {
3731             if (IsExpanded (m_curItem)) {
3732                 Collapse (m_curItem);
3733             }else{
3734                 newItem = GetItemParent (m_curItem);
3735                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
3736                     newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
3737                 }
3738             }
3739         }break;
3740 
3741         // <RIGHT>: if possible expand subtree, else go go to the first child
3742         case WXK_RIGHT: {
3743             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
3744                 Expand (m_curItem);
3745             }else{
3746                 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3747                     wxTreeItemIdValue cookie = 0;
3748                     newItem = GetFirstChild (m_curItem, cookie);
3749                 }
3750             }
3751         }break;
3752 
3753         // <DOWN>: if expanded go to the first child, else to the next sibling, ect
3754         case WXK_DOWN: {
3755             if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
3756                 wxTreeItemIdValue cookie = 0;
3757                 newItem = GetFirstChild( m_curItem, cookie );
3758             }
3759             if (!newItem) {
3760                 wxTreeItemId parent = m_curItem;
3761                 do {
3762                     newItem = GetNextSibling (parent);
3763                     parent = GetItemParent (parent);
3764                 } while (!newItem && parent);
3765             }
3766         }break;
3767 
3768         // <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
3769         case WXK_PAGEDOWN: {
3770         int flags = 0;
3771         int col = 0;
3772         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
3773         // PAGE-UP: first go the the first visible row
3774             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3775             newItem = GetLastVisible(false, true);
3776         // if we are already there then scroll down one page
3777             if (newItem == m_curItem) {
3778                 abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
3779 //                if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
3780                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
3781             }
3782         // if we reached the empty area below the rows, return last item instead
3783             if (! newItem) newItem = GetLastVisible(false, false);
3784         } break;
3785 
3786         // <END>: go to last item of the root
3787         case WXK_END: {
3788             newItem = GetLastVisible (false, false);
3789         }break;
3790 
3791         // any char: go to the next matching string
3792         default:
3793             wxChar key = event.GetUnicodeKey();
3794             if (key == WXK_NONE) key = (wxChar)event.GetKeyCode();
3795             if (key  >= 32) {
3796                 // prepare search parameters
3797                 int mode = wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE;
3798                 if (!m_findTimer->IsRunning()) m_findStr.Clear();
3799                 m_findStr.Append (key);
3800                 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
3801                 wxTreeItemId prev = (wxTreeItemId*)NULL;
3802                 // try if current item or one of its followers matches
3803                 if (m_curItem) {
3804                     prev = (wxTreeItemId*)m_curItem;
3805                     for (int col=0; col<=GetColumnCount() - 1; col++) {
3806                         if (MatchItemText(GetItemText(prev, col), m_findStr, mode)) {
3807                             newItem = prev;
3808                             break;
3809                         }
3810                     }
3811                     if (! newItem) {
3812                         newItem = FindItem (prev, -1, m_findStr, mode);
3813                     };
3814                 }
3815                 // current item or does not match: try to find next
3816                 // still not match: search from beginning (but only if there was a current item i.e.we did not start from root already)
3817                 if (! newItem) {
3818                     prev = (wxTreeItemId*)NULL;
3819                     newItem = FindItem (prev, -1, m_findStr, mode);
3820                 }
3821                 // no match at all: remove just typed char to allow try with another extension
3822                 if (! newItem) m_findStr.RemoveLast();
3823             }
3824             event.Skip();
3825 
3826     }
3827 
3828     // select and show the new item
3829     if (newItem) {
3830         if (!event.ControlDown()) {
3831             bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
3832                                       HasFlag(wxTR_MULTIPLE));
3833             SelectItem (newItem, m_shiftItem, unselect_others);
3834         }
3835         EnsureVisible (newItem);
3836         wxTreeListItem *oldItem = m_curItem;
3837         SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
3838         RefreshLine (oldItem);
3839     }
3840 
3841 }
3842 
HitTest(const wxPoint & point,int & flags,int & column)3843 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
3844 
3845     int w, h;
3846     GetSize(&w, &h);
3847     flags=0;
3848     column = -1;
3849     if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
3850     if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
3851     if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
3852     if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
3853     if (flags) return wxTreeItemId();
3854 
3855     if (!m_rootItem) {
3856         flags = wxTREE_HITTEST_NOWHERE;
3857         column = -1;
3858         return wxTreeItemId();
3859     }
3860 
3861     wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
3862                                                this, flags, column, 0);
3863     if (!hit) {
3864         flags = wxTREE_HITTEST_NOWHERE;
3865         column = -1;
3866         return wxTreeItemId();
3867     }
3868     return hit;
3869 }
3870 
3871 // get the bounding rectangle of the item (or of its label only)
GetBoundingRect(const wxTreeItemId & itemId,wxRect & rect,bool WXUNUSED (textOnly)) const3872 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
3873                                             bool WXUNUSED(textOnly)) const {
3874     wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
3875 
3876     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
3877 
3878     int xUnit, yUnit;
3879     GetScrollPixelsPerUnit (&xUnit, &yUnit);
3880     int startX, startY;
3881     GetViewStart(& startX, & startY);
3882 
3883     rect.x = item->GetX() - startX * xUnit;
3884     rect.y = item->GetY() - startY * yUnit;
3885     rect.width = item->GetWidth();
3886     rect.height = GetLineHeight (item);
3887 
3888     return true;
3889 }
3890 
3891 /* **** */
3892 
EditLabel(const wxTreeItemId & item,int column)3893 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
3894 
3895 // validate
3896     if (!item.IsOk()) return;
3897     if (!((column >= 0) && (column < GetColumnCount()))) return;
3898 
3899 // cancel any editing
3900     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
3901 
3902 // prepare edit (position)
3903     m_editItem = (wxTreeListItem*) item.m_pItem;
3904 
3905     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
3906     te.SetInt (column);
3907     SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
3908 
3909     // ensure that the position of the item it calculated in any case
3910     if (m_dirty) CalculatePositions();
3911 
3912     wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
3913 
3914     // position & size are rather unpredictable (tsssk, tssssk) so were
3915     //  set by trial & error (on Win 2003 pre-XP style)
3916     int x = 0;
3917     int w = +4;  // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
3918     int y = m_editItem->GetY() + 1;  // this is cell, not text
3919     int h = m_editItem->GetHeight() - 1;  // consequence from above
3920     long style = 0;
3921     if (column == GetMainColumn()) {
3922         x += m_editItem->GetTextX(column) - 2;  // wrong by 2, don't know why
3923         w += m_editItem->GetWidth();
3924     } else {
3925         for (int i = 0; i < column; ++i) {
3926             if ( header_win->IsColumnShown(i) ) {
3927                 x += header_win->GetColumnWidth (i); // start of column
3928             }
3929 		}
3930         w += header_win->GetColumnWidth (column);  // currently non-main column width not pre-computed
3931     }
3932     switch (header_win->GetColumnAlignment (column)) {
3933         case wxALIGN_LEFT:   {style = wxTE_LEFT;   x -= 1; break;}
3934         case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
3935         case wxALIGN_RIGHT:  {style = wxTE_RIGHT;  x += 0; break;}  // yes, strange but that's the way it is
3936     }
3937     // wxTextCtrl simple border style requires 2 extra pixels before and after
3938     //  (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
3939     y -= 2; x -= 2;
3940     w += 4; h += 4;
3941 
3942     wxClientDC dc (this);
3943     PrepareDC (dc);
3944     x = dc.LogicalToDeviceX (x);
3945     y = dc.LogicalToDeviceY (y);
3946 
3947 // now do edit (change state, show control)
3948     m_editCol = column;  // only used in OnRenameAccept()
3949     m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
3950                                                this, m_editItem->GetText (column),
3951                                                wxPoint (x, y), wxSize (w, h), style);
3952     m_editControl->SelectAll();
3953     m_editControl->SetFocus();
3954 }
3955 
OnRenameTimer()3956 void wxTreeListMainWindow::OnRenameTimer() {
3957     EditLabel (m_curItem, GetCurrentColumn());
3958 }
3959 
OnRenameAccept(bool isCancelled)3960 void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
3961 
3962     // TODO if the validator fails this causes a crash
3963     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
3964     le.SetLabel( m_editRes );
3965     le.SetEditCanceled(isCancelled);
3966     le.SetInt(m_editCol);
3967     SendEvent(0, m_editItem, &le); if (! isCancelled  && le.IsAllowed())
3968     {
3969         SetItemText (m_editItem, le.GetInt(), le.GetLabel());
3970     }
3971 }
3972 
EndEdit(bool isCancelled)3973 void wxTreeListMainWindow::EndEdit(bool isCancelled) {
3974     if (m_editControl) { m_editControl->EndEdit(true); }
3975 }
3976 
OnMouse(wxMouseEvent & event)3977 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
3978 bool mayDrag = true;
3979 bool maySelect = true;  // may change selection
3980 bool mayClick = true;  // may process DOWN clicks to expand, send click events
3981 bool mayDoubleClick = true;  // implies mayClick
3982 bool bSkip = true;
3983 
3984     // send event to user code
3985     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
3986     if (!m_rootItem) return;
3987 
3988 
3989 // ---------- DETERMINE EVENT ----------
3990 /*
3991 wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
3992     event.LeftDown(), event.MiddleDown(), event.RightDown(),
3993     event.LeftUp(), event.MiddleUp(), event.RightUp(),
3994     event.LeftDClick(), event.Dragging());
3995 */
3996     wxPoint p = wxPoint (event.GetX(), event.GetY());
3997     int flags = 0;
3998     wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
3999                                                 this, flags, m_curColumn, 0);
4000     bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
4001     // we were dragging
4002     if (m_isDragging) {
4003         maySelect = mayDoubleClick = false;
4004     }
4005     // we are starting or continuing to drag
4006     if (event.Dragging()) {
4007         maySelect = mayDoubleClick = mayClick = false;
4008     }
4009     // crosshair area is special
4010     if (bCrosshair) {
4011         // left click does not select
4012         if (event.LeftDown()) maySelect = false;
4013         // double click is ignored
4014         mayDoubleClick = false;
4015     }
4016     // double click only if simple click
4017     if (mayDoubleClick) mayDoubleClick = mayClick;
4018     // selection conditions --remember also that selection exludes editing
4019     if (maySelect) maySelect = mayClick;  // yes, select/unselect requires a click
4020     if (maySelect) {
4021 
4022         // multiple selection mode complicates things, sometimes we
4023         //  select on button-up instead of down:
4024         if (HasFlag(wxTR_MULTIPLE)) {
4025 
4026             // CONTROL/SHIFT key used, don't care about anything else, will
4027             //  toggle on key down
4028             if (event.ControlDown() || event.ShiftDown()) {
4029                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
4030                 m_lastOnSame = false;  // prevent editing when keys are used
4031 
4032             // already selected item: to allow drag or contextual menu for multiple
4033             //  items, we only select/unselect on click-up --and only on LEFT
4034             // click, right is reserved for contextual menu
4035             } else if ((item != NULL && item->IsSelected())) {
4036                 maySelect = maySelect && event.LeftUp();
4037 
4038             // non-selected items: select on click-down like simple select (so
4039             //  that a right-click contextual menu may be chained)
4040             } else {
4041                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
4042             }
4043 
4044         // single-select is simply on left or right click-down
4045         } else {
4046             maySelect = maySelect && (event.LeftDown() || event.RightDown());
4047         }
4048     }
4049 
4050 
4051 // ----------  GENERAL ACTIONS  ----------
4052 
4053     // set focus if window clicked
4054     if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
4055 
4056     // tooltip change ?
4057     if (item != m_toolTipItem) {
4058 
4059         // not over an item, use global tip
4060         if (item == NULL) {
4061             m_toolTipItem = NULL;
4062             wxScrolledWindow::SetToolTip(m_toolTip);
4063 
4064         // over an item
4065         } else {
4066             const wxString *tip = item->GetToolTip();
4067 
4068             // is there an item-specific tip ?
4069             if (tip) {
4070                 m_toolTipItem = item;
4071                 wxScrolledWindow::SetToolTip(*tip);
4072 
4073             // no item tip, but we are in item-specific mode (SetItemToolTip()
4074             //  was called after SetToolTip() )
4075             } else if (m_isItemToolTip) {
4076                 m_toolTipItem = item;
4077                 wxScrolledWindow::SetToolTip(wxString());
4078 
4079             // no item tip, display global tip instead; item change ignored
4080             } else if (m_toolTipItem != NULL) {
4081                 m_toolTipItem = NULL;
4082                 wxScrolledWindow::SetToolTip(m_toolTip);
4083             }
4084         }
4085     }
4086 
4087 
4088 // ----------  HANDLE SIMPLE-CLICKS  (selection change, contextual menu) ----------
4089     if (mayClick) {
4090 
4091         // 2nd left-click on an item might trigger edit
4092         if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
4093 
4094         // left-click on haircross is expand (and no select)
4095         if (bCrosshair && event.LeftDown()) {
4096 
4097             bSkip = false;
4098 
4099             // note that we only toggle the item for a single click, double
4100             // click on the button doesn't do anything
4101             Toggle (item);
4102         }
4103 
4104         if (maySelect) {
4105             bSkip = false;
4106 
4107             // set / remember item at shift down before current item gets changed
4108             if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
4109                 if (!m_shiftItem) m_shiftItem = m_curItem;
4110             }else{
4111                 m_shiftItem = (wxTreeListItem*)NULL;
4112             }
4113 
4114             // how is selection altered
4115             // keep or discard already selected ?
4116             bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
4117                 event.ShiftDown()
4118              || event.ControlDown()
4119             ));
4120 
4121             // check is selection change is not vetoed
4122             if (SelectItem(item, m_shiftItem, unselect_others)) {
4123                 // make the new item the current item
4124                 EnsureVisible (item);
4125                 SetCurrentItem(item);
4126             }
4127         }
4128 
4129         // generate click & menu events
4130         if (event.MiddleDown()) {
4131             // our own event to set point
4132             wxTreeEvent nevent(0, 0);
4133             nevent.SetPoint(p);
4134             nevent.SetInt(m_curColumn);
4135             bSkip = false;
4136             SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item, &nevent);
4137         }
4138         if (event.RightDown()) {
4139             // our own event to set point
4140             wxTreeEvent nevent(0, 0);
4141             nevent.SetPoint(p);
4142             nevent.SetInt(m_curColumn);
4143             bSkip = false;
4144             SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item, &nevent);
4145         }
4146         if (event.RightUp()) {
4147             // our own event to set point
4148             wxTreeEvent nevent(0, 0);
4149             nevent.SetPoint(p);
4150             nevent.SetInt(m_curColumn);
4151             SendEvent(wxEVT_COMMAND_TREE_ITEM_MENU, item, &nevent);
4152         }
4153 
4154         // if 2nd left click finishes on same item, will edit it
4155         if (m_lastOnSame && event.LeftUp()) {
4156             if ((item == m_curItem) && (m_curColumn != -1) &&
4157                 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
4158                 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
4159             ){
4160                 m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
4161                 bSkip = false;
4162             }
4163             m_lastOnSame = false;
4164         }
4165     }
4166 
4167 
4168 // ----------  HANDLE DOUBLE-CLICKS  ----------
4169     if (mayDoubleClick && event.LeftDClick()) {
4170 
4171         bSkip = false;
4172 
4173         // double clicking should not start editing the item label
4174         m_editTimer->Stop();
4175         m_lastOnSame = false;
4176 
4177         // selection reset to that single item which was double-clicked
4178         if (SelectItem(item, (wxTreeItemId*)NULL, true)) {  // unselect others --return false if vetoed
4179 
4180             // selection change not vetoed, send activate event
4181             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
4182 
4183                 // if the user code didn't process the activate event,
4184                 // handle it ourselves by toggling the item when it is
4185                 // double clicked
4186                 if (item && item->HasPlus()) Toggle(item);
4187             }
4188         }
4189     }
4190 
4191 
4192 // ----------  HANDLE DRAGGING  ----------
4193 // NOTE: drag itself makes no change to selection
4194     if (mayDrag) {  // actually this is always true
4195 
4196         // CASE 1: we were dragging => continue, end, abort
4197         if (m_isDragging) {
4198 
4199             // CASE 1.1: click aborts drag:
4200             if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
4201 
4202                 bSkip = false;
4203 
4204                 // stop dragging
4205                 m_isDragStarted = m_isDragging = false;
4206                 if (HasCapture()) ReleaseMouse();
4207                 RefreshSelected();
4208 
4209             // CASE 1.2: still dragging
4210             } else if (event.Dragging()) {
4211 
4212                 ;; // nothing to do
4213 
4214             // CASE 1.3: dragging now ends normally
4215             } else {
4216 
4217                 bSkip = false;
4218 
4219                 // stop dragging
4220                 m_isDragStarted = m_isDragging = false;
4221                 if (HasCapture()) ReleaseMouse();
4222                 RefreshSelected();
4223 
4224                 // send drag end event
4225                 // our own event to set point
4226                 wxTreeEvent nevent(0, 0);
4227                 nevent.SetPoint(p);
4228                 nevent.SetInt(m_curColumn);
4229                 SendEvent(wxEVT_COMMAND_TREE_END_DRAG, item, &nevent);
4230             }
4231 
4232         // CASE 2: not were not dragging => continue, start
4233         } else if (event.Dragging()) {
4234 
4235             // We will really start dragging if we've moved beyond a few pixels
4236             if (m_isDragStarted) {
4237                 const int tolerance = 3;
4238                 int dx = abs(p.x - m_dragStartPos.x);
4239                 int dy = abs(p.y - m_dragStartPos.y);
4240                 if (dx <= tolerance && dy <= tolerance)
4241                     return;
4242             // determine drag start
4243             } else {
4244                 m_dragStartPos = p;
4245                 m_dragCol = GetCurrentColumn();
4246                 m_dragItem = item;
4247                 m_isDragStarted = true;
4248                 return;
4249             }
4250 
4251             bSkip = false;
4252 
4253             // we are now dragging
4254             m_isDragging = true;
4255             RefreshSelected();
4256             CaptureMouse(); // TODO: usefulness unclear
4257 
4258             wxTreeEvent nevent(0, 0);
4259             nevent.SetPoint(p);
4260             nevent.SetInt(m_dragCol);
4261             nevent.Veto();
4262             SendEvent(event.LeftIsDown()
4263                                   ? wxEVT_COMMAND_TREE_BEGIN_DRAG
4264                                   : wxEVT_COMMAND_TREE_BEGIN_RDRAG,
4265                       m_dragItem, &nevent);
4266         }
4267     }
4268 
4269 
4270     if (bSkip) event.Skip();
4271 }
4272 
4273 
OnIdle(wxIdleEvent & WXUNUSED (event))4274 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
4275     /* after all changes have been done to the tree control,
4276      * we actually redraw the tree when everything is over */
4277 
4278     if (!m_dirty) return;
4279 
4280     m_dirty = false;
4281 
4282     CalculatePositions();
4283     Refresh();
4284     AdjustMyScrollbars();
4285 }
4286 
OnScroll(wxScrollWinEvent & event)4287 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
4288 
4289     // send event to wxTreeListCtrl (for user code)
4290     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
4291 
4292     // TODO
4293     HandleOnScroll( event );
4294 
4295     if(event.GetOrientation() == wxHORIZONTAL) {
4296         m_owner->GetHeaderWindow()->Refresh();
4297         m_owner->GetHeaderWindow()->Update();
4298     }
4299 }
4300 
CalculateSize(wxTreeListItem * item,wxDC & dc)4301 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
4302     wxCoord text_w = 0;
4303     wxCoord text_h = 0;
4304 
4305     dc.SetFont (GetItemFont (item));
4306     dc.GetTextExtent (!item->GetText(m_main_column).empty()
4307             ? item->GetText (m_main_column)
4308             : _T(" "),  // blank to avoid zero height and no highlight width
4309         &text_w, &text_h);
4310     // restore normal font
4311     dc.SetFont (m_normalFont);
4312 
4313     int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
4314     if (max_h < 30) { // add 10% space if greater than 30 pixels
4315         max_h += 2; // minimal 2 pixel space
4316     }else{
4317         max_h += max_h / 10; // otherwise 10% space
4318     }
4319 
4320     item->SetHeight (max_h);
4321     if (max_h > m_lineHeight) m_lineHeight = max_h;
4322     item->SetWidth(m_imgWidth + text_w+2);
4323 }
4324 
4325 // -----------------------------------------------------------------------------
CalculateLevel(wxTreeListItem * item,wxDC & dc,int level,int & y,int x_colstart)4326 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
4327                                            int level, int &y, int x_colstart) {
4328 
4329     // calculate position of vertical lines
4330     int x = x_colstart + MARGIN; // start of column
4331     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
4332     if (HasButtons()) {
4333         x += (m_btnWidth-m_btnWidth2); // half button space
4334     }else{
4335         x += (m_indent-m_indent/2);
4336     }
4337     if (HasFlag(wxTR_HIDE_ROOT)) {
4338         x += m_indent * (level-1); // indent but not level 1
4339     }else{
4340         x += m_indent * level; // indent according to level
4341     }
4342 
4343     // a hidden root is not evaluated, but its children are always
4344     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
4345 
4346     CalculateSize( item, dc );
4347 
4348     // set its position
4349     item->SetX (x);
4350     item->SetY (y);
4351     y += GetLineHeight(item);
4352 
4353     // we don't need to calculate collapsed branches
4354     if ( !item->IsExpanded() ) return;
4355 
4356 Recurse:
4357     wxArrayTreeListItems& children = item->GetChildren();
4358     long n, count = (long)children.Count();
4359     ++level;
4360     for (n = 0; n < count; ++n) {
4361         CalculateLevel( children[n], dc, level, y, x_colstart );  // recurse
4362     }
4363 }
4364 
CalculatePositions()4365 void wxTreeListMainWindow::CalculatePositions() {
4366     if ( !m_rootItem ) return;
4367 
4368     wxClientDC dc(this);
4369     PrepareDC( dc );
4370 
4371     dc.SetFont( m_normalFont );
4372 
4373     dc.SetPen( m_dottedPen );
4374     //if(GetImageList() == NULL)
4375     // m_lineHeight = (int)(dc.GetCharHeight() + 4);
4376 
4377     int y = 2;
4378     int x_colstart = 0;
4379     for (int i = 0; i < (int)GetMainColumn(); ++i) {
4380         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
4381         x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
4382     }
4383     CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
4384 }
4385 
RefreshSubtree(wxTreeListItem * item)4386 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
4387     if (m_dirty) return;
4388 
4389     wxClientDC dc(this);
4390     PrepareDC(dc);
4391 
4392     int cw = 0;
4393     int ch = 0;
4394     GetVirtualSize( &cw, &ch );
4395 
4396     wxRect rect;
4397     rect.x = dc.LogicalToDeviceX( 0 );
4398     rect.width = cw;
4399     rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
4400     rect.height = ch;
4401 
4402     Refresh (true, &rect );
4403     AdjustMyScrollbars();
4404 }
4405 
RefreshLine(wxTreeListItem * item)4406 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
4407     if (m_dirty) return;
4408 
4409     wxClientDC dc(this);
4410     PrepareDC( dc );
4411 
4412     int cw = 0;
4413     int ch = 0;
4414     GetVirtualSize( &cw, &ch );
4415 
4416     wxRect rect;
4417     rect.x = dc.LogicalToDeviceX( 0 );
4418     rect.y = dc.LogicalToDeviceY( item->GetY() );
4419     rect.width = cw;
4420     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
4421 
4422     Refresh (true, &rect);
4423 }
4424 
RefreshSelected()4425 void wxTreeListMainWindow::RefreshSelected() {
4426     // TODO: this is awfully inefficient, we should keep the list of all
4427     //       selected items internally, should be much faster
4428     if (m_rootItem) {
4429         RefreshSelectedUnder (m_rootItem);
4430     }
4431 }
4432 
RefreshSelectedUnder(wxTreeListItem * item)4433 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
4434     if (item->IsSelected()) {
4435         RefreshLine (item);
4436     }
4437 
4438     const wxArrayTreeListItems& children = item->GetChildren();
4439     long count = (long)children.GetCount();
4440     for (long n = 0; n < count; n++ ) {
4441         RefreshSelectedUnder (children[n]);
4442     }
4443 }
4444 
4445 // ----------------------------------------------------------------------------
4446 // changing colours: we need to refresh the tree control
4447 // ----------------------------------------------------------------------------
4448 
SetBackgroundColour(const wxColour & colour)4449 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
4450     if (!wxWindow::SetBackgroundColour(colour)) return false;
4451 
4452     Refresh();
4453     return true;
4454 }
4455 
SetForegroundColour(const wxColour & colour)4456 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
4457     if (!wxWindow::SetForegroundColour(colour)) return false;
4458 
4459     Refresh();
4460     return true;
4461 }
4462 
SetItemText(const wxTreeItemId & itemId,int column,const wxString & text)4463 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
4464     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
4465 
4466     if (this->IsFrozen())
4467     {
4468         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
4469         item->SetText(column, text);
4470         m_dirty = true;
4471     }
4472     else
4473     {
4474         wxClientDC dc(this);
4475         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
4476         item->SetText(column, text);
4477         CalculateSize(item, dc);
4478         RefreshLine(item);
4479     };
4480 }
4481 
GetItemText(const wxTreeItemId & itemId,int column) const4482 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
4483     wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
4484 
4485     if( IsVirtual() )   return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
4486     else                return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
4487 }
4488 
GetItemText(wxTreeItemData * item,int column) const4489 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
4490    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
4491    return m_owner->OnGetItemText(item, column);
4492 }
4493 
SetFocus()4494 void wxTreeListMainWindow::SetFocus() {
4495     wxWindow::SetFocus();
4496 }
4497 
4498 
GetItemWidth(int column,wxTreeListItem * item)4499 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
4500     if (!item) return 0;
4501 
4502     // determine item width
4503     int w = 0, h = 0;
4504     wxFont font = GetItemFont (item);
4505     GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
4506     w += 2*MARGIN;
4507 
4508     // calculate width
4509     int width = w + 2*MARGIN;
4510     if (column == GetMainColumn()) {
4511         width += MARGIN;
4512         if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
4513         if (HasButtons()) width += m_btnWidth + LINEATROOT;
4514         if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
4515 
4516         // count indent level
4517         int level = 0;
4518         wxTreeListItem *parent = item->GetItemParent();
4519         wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
4520         while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
4521             level++;
4522             parent = parent->GetItemParent();
4523         }
4524         if (level) width += level * GetIndent();
4525     }
4526 
4527     return width;
4528 }
4529 
GetBestColumnWidth(int column,wxTreeItemId parent)4530 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
4531     int maxWidth, h;
4532     GetClientSize (&maxWidth, &h);
4533     int width = 0;
4534 
4535     // get root if on item
4536     if (!parent.IsOk()) parent = GetRootItem();
4537 
4538     // add root width
4539     if (!HasFlag(wxTR_HIDE_ROOT)) {
4540         int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
4541         if (width < w) width = w;
4542         if (width > maxWidth) return maxWidth;
4543     }
4544 
4545     wxTreeItemIdValue cookie = 0;
4546     wxTreeItemId item = GetFirstChild (parent, cookie);
4547     while (item.IsOk()) {
4548         int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
4549         if (width < w) width = w;
4550         if (width > maxWidth) return maxWidth;
4551 
4552         // check the children of this item
4553         if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
4554             int w = GetBestColumnWidth (column, item);
4555             if (width < w) width = w;
4556             if (width > maxWidth) return maxWidth;
4557         }
4558 
4559         // next sibling
4560         item = GetNextChild (parent, cookie);
4561     }
4562 
4563     return width;
4564 }
4565 
4566 
SendEvent(wxEventType event_type,wxTreeListItem * item,wxTreeEvent * event)4567 bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
4568 wxTreeEvent nevent (event_type, 0);
4569 
4570     if (event == NULL) {
4571         event = &nevent;
4572         event->SetInt (m_curColumn); // the mouse colum
4573     } else if (event_type) {
4574         event->SetEventType(event_type);
4575     }
4576 
4577     event->SetEventObject (m_owner);
4578     event->SetId(m_owner->GetId());
4579     if (item) {
4580         event->SetItem (item);
4581     }
4582 
4583     return m_owner->GetEventHandler()->ProcessEvent (*event);
4584 }
4585 
4586 #if wxCHECK_VERSION(3,1,3)
OnDpiChanged(wxDPIChangedEvent & e)4587 void wxTreeListMainWindow::OnDpiChanged(wxDPIChangedEvent& e)
4588 {
4589     m_dirty = true;
4590     m_lineHeight = LINEHEIGHT;
4591     if (m_imageListNormal)
4592     {
4593         CalculateLineHeight();
4594     };
4595     Refresh();
4596 }
4597 #endif
4598 
4599 //-----------------------------------------------------------------------------
4600 //  wxTreeListCtrl
4601 //-----------------------------------------------------------------------------
4602 
4603 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
4604 
4605 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
4606     EVT_SIZE(wxTreeListCtrl::OnSize)
4607 END_EVENT_TABLE();
4608 
Create(wxWindow * parent,wxWindowID id,const wxPoint & pos,const wxSize & size,long style,const wxValidator & validator,const wxString & name)4609 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
4610                             const wxPoint& pos,
4611                             const wxSize& size,
4612                             long style, const wxValidator &validator,
4613                             const wxString& name)
4614 {
4615     long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE |
4616                                 wxBORDER_RAISED | wxBORDER_STATIC);
4617     main_style |= wxWANTS_CHARS ;
4618     long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
4619 
4620     if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
4621        return false;
4622     }
4623     m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
4624                                            main_style, validator);
4625     m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
4626                                                wxPoint(0, 0), wxDefaultSize,
4627                                                wxTAB_TRAVERSAL);
4628     CalculateAndSetHeaderHeight();
4629     return true;
4630 }
4631 
CalculateAndSetHeaderHeight()4632 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
4633 {
4634     if (m_header_win) {
4635 
4636         // we use 'g' to get the descent, too
4637         int h;
4638 #ifdef __WXMSW__
4639         h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
4640 #else
4641         h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
4642 #endif
4643 
4644         // only update if changed
4645         if (h != m_headerHeight) {
4646             m_headerHeight = h;
4647             DoHeaderLayout();
4648         }
4649     }
4650 }
4651 
DoHeaderLayout()4652 void wxTreeListCtrl::DoHeaderLayout()
4653 {
4654     int w, h;
4655     GetClientSize(&w, &h);
4656     if (m_header_win) {
4657         m_header_win->SetSize (0, 0, w, m_headerHeight);
4658         m_header_win->Refresh();
4659     }
4660     if (m_main_win) {
4661         m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
4662     }
4663 }
4664 
OnSize(wxSizeEvent & WXUNUSED (event))4665 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
4666 {
4667     DoHeaderLayout();
4668 }
4669 
GetCount() const4670 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
4671 
GetIndent() const4672 unsigned int wxTreeListCtrl::GetIndent() const
4673 { return m_main_win->GetIndent(); }
4674 
SetIndent(unsigned int indent)4675 void wxTreeListCtrl::SetIndent(unsigned int indent)
4676 { m_main_win->SetIndent(indent); }
4677 
GetLineSpacing() const4678 unsigned int wxTreeListCtrl::GetLineSpacing() const
4679 { return m_main_win->GetLineSpacing(); }
4680 
SetLineSpacing(unsigned int spacing)4681 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
4682 { m_main_win->SetLineSpacing(spacing); }
4683 
GetImageList() const4684 wxImageList* wxTreeListCtrl::GetImageList() const
4685 { return m_main_win->GetImageList(); }
4686 
GetStateImageList() const4687 wxImageList* wxTreeListCtrl::GetStateImageList() const
4688 { return m_main_win->GetStateImageList(); }
4689 
GetButtonsImageList() const4690 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
4691 { return m_main_win->GetButtonsImageList(); }
4692 
SetImageList(wxImageList * imageList)4693 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
4694 { m_main_win->SetImageList(imageList); }
4695 
SetStateImageList(wxImageList * imageList)4696 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
4697 { m_main_win->SetStateImageList(imageList); }
4698 
SetButtonsImageList(wxImageList * imageList)4699 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
4700 { m_main_win->SetButtonsImageList(imageList); }
4701 
AssignImageList(wxImageList * imageList)4702 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
4703 { m_main_win->AssignImageList(imageList); }
4704 
AssignStateImageList(wxImageList * imageList)4705 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
4706 { m_main_win->AssignStateImageList(imageList); }
4707 
AssignButtonsImageList(wxImageList * imageList)4708 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
4709 { m_main_win->AssignButtonsImageList(imageList); }
4710 
4711 
4712 
GetItemText(const wxTreeItemId & item,int column) const4713 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
4714 { return m_main_win->GetItemText (item, column); }
4715 
GetItemImage(const wxTreeItemId & item,wxTreeItemIcon which) const4716 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
4717 { return m_main_win->GetItemImage(item, which); }
GetItemImage(const wxTreeItemId & item,int column) const4718 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
4719 { return m_main_win->GetItemImage(item, column); }
4720 
GetItemData(const wxTreeItemId & item) const4721 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
4722 { return m_main_win->GetItemData(item); }
GetItemData(const wxTreeItemId & item,int column) const4723 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
4724 { return m_main_win->GetItemData(item, column); }
4725 
GetItemBold(const wxTreeItemId & item) const4726 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
4727 { return m_main_win->GetItemBold(item); }
GetItemBold(const wxTreeItemId & item,int column) const4728 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
4729 { return m_main_win->GetItemBold(item, column); }
4730 
GetItemTextColour(const wxTreeItemId & item) const4731 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
4732 { return m_main_win->GetItemTextColour(item); }
GetItemTextColour(const wxTreeItemId & item,int column) const4733 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
4734 { return m_main_win->GetItemTextColour(item, column); }
4735 
GetItemBackgroundColour(const wxTreeItemId & item) const4736 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
4737 { return m_main_win->GetItemBackgroundColour(item); }
GetItemBackgroundColour(const wxTreeItemId & item,int column) const4738 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
4739 { return m_main_win->GetItemBackgroundColour(item, column); }
4740 
GetItemFont(const wxTreeItemId & item) const4741 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
4742 { return m_main_win->GetItemFont(item); }
GetItemFont(const wxTreeItemId & item,int column) const4743 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
4744 { return m_main_win->GetItemFont(item, column); }
4745 
4746 
4747 
SetItemHasChildren(const wxTreeItemId & item,bool has)4748 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
4749 { m_main_win->SetItemHasChildren(item, has); }
4750 
SetItemText(const wxTreeItemId & item,int column,const wxString & text)4751 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
4752 { m_main_win->SetItemText (item, column, text); }
4753 
SetItemImage(const wxTreeItemId & item,int image,wxTreeItemIcon which)4754 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
4755 { m_main_win->SetItemImage(item, image, which); }
SetItemImage(const wxTreeItemId & item,int column,int image)4756 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
4757 { m_main_win->SetItemImage(item, column, image); }
4758 
SetItemData(const wxTreeItemId & item,wxTreeItemData * data)4759 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data)
4760 { m_main_win->SetItemData(item, data); }
SetItemData(const wxTreeItemId & item,int column,wxTreeItemData * data)4761 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
4762 { m_main_win->SetItemData(item, column, data); }
4763 
SetItemBold(const wxTreeItemId & item,bool bold)4764 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold)
4765 { m_main_win->SetItemBold(item, bold); }
SetItemBold(const wxTreeItemId & item,int column,bool bold)4766 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
4767 { m_main_win->SetItemBold(item, column, bold); }
4768 
SetItemTextColour(const wxTreeItemId & item,const wxColour & colour)4769 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour)
4770 { m_main_win->SetItemTextColour(item, colour); }
SetItemTextColour(const wxTreeItemId & item,int column,const wxColour & colour)4771 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
4772 { m_main_win->SetItemTextColour(item, column, colour); }
4773 
SetItemBackgroundColour(const wxTreeItemId & item,const wxColour & colour)4774 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour)
4775 { m_main_win->SetItemBackgroundColour(item, colour); }
SetItemBackgroundColour(const wxTreeItemId & item,int column,const wxColour & colour)4776 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
4777 { m_main_win->SetItemBackgroundColour(item, column, colour); }
4778 
SetItemFont(const wxTreeItemId & item,const wxFont & font)4779 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font)
4780 { m_main_win->SetItemFont(item, font); }
SetItemFont(const wxTreeItemId & item,int column,const wxFont & font)4781 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
4782 { m_main_win->SetItemFont(item, column, font); }
4783 
4784 
4785 
SetFont(const wxFont & font)4786 bool wxTreeListCtrl::SetFont(const wxFont& font)
4787 {
4788     if (m_header_win) {
4789         m_header_win->SetFont(font);
4790         CalculateAndSetHeaderHeight();
4791         m_header_win->Refresh();
4792     }
4793     if (m_main_win) {
4794         return m_main_win->SetFont(font);
4795     }else{
4796         return false;
4797     }
4798 }
4799 
SetWindowStyleFlag(long style)4800 void wxTreeListCtrl::SetWindowStyleFlag(long style)
4801 {
4802     if (m_main_win)
4803     {
4804         long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE | wxBORDER_RAISED | wxBORDER_STATIC);
4805         main_style |= wxWANTS_CHARS;
4806         m_main_win->SetWindowStyle(main_style);
4807     };
4808     m_windowStyle = style & ~(wxVSCROLL | wxHSCROLL);
4809     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
4810 }
4811 
GetWindowStyleFlag() const4812 long wxTreeListCtrl::GetWindowStyleFlag() const
4813 {
4814     long style = m_windowStyle;
4815     if(m_main_win)
4816         style |= m_main_win->GetWindowStyle();
4817     return style;
4818 }
4819 
IsVisible(const wxTreeItemId & item,bool fullRow,bool within) const4820 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4821 { return m_main_win->IsVisible(item, fullRow, within); }
4822 
HasChildren(const wxTreeItemId & item) const4823 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
4824 { return m_main_win->HasChildren(item); }
4825 
IsExpanded(const wxTreeItemId & item) const4826 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
4827 { return m_main_win->IsExpanded(item); }
4828 
IsSelected(const wxTreeItemId & item) const4829 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
4830 { return m_main_win->IsSelected(item); }
4831 
GetChildrenCount(const wxTreeItemId & item,bool rec)4832 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
4833 { return m_main_win->GetChildrenCount(item, rec); }
4834 
GetRootItem() const4835 wxTreeItemId wxTreeListCtrl::GetRootItem() const
4836 { return m_main_win->GetRootItem(); }
4837 
GetSelection() const4838 wxTreeItemId wxTreeListCtrl::GetSelection() const
4839 { return m_main_win->GetSelection(); }
4840 
GetSelections(wxArrayTreeItemIds & arr) const4841 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
4842 { return m_main_win->GetSelections(arr); }
4843 
GetItemParent(const wxTreeItemId & item) const4844 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
4845 { return m_main_win->GetItemParent(item); }
4846 
GetFirstChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4847 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
4848                                             wxTreeItemIdValue& cookie) const
4849 { return m_main_win->GetFirstChild(item, cookie); }
4850 
GetNextChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4851 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
4852                                            wxTreeItemIdValue& cookie) const
4853 { return m_main_win->GetNextChild(item, cookie); }
4854 
GetPrevChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4855 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
4856                                            wxTreeItemIdValue& cookie) const
4857 { return m_main_win->GetPrevChild(item, cookie); }
4858 
GetLastChild(const wxTreeItemId & item,wxTreeItemIdValue & cookie) const4859 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
4860                                            wxTreeItemIdValue& cookie) const
4861 { return m_main_win->GetLastChild(item, cookie); }
4862 
4863 
GetNextSibling(const wxTreeItemId & item) const4864 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
4865 { return m_main_win->GetNextSibling(item); }
4866 
GetPrevSibling(const wxTreeItemId & item) const4867 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
4868 { return m_main_win->GetPrevSibling(item); }
4869 
GetNext(const wxTreeItemId & item) const4870 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
4871 { return m_main_win->GetNext(item, true); }
4872 
GetPrev(const wxTreeItemId & item) const4873 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
4874 { return m_main_win->GetPrev(item, true); }
4875 
GetFirstExpandedItem() const4876 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
4877 { return m_main_win->GetFirstExpandedItem(); }
4878 
GetNextExpanded(const wxTreeItemId & item) const4879 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
4880 { return m_main_win->GetNextExpanded(item); }
4881 
GetPrevExpanded(const wxTreeItemId & item) const4882 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
4883 { return m_main_win->GetPrevExpanded(item); }
4884 
GetFirstVisibleItem(bool fullRow) const4885 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
4886 { return GetFirstVisible(fullRow); }
GetFirstVisible(bool fullRow,bool within) const4887 wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
4888 { return m_main_win->GetFirstVisible(fullRow, within); }
4889 
GetLastVisible(bool fullRow,bool within) const4890 wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
4891 { return m_main_win->GetLastVisible(fullRow, within); }
4892 
GetNextVisible(const wxTreeItemId & item,bool fullRow,bool within) const4893 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4894 { return m_main_win->GetNextVisible(item, fullRow, within); }
4895 
GetPrevVisible(const wxTreeItemId & item,bool fullRow,bool within) const4896 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
4897 { return m_main_win->GetPrevVisible(item, fullRow, within); }
4898 
AddRoot(const wxString & text,int image,int selectedImage,wxTreeItemData * data)4899 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
4900                                       int selectedImage, wxTreeItemData* data)
4901 { return m_main_win->AddRoot (text, image, selectedImage, data); }
4902 
PrependItem(const wxTreeItemId & parent,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4903 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
4904                                          const wxString& text, int image,
4905                                          int selectedImage,
4906                                          wxTreeItemData* data)
4907 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
4908 
InsertItem(const wxTreeItemId & parent,const wxTreeItemId & previous,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4909 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4910                                         const wxTreeItemId& previous,
4911                                         const wxString& text, int image,
4912                                         int selectedImage,
4913                                         wxTreeItemData* data)
4914 {
4915     return m_main_win->InsertItem(parent, previous, text, image,
4916                                   selectedImage, data);
4917 }
4918 
InsertItem(const wxTreeItemId & parent,size_t index,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4919 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
4920                                         size_t index,
4921                                         const wxString& text, int image,
4922                                         int selectedImage,
4923                                         wxTreeItemData* data)
4924 {
4925     return m_main_win->InsertItem(parent, index, text, image,
4926                                   selectedImage, data);
4927 }
4928 
AppendItem(const wxTreeItemId & parent,const wxString & text,int image,int selectedImage,wxTreeItemData * data)4929 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
4930                                         const wxString& text, int image,
4931                                         int selectedImage,
4932                                         wxTreeItemData* data)
4933 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
4934 
Delete(const wxTreeItemId & item)4935 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
4936 { m_main_win->Delete(item); }
4937 
DeleteChildren(const wxTreeItemId & item)4938 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
4939 { m_main_win->DeleteChildren(item); }
4940 
DeleteRoot()4941 void wxTreeListCtrl::DeleteRoot()
4942 { m_main_win->DeleteRoot(); }
4943 
Expand(const wxTreeItemId & item)4944 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
4945 { m_main_win->Expand(item); }
4946 
ExpandAll(const wxTreeItemId & item)4947 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
4948 { m_main_win->ExpandAll(item); }
4949 
Collapse(const wxTreeItemId & item)4950 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
4951 { m_main_win->Collapse(item); }
4952 
CollapseAndReset(const wxTreeItemId & item)4953 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
4954 { m_main_win->CollapseAndReset(item); }
4955 
Toggle(const wxTreeItemId & item)4956 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
4957 { m_main_win->Toggle(item); }
4958 
Unselect()4959 void wxTreeListCtrl::Unselect()
4960 { m_main_win->Unselect(); }
4961 
UnselectAll()4962 void wxTreeListCtrl::UnselectAll()
4963 { m_main_win->UnselectAll(); }
4964 
SelectItem(const wxTreeItemId & item,const wxTreeItemId & last,bool unselect_others)4965 bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
4966                                 bool unselect_others)
4967 { return m_main_win->SelectItem (item, last, unselect_others); }
4968 
SelectAll()4969 void wxTreeListCtrl::SelectAll()
4970 { m_main_win->SelectAll(); }
4971 
EnsureVisible(const wxTreeItemId & item)4972 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
4973 { m_main_win->EnsureVisible(item); }
4974 
ScrollTo(const wxTreeItemId & item)4975 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
4976 { m_main_win->ScrollTo(item); }
4977 
HitTest(const wxPoint & pos,int & flags,int & column)4978 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
4979 {
4980     wxPoint p = pos;
4981     return m_main_win->HitTest (p, flags, column);
4982 }
4983 
GetBoundingRect(const wxTreeItemId & item,wxRect & rect,bool textOnly) const4984 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
4985                                      bool textOnly) const
4986 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
4987 
EditLabel(const wxTreeItemId & item,int column)4988 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
4989     { m_main_win->EditLabel (item, column); }
EndEdit(bool isCancelled)4990 void wxTreeListCtrl::EndEdit(bool isCancelled)
4991     { m_main_win->EndEdit(isCancelled); }
4992 
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2)4993 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
4994 {
4995     // do the comparison here and not in m_main_win in order to allow
4996     // override in child class
4997     return wxStrcmp(GetItemText(item1), GetItemText(item2));
4998 }
OnCompareItems(const wxTreeItemId & item1,const wxTreeItemId & item2,int column)4999 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
5000 {
5001     // do the comparison here and not in m_main_win in order to allow
5002     // override in child class
5003     return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
5004 }
5005 
SortChildren(const wxTreeItemId & item,int column,bool reverseOrder)5006 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
5007 { m_main_win->SortChildren(item, column, reverseOrder); }
5008 
FindItem(const wxTreeItemId & item,int column,const wxString & str,int mode)5009 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
5010 { return m_main_win->FindItem (item, column, str, mode); }
5011 
SetDragItem(const wxTreeItemId & item)5012 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
5013 { m_main_win->SetDragItem (item); }
5014 
SetBackgroundColour(const wxColour & colour)5015 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
5016 {
5017     if (!m_main_win) return false;
5018     return m_main_win->SetBackgroundColour(colour);
5019 }
5020 
SetForegroundColour(const wxColour & colour)5021 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
5022 {
5023     if (!m_main_win) return false;
5024     return m_main_win->SetForegroundColour(colour);
5025 }
5026 
GetColumnCount() const5027 int wxTreeListCtrl::GetColumnCount() const
5028 { return m_main_win->GetColumnCount(); }
5029 
SetColumnWidth(int column,int width)5030 void wxTreeListCtrl::SetColumnWidth(int column, int width)
5031 {
5032     m_header_win->SetColumnWidth (column, width);
5033     m_header_win->Refresh();
5034 }
5035 
GetColumnWidth(int column) const5036 int wxTreeListCtrl::GetColumnWidth(int column) const
5037 { return m_header_win->GetColumnWidth(column); }
5038 
SetMainColumn(int column)5039 void wxTreeListCtrl::SetMainColumn(int column)
5040 { m_main_win->SetMainColumn(column); }
5041 
GetMainColumn() const5042 int wxTreeListCtrl::GetMainColumn() const
5043 { return m_main_win->GetMainColumn(); }
5044 
SetColumnText(int column,const wxString & text)5045 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
5046 {
5047     m_header_win->SetColumnText (column, text);
5048     m_header_win->Refresh();
5049 }
5050 
GetColumnText(int column) const5051 wxString wxTreeListCtrl::GetColumnText(int column) const
5052 { return m_header_win->GetColumnText(column); }
5053 
AddColumn(const wxTreeListColumnInfo & colInfo)5054 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
5055 {
5056     m_header_win->AddColumn (colInfo);
5057     DoHeaderLayout();
5058 }
5059 
InsertColumn(int before,const wxTreeListColumnInfo & colInfo)5060 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
5061 {
5062     m_header_win->InsertColumn (before, colInfo);
5063     m_header_win->Refresh();
5064 }
5065 
RemoveColumn(int column)5066 void wxTreeListCtrl::RemoveColumn(int column)
5067 {
5068     m_header_win->RemoveColumn (column);
5069     m_header_win->Refresh();
5070 }
5071 
SetColumn(int column,const wxTreeListColumnInfo & colInfo)5072 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
5073 {
5074     m_header_win->SetColumn (column, colInfo);
5075     m_header_win->Refresh();
5076 }
5077 
GetColumn(int column) const5078 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
5079 { return m_header_win->GetColumn(column); }
5080 
GetColumn(int column)5081 wxTreeListColumnInfo wxTreeListCtrl::GetColumn(int column)
5082 { return m_header_win->GetColumn(column); }
5083 
SetColumnImage(int column,int image)5084 void wxTreeListCtrl::SetColumnImage(int column, int image)
5085 {
5086     m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
5087     m_header_win->Refresh();
5088 }
5089 
GetColumnImage(int column) const5090 int wxTreeListCtrl::GetColumnImage(int column) const
5091 {
5092     return m_header_win->GetColumn(column).GetImage();
5093 }
5094 
SetColumnEditable(int column,bool shown)5095 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
5096 {
5097     m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
5098 }
5099 
SetColumnShown(int column,bool shown)5100 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
5101 {
5102     wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
5103     m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
5104     m_header_win->Refresh();
5105 }
5106 
IsColumnEditable(int column) const5107 bool wxTreeListCtrl::IsColumnEditable(int column) const
5108 {
5109     return m_header_win->GetColumn(column).IsEditable();
5110 }
5111 
IsColumnShown(int column) const5112 bool wxTreeListCtrl::IsColumnShown(int column) const
5113 {
5114     return m_header_win->GetColumn(column).IsShown();
5115 }
5116 
SetColumnAlignment(int column,int flag)5117 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
5118 {
5119     m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
5120     m_header_win->Refresh();
5121 }
5122 
GetColumnAlignment(int column) const5123 int wxTreeListCtrl::GetColumnAlignment(int column) const
5124 {
5125     return m_header_win->GetColumn(column).GetAlignment();
5126 }
5127 
Refresh(bool erase,const wxRect * rect)5128 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
5129 {
5130     m_main_win->Refresh (erase, rect);
5131     m_header_win->Refresh (erase, rect);
5132 }
5133 
SetFocus()5134 void wxTreeListCtrl::SetFocus()
5135 { m_main_win->SetFocus(); }
5136 
DoGetBestSize() const5137 wxSize wxTreeListCtrl::DoGetBestSize() const
5138 {
5139     wxSize bestSizeHeader = m_header_win->GetBestSize();
5140     wxSize bestSizeMain = m_main_win->GetBestSize();
5141     return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
5142 }
5143 
OnGetItemText(wxTreeItemData * WXUNUSED (item),long WXUNUSED (column)) const5144 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
5145 {
5146     return wxEmptyString;
5147 }
5148 
SetToolTip(const wxString & tip)5149 void wxTreeListCtrl::SetToolTip(const wxString& tip) {
5150     m_header_win->SetToolTip(tip);
5151     m_main_win->SetToolTip(tip);
5152 }
SetToolTip(wxToolTip * tip)5153 void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
5154     m_header_win->SetToolTip(tip);
5155     m_main_win->SetToolTip(tip);
5156 }
5157 
SetItemToolTip(const wxTreeItemId & item,const wxString & tip)5158 void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
5159     m_main_win->SetItemToolTip(item, tip);
5160 }
5161 
SetCurrentItem(const wxTreeItemId & itemId)5162 void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
5163     m_main_win->SetCurrentItem(itemId);
5164 }
5165 
SetItemParent(const wxTreeItemId & parent,const wxTreeItemId & item)5166 void wxTreeListCtrl::SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item) {
5167     m_main_win->SetItemParent(parent, item);
5168 }
5169 
5170 //-----------------------------------------------------------------------------
5171 // wxTreeListCtrlXmlHandler - XRC support for wxTreeListCtrl
5172 //-----------------------------------------------------------------------------
5173 
5174 #if wxUSE_XRC
5175 
IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrlXmlHandler,wxXmlResourceHandler)5176 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrlXmlHandler, wxXmlResourceHandler)
5177 
5178 wxTreeListCtrlXmlHandler::wxTreeListCtrlXmlHandler() : wxXmlResourceHandler() {
5179 
5180 #define wxTR_NO_BUTTONS              0x0000     // for convenience
5181 #define wxTR_HAS_BUTTONS             0x0001     // draw collapsed/expanded btns
5182 #define wxTR_NO_LINES                0x0004     // don't draw lines at all
5183 #define wxTR_LINES_AT_ROOT           0x0008     // connect top-level nodes
5184 #define wxTR_TWIST_BUTTONS           0x0010     // still used by wxTreeListCtrl
5185 
5186 #define wxTR_SINGLE                  0x0000     // for convenience
5187 #define wxTR_MULTIPLE                0x0020     // can select multiple items
5188 #define wxTR_EXTENDED                0x0040     // TODO: allow extended selection
5189 #define wxTR_HAS_VARIABLE_ROW_HEIGHT 0x0080     // what it says
5190 
5191 #define wxTR_EDIT_LABELS             0x0200     // can edit item labels
5192 #define wxTR_ROW_LINES               0x0400     // put border around items
5193 #define wxTR_HIDE_ROOT               0x0800     // don't display root node
5194 
5195 #define wxTR_FULL_ROW_HIGHLIGHT      0x2000     // highlight full horz space
5196 
5197 #ifdef __WXGTK20__
5198 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_NO_LINES)
5199 #else
5200 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT)
5201 #endif
5202 
5203 // wxTreeCtrl styles, taken from treebase.h
5204 	XRC_ADD_STYLE(wxTR_NO_BUTTONS);
5205 	XRC_ADD_STYLE(wxTR_HAS_BUTTONS);
5206 	XRC_ADD_STYLE(wxTR_NO_LINES);
5207 	XRC_ADD_STYLE(wxTR_LINES_AT_ROOT);
5208 	XRC_ADD_STYLE(wxTR_TWIST_BUTTONS);
5209 
5210 	XRC_ADD_STYLE(wxTR_SINGLE);
5211 	XRC_ADD_STYLE(wxTR_MULTIPLE);
5212 #if WXWIN_COMPATIBILITY_2_8
5213     // according to wxWidgets release notes, wxTR_EXTENDED is deprecated
5214     XRC_ADD_STYLE(wxTR_EXTENDED);
5215 #endif // WXWIN_COMPATIBILITY_2_8
5216     XRC_ADD_STYLE(wxTR_HAS_VARIABLE_ROW_HEIGHT);
5217 
5218     XRC_ADD_STYLE(wxTR_EDIT_LABELS);
5219     XRC_ADD_STYLE(wxTR_ROW_LINES);
5220     XRC_ADD_STYLE(wxTR_HIDE_ROOT);
5221 
5222     XRC_ADD_STYLE(wxTR_FULL_ROW_HIGHLIGHT);
5223 
5224     XRC_ADD_STYLE(wxTR_DEFAULT_STYLE);
5225 
5226 // wxTreeListCtrl-specific styles
5227     XRC_ADD_STYLE(wxTR_COLUMN_LINES);
5228     XRC_ADD_STYLE(wxTR_VIRTUAL);
5229 
5230 // standard wxWidgets styles
5231 	AddWindowStyles();
5232 }
5233 
DoCreateResource()5234 wxObject *wxTreeListCtrlXmlHandler::DoCreateResource() {
5235 	XRC_MAKE_INSTANCE(tlc, wxTreeListCtrl);
5236 	tlc->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName());
5237     SetupWindow(tlc);
5238 	return tlc;
5239 }
5240 
CanHandle(wxXmlNode * node)5241 bool wxTreeListCtrlXmlHandler::CanHandle(wxXmlNode * node) {
5242 	return IsOfClass(node, wxT("TreeListCtrl"));
5243 }
5244 
5245 #endif  // wxUSE_XRC
5246 
5247 } // namespace wxcode
5248