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