treelistctrl.cpp

Go to the documentation of this file.
00001 
00002 // Name:        treelistctrl.cpp
00003 // Purpose:     multi column tree control implementation
00004 // Created:     01/02/97
00005 // Author:      Robert Roebling
00006 // Maintainer:  Ronan Chartois (pgriddev)
00007 // Version:     $Id: treelistctrl.cpp 3062 2012-09-23 13:48:23Z pgriddev $
00008 // Copyright:   (c) 2004-2011 Robert Roebling, Julian Smart, Alberto Griggio,
00009 //              Vadim Zeitlin, Otto Wyss, Ronan Chartois
00010 // Licence:     wxWindows
00012 
00013 // ===========================================================================
00014 // declarations
00015 // ===========================================================================
00016 
00017 // ---------------------------------------------------------------------------
00018 // headers
00019 // ---------------------------------------------------------------------------
00020 
00021 #if defined(__GNUG__) && !defined(__APPLE__)
00022   #pragma implementation "treelistctrl.h"
00023 #endif
00024 
00025 // For compilers that support precompilation, includes "wx.h".
00026 #include "wx/wxprec.h"
00027 
00028 #ifdef __BORLANDC__
00029     #pragma hdrstop
00030 #endif
00031 
00032 
00033 #include <wx/app.h>
00034 #include <wx/treebase.h>
00035 #include <wx/timer.h>
00036 #include <wx/textctrl.h>
00037 #include <wx/imaglist.h>
00038 #include <wx/settings.h>
00039 #include <wx/dcclient.h>
00040 #include <wx/dcscreen.h>
00041 #include <wx/scrolwin.h>
00042 #include <wx/dcmemory.h>
00043 #if wxCHECK_VERSION(2, 7, 0)
00044    #include <wx/renderer.h>
00045 #endif
00046 #include <wx/apptrait.h>
00047 #include <wx/dcbuffer.h>
00048 #include <wx/tooltip.h>
00049 #include <wx/hashmap.h>
00050 #include <wx/dynarray.h>
00051 #include <wx/arrimpl.cpp>
00052 
00053 #if defined(__WXMAC__) && defined(__WXOSX__)
00054 #include "wx/osx/private.h"
00055 #elif defined(__WXMAC__)
00056 #include "wx/mac/private.h"
00057 #endif
00058 
00059 #include "treelistctrl.h"
00060 
00061 #include <wx/log.h>  // only required for debugging purpose
00062 #include <wx/msgdlg.h>  // only required for debugging purpose
00063 #include <algorithm>
00064 
00065 
00066 #if wxCHECK_VERSION(2,9,0)
00067 namespace wxcode {
00068 #endif
00069 
00070 // ---------------------------------------------------------------------------
00071 // array types
00072 // ---------------------------------------------------------------------------
00073 
00074 class wxTreeListItem;
00075 class wxTreeListItemCellAttr;
00076 
00077 #if !wxCHECK_VERSION(2, 5, 0)
00078 WX_DEFINE_ARRAY(wxTreeListItem *, wxArrayTreeListItems);
00079 #else
00080 WX_DEFINE_ARRAY_PTR(wxTreeListItem *, wxArrayTreeListItems);
00081 #endif
00082 
00083 WX_DECLARE_OBJARRAY(wxTreeListColumnInfo, wxArrayTreeListColumnInfo);
00084 WX_DEFINE_OBJARRAY(wxArrayTreeListColumnInfo);
00085 
00086 
00087 WX_DECLARE_HASH_MAP( int, wxTreeListItemCellAttr *, wxIntegerHash, wxIntegerEqual, wxTreeListItemCellAttrHash );
00088 
00089 // --------------------------------------------------------------------------
00090 // constants
00091 // --------------------------------------------------------------------------
00092 
00093 static const int NO_IMAGE = -1;
00094 
00095 static const int LINEHEIGHT = 10;
00096 static const int LINEATROOT = 5;
00097 static const int MARGIN = 2;
00098 static const int MININDENT = 16;
00099 static const int BTNWIDTH = 9;
00100 static const int BTNHEIGHT = 9;
00101 static const int EXTRA_WIDTH = 4;
00102 static const int EXTRA_HEIGHT = 4;
00103 static const int HEADER_OFFSET_X = 0;  // changed from 1 to 0 on 2009.03.10 for Windows (other OS untested)
00104 static const int HEADER_OFFSET_Y = 1;
00105 
00106 static const int DRAG_TIMER_TICKS = 250; // minimum drag wait time in ms
00107 static const int FIND_TIMER_TICKS = 500; // minimum find wait time in ms
00108 static const int RENAME_TIMER_TICKS = 250; // minimum rename wait time in ms
00109 
00110 const wxChar* wxTreeListCtrlNameStr = _T("treelistctrl");
00111 
00112 static wxTreeListColumnInfo wxInvalidTreeListColumnInfo;
00113 
00114 
00115 // ---------------------------------------------------------------------------
00116 // private classes
00117 // ---------------------------------------------------------------------------
00118 
00119 class  wxTreeListHeaderWindow : public wxWindow
00120 {
00121 protected:
00122     wxTreeListMainWindow *m_owner;
00123     const wxCursor *m_currentCursor;
00124     const wxCursor *m_resizeCursor;
00125     bool m_isDragging;
00126 
00127     // column being resized
00128     int m_column;
00129 
00130     // divider line position in logical (unscrolled) coords
00131     int m_currentX;
00132 
00133     // minimal position beyond which the divider line can't be dragged in
00134     // logical coords
00135     int m_minX;
00136 
00137     wxArrayTreeListColumnInfo m_columns;
00138 
00139     // total width of the columns
00140     int m_total_col_width;
00141 
00142 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
00143     // which col header is currently highlighted with mouse-over
00144     int m_hotTrackCol;
00145     int XToCol(int x);
00146     void RefreshColLabel(int col);
00147 #endif
00148 
00149 public:
00150     wxTreeListHeaderWindow();
00151 
00152     wxTreeListHeaderWindow( wxWindow *win,
00153                             wxWindowID id,
00154                             wxTreeListMainWindow *owner,
00155                             const wxPoint &pos = wxDefaultPosition,
00156                             const wxSize &size = wxDefaultSize,
00157                             long style = 0,
00158                             const wxString &name = _T("wxtreelistctrlcolumntitles") );
00159 
00160     virtual ~wxTreeListHeaderWindow();
00161 
00162     void DoDrawRect( wxDC *dc, int x, int y, int w, int h );
00163     void DrawCurrent();
00164     void AdjustDC(wxDC& dc);
00165 
00166     void OnPaint( wxPaintEvent &event );
00167     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // reduce flicker
00168     void OnMouse( wxMouseEvent &event );
00169     void OnSetFocus( wxFocusEvent &event );
00170 
00171     // total width of all columns
00172     int GetWidth() const { return m_total_col_width; }
00173 
00174     // column manipulation
00175     int GetColumnCount() const { return (int)m_columns.GetCount(); }
00176 
00177     void AddColumn (const wxTreeListColumnInfo& colInfo);
00178 
00179     void InsertColumn (int before, const wxTreeListColumnInfo& colInfo);
00180 
00181     void RemoveColumn (int column);
00182 
00183     // column information manipulation
00184     const wxTreeListColumnInfo& GetColumn (int column) const{
00185         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00186                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
00187         return m_columns[column];
00188     }
00189     wxTreeListColumnInfo& GetColumn (int column) {
00190         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00191                      wxInvalidTreeListColumnInfo, _T("Invalid column"));
00192         return m_columns[column];
00193     }
00194     void SetColumn (int column, const wxTreeListColumnInfo& info);
00195 
00196     wxString GetColumnText (int column) const {
00197         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00198                      wxEmptyString, _T("Invalid column"));
00199         return m_columns[column].GetText();
00200     }
00201     void SetColumnText (int column, const wxString& text) {
00202         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
00203                      _T("Invalid column"));
00204         m_columns[column].SetText (text);
00205     }
00206 
00207     int GetColumnAlignment (int column) const {
00208         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00209                      wxALIGN_LEFT, _T("Invalid column"));
00210         return m_columns[column].GetAlignment();
00211     }
00212     void SetColumnAlignment (int column, int flag) {
00213         wxCHECK_RET ((column >= 0) && (column < GetColumnCount()),
00214                      _T("Invalid column"));
00215         m_columns[column].SetAlignment (flag);
00216     }
00217 
00218     int GetColumnWidth (int column) const {
00219         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00220                      -1, _T("Invalid column"));
00221         return m_columns[column].GetWidth();
00222     }
00223     void SetColumnWidth (int column, int width);
00224 
00225     bool IsColumnEditable (int column) const {
00226         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00227                      false, _T("Invalid column"));
00228         return m_columns[column].IsEditable();
00229     }
00230 
00231     bool IsColumnShown (int column) const {
00232         wxCHECK_MSG ((column >= 0) && (column < GetColumnCount()),
00233                      true, _T("Invalid column"));
00234         return m_columns[column].IsShown();
00235     }
00236 
00237     // needs refresh
00238     bool m_dirty;
00239 
00240 private:
00241     // common part of all ctors
00242     void Init();
00243 
00244     void SendListEvent(wxEventType type, wxPoint pos);
00245 
00246     DECLARE_DYNAMIC_CLASS(wxTreeListHeaderWindow)
00247     DECLARE_EVENT_TABLE()
00248 };
00249 
00250 
00251 //-----------------------------------------------------------------------------
00252 
00253 class wxEditTextCtrl;
00254 
00255 
00256 // this is the "true" control
00257 class  wxTreeListMainWindow: public wxScrolledWindow
00258 {
00259 friend class wxTreeListItem;
00260 friend class wxTreeListRenameTimer;
00261 friend class wxEditTextCtrl;
00262 
00263 public:
00264     // creation
00265     // --------
00266     wxTreeListMainWindow() { Init(); }
00267 
00268     wxTreeListMainWindow (wxTreeListCtrl *parent, wxWindowID id = -1,
00269                const wxPoint& pos = wxDefaultPosition,
00270                const wxSize& size = wxDefaultSize,
00271                long style = wxTR_DEFAULT_STYLE,
00272                const wxValidator &validator = wxDefaultValidator,
00273                const wxString& name = _T("wxtreelistmainwindow"))
00274     {
00275         Init();
00276         Create (parent, id, pos, size, style, validator, name);
00277     }
00278 
00279     virtual ~wxTreeListMainWindow();
00280 
00281     bool Create(wxTreeListCtrl *parent, wxWindowID id = -1,
00282                 const wxPoint& pos = wxDefaultPosition,
00283                 const wxSize& size = wxDefaultSize,
00284                 long style = wxTR_DEFAULT_STYLE,
00285                 const wxValidator &validator = wxDefaultValidator,
00286                 const wxString& name = _T("wxtreelistctrl"));
00287 
00288     // accessors
00289     // ---------
00290 
00291     // return true if this is a virtual list control
00292     bool IsVirtual() const { return HasFlag(wxTR_VIRTUAL); }
00293 
00294     // get the total number of items in the control
00295     size_t GetCount() const;
00296 
00297     // indent is the number of pixels the children are indented relative to
00298     // the parents position. SetIndent() also redraws the control
00299     // immediately.
00300     unsigned int GetIndent() const { return m_indent; }
00301     void SetIndent(unsigned int indent);
00302 
00303     // see wxTreeListCtrl for the meaning
00304     unsigned int GetLineSpacing() const { return m_linespacing; }
00305     void SetLineSpacing(unsigned int spacing);
00306 
00307     // image list: these functions allow to associate an image list with
00308     // the control and retrieve it. Note that when assigned with
00309     // SetImageList, the control does _not_ delete
00310     // the associated image list when it's deleted in order to allow image
00311     // lists to be shared between different controls. If you use
00312     // AssignImageList, the control _does_ delete the image list.
00313 
00314     // The normal image list is for the icons which correspond to the
00315     // normal tree item state (whether it is selected or not).
00316     // Additionally, the application might choose to show a state icon
00317     // which corresponds to an app-defined item state (for example,
00318     // checked/unchecked) which are taken from the state image list.
00319     wxImageList *GetImageList() const { return m_imageListNormal; }
00320     wxImageList *GetStateImageList() const { return m_imageListState; }
00321     wxImageList *GetButtonsImageList() const { return m_imageListButtons; }
00322 
00323     void SetImageList(wxImageList *imageList);
00324     void SetStateImageList(wxImageList *imageList);
00325     void SetButtonsImageList(wxImageList *imageList);
00326     void AssignImageList(wxImageList *imageList);
00327     void AssignStateImageList(wxImageList *imageList);
00328     void AssignButtonsImageList(wxImageList *imageList);
00329 
00330     void SetToolTip(const wxString& tip);
00331     void SetToolTip(wxToolTip *tip);
00332     void SetItemToolTip(const wxTreeItemId& item, const wxString &tip);
00333 
00334     // Functions to work with tree ctrl items.
00335 
00336 
00337 
00338     // accessors (most props have a default at row/item level *and* a default at cell level)
00339     // ---------
00340 
00341     wxString GetItemText (const wxTreeItemId& item, int column) const;
00342     wxString GetItemText (wxTreeItemData* item, int column) const;
00343 
00344     // ItemImage is special: main col has multiple images
00345     int GetItemImage (const wxTreeItemId& item,             wxTreeItemIcon which = wxTreeItemIcon_Normal) const  { return GetItemImage (item, GetMainColumn(), which); }
00346     int GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const;
00347 
00348     // ItemData is special, there is a separate default at row/item level
00349     wxTreeItemData *GetItemData(const wxTreeItemId& item) const;
00350     wxTreeItemData *GetItemData(const wxTreeItemId& item, int column) const;
00351 
00352     bool GetItemBold(const wxTreeItemId& item)             const;
00353     bool GetItemBold(const wxTreeItemId& item, int column) const;
00354 
00355     wxColour GetItemTextColour(const wxTreeItemId& item)             const;
00356     wxColour GetItemTextColour(const wxTreeItemId& item, int column) const;
00357 
00358     wxColour GetItemBackgroundColour(const wxTreeItemId& item)             const;
00359     wxColour GetItemBackgroundColour(const wxTreeItemId& item, int column) const;
00360 
00361     wxFont GetItemFont(const wxTreeItemId& item) const;
00362     wxFont GetItemFont(const wxTreeItemId& item, int column) const;
00363 
00364 
00365 
00366     // modifiers (most properties have a default at row/item level *and* a default at cell level)
00367     // ---------
00368 
00369     // force appearance of [+] button near the item. This is useful to
00370     // allow the user to expand the items which don't have any children now
00371     // - but instead add them only when needed, thus minimizing memory
00372     // usage and loading time.
00373     void SetItemHasChildren(const wxTreeItemId& item, bool has = true);
00374 
00375     // set item's label
00376     void SetItemText (const wxTreeItemId& item, int column, const wxString& text);
00377 
00378     // get one of the images associated with the item (normal by default)
00379     void SetItemImage (const wxTreeItemId& item,             int image, wxTreeItemIcon which = wxTreeItemIcon_Normal) { SetItemImage (item, GetMainColumn(), image, which); }
00380     void SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which = wxTreeItemIcon_Normal);
00381 
00382     // associate some data with the item
00383     void SetItemData(const wxTreeItemId& item,             wxTreeItemData *data);
00384     void SetItemData(const wxTreeItemId& item, int column, wxTreeItemData *data);
00385 
00386     // the item will be shown in bold
00387     void SetItemBold(const wxTreeItemId& item,             bool bold = true);
00388     void SetItemBold(const wxTreeItemId& item, int column, bool bold = true);
00389 
00390     // set the item's text colour
00391     void SetItemTextColour(const wxTreeItemId& item,             const wxColour& colour);
00392     void SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour);
00393 
00394     // set the item's background colour
00395     void SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour);
00396     void SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour);
00397 
00398     // set the item's font (should be of the same height for all items)
00399     void SetItemFont(const wxTreeItemId& item,             const wxFont& font);
00400     void SetItemFont(const wxTreeItemId& item, int column, const wxFont& font);
00401 
00402 
00403 
00404     // item status inquiries
00405     // ---------------------
00406 
00407     // is the item visible (it might be outside the view or not expanded)?
00408     bool IsVisible(const wxTreeItemId& item, bool fullRow, bool within = true) const;
00409     // does the item has any children?
00410     bool HasChildren(const wxTreeItemId& item) const;
00411     // is the item expanded (only makes sense if HasChildren())?
00412     bool IsExpanded(const wxTreeItemId& item) const;
00413     // is this item currently selected (the same as has focus)?
00414     bool IsSelected(const wxTreeItemId& item) const;
00415     // is item text in bold font?
00416     bool IsBold(const wxTreeItemId& item)             const;
00417     bool IsBold(const wxTreeItemId& item, int column) const;
00418 
00419 
00420 
00421     // set the window font
00422     virtual bool SetFont( const wxFont &font );
00423 
00424     // set the styles.  No need to specify a GetWindowStyle here since
00425     // the base wxWindow member function will do it for us
00426     void SetWindowStyle(const long styles);
00427 
00428     // number of children
00429     // ------------------
00430 
00431     // if 'recursively' is false, only immediate children count, otherwise
00432     // the returned number is the number of all items in this branch
00433     size_t GetChildrenCount(const wxTreeItemId& item, bool recursively = true);
00434 
00435     // navigation
00436     // ----------
00437 
00438     // wxTreeItemId.IsOk() will return false if there is no such item
00439 
00440     // get the root tree item
00441     wxTreeItemId GetRootItem() const { return m_rootItem; }  // implict cast from wxTreeListItem *
00442 
00443     // get the item currently selected, only if a single item is selected
00444     wxTreeItemId GetSelection() const { return m_selectItem; }
00445 
00446     // get all the items currently selected, return count of items
00447     size_t GetSelections(wxArrayTreeItemIds&) const;
00448 
00449     // get the parent of this item (may return NULL if root)
00450     wxTreeItemId GetItemParent(const wxTreeItemId& item) const;
00451 
00452     // for this enumeration function you must pass in a "cookie" parameter
00453     // which is opaque for the application but is necessary for the library
00454     // to make these functions reentrant (i.e. allow more than one
00455     // enumeration on one and the same object simultaneously). Of course,
00456     // the "cookie" passed to GetFirstChild() and GetNextChild() should be
00457     // the same!
00458 
00459     // get child of this item
00460 #if !wxCHECK_VERSION(2, 5, 0)
00461     wxTreeItemId GetFirstChild(const wxTreeItemId& item, long& cookie) const;
00462     wxTreeItemId GetNextChild(const wxTreeItemId& item, long& cookie) const;
00463     wxTreeItemId GetPrevChild(const wxTreeItemId& item, long& cookie) const;
00464     wxTreeItemId GetLastChild(const wxTreeItemId& item, long& cookie) const;
00465 #else
00466     wxTreeItemId GetFirstChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
00467     wxTreeItemId GetNextChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
00468     wxTreeItemId GetPrevChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
00469     wxTreeItemId GetLastChild(const wxTreeItemId& item, wxTreeItemIdValue& cookie) const;
00470 #endif
00471 
00472     // get sibling of this item
00473     wxTreeItemId GetNextSibling(const wxTreeItemId& item) const;
00474     wxTreeItemId GetPrevSibling(const wxTreeItemId& item) const;
00475 
00476     // get item in the full tree (currently only for internal use)
00477     wxTreeItemId GetNext(const wxTreeItemId& item, bool fulltree = true) const;
00478     wxTreeItemId GetPrev(const wxTreeItemId& item, bool fulltree = true) const;
00479 
00480     // get expanded item, see IsExpanded()
00481     wxTreeItemId GetFirstExpandedItem() const;
00482     wxTreeItemId GetNextExpanded(const wxTreeItemId& item) const;
00483     wxTreeItemId GetPrevExpanded(const wxTreeItemId& item) const;
00484 
00485     // get visible item, see IsVisible()
00486     wxTreeItemId GetFirstVisible(                          bool fullRow, bool within) const;
00487     wxTreeItemId GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
00488     wxTreeItemId GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const;
00489     wxTreeItemId GetLastVisible (                          bool fullRow, bool within) const;
00490 
00491     // operations
00492     // ----------
00493 
00494     // add the root node to the tree
00495     wxTreeItemId AddRoot (const wxString& text,
00496                           int image = -1, int selectedImage = -1,
00497                           wxTreeItemData *data = NULL);
00498 
00499     // insert a new item in as the first child of the parent
00500     wxTreeItemId PrependItem(const wxTreeItemId& parent,
00501                              const wxString& text,
00502                              int image = -1, int selectedImage = -1,
00503                              wxTreeItemData *data = NULL);
00504 
00505     // insert a new item after a given one
00506     wxTreeItemId InsertItem(const wxTreeItemId& parent,
00507                             const wxTreeItemId& idPrevious,
00508                             const wxString& text,
00509                             int image = -1, int selectedImage = -1,
00510                             wxTreeItemData *data = NULL);
00511 
00512     // insert a new item before the one with the given index
00513     wxTreeItemId InsertItem(const wxTreeItemId& parent,
00514                             size_t index,
00515                             const wxString& text,
00516                             int image = -1, int selectedImage = -1,
00517                             wxTreeItemData *data = NULL);
00518 
00519     // insert a new item in as the last child of the parent
00520     wxTreeItemId AppendItem(const wxTreeItemId& parent,
00521                             const wxString& text,
00522                             int image = -1, int selectedImage = -1,
00523                             wxTreeItemData *data = NULL);
00524 
00525     // delete this item and associated data if any
00526     void Delete(const wxTreeItemId& item);
00527     // delete all children (but don't delete the item itself)
00528     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
00529     void DeleteChildren(const wxTreeItemId& item);
00530     // delete the root and all its children from the tree
00531     // NB: this won't send wxEVT_COMMAND_TREE_ITEM_DELETED events
00532     void DeleteRoot();
00533 
00534     void SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item);
00535 
00536     // expand this item
00537     void Expand(const wxTreeItemId& item);
00538     // expand this item and all subitems recursively
00539     void ExpandAll(const wxTreeItemId& item);
00540     // collapse the item without removing its children
00541     void Collapse(const wxTreeItemId& item);
00542     // collapse the item and remove all children
00543     void CollapseAndReset(const wxTreeItemId& item);
00544     // toggles the current state
00545     void Toggle(const wxTreeItemId& item);
00546 
00547     // set cursor item (indicated by black rectangle)
00548     void SetCurrentItem(const wxTreeItemId& item);
00549 
00550     // remove the selection from currently selected item (if any)
00551     void Unselect();
00552     void UnselectAll();
00553     // select this item
00554     bool SelectItem(const wxTreeItemId& item, const wxTreeItemId& prev = (wxTreeItemId*)NULL,
00555                     bool unselect_others = true);
00556     void SelectAll();
00557     // make sure this item is visible (expanding the parent item and/or
00558     // scrolling to this item if necessary)
00559     void EnsureVisible(const wxTreeItemId& item);
00560     // scroll to this item (but don't expand its parent)
00561     void ScrollTo(const wxTreeItemId& item);
00562     void AdjustMyScrollbars();
00563 
00564     // The first function is more portable (because easier to implement
00565     // on other platforms), but the second one returns some extra info.
00566     wxTreeItemId HitTest (const wxPoint& point)
00567         { int flags; int column; return HitTest (point, flags, column); }
00568     wxTreeItemId HitTest (const wxPoint& point, int& flags)
00569         { int column; return HitTest (point, flags, column); }
00570     wxTreeItemId HitTest (const wxPoint& point, int& flags, int& column);
00571 
00572 
00573     // get the bounding rectangle of the item (or of its label only)
00574     bool GetBoundingRect(const wxTreeItemId& item,
00575                          wxRect& rect,
00576                          bool textOnly = false) const;
00577 
00578     // Start editing the item label: this (temporarily) replaces the item
00579     // with a one line edit control. The item will be selected if it hadn't
00580     // been before.
00581     void EditLabel (const wxTreeItemId& item, int column);
00582     void EndEdit(bool isCancelled);
00583 
00584     // sorting
00585     // this function is called to compare 2 items and should return -1, 0
00586     // or +1 if the first item is less than, equal to or greater than the
00587     // second one. The base class version performs alphabetic comparaison
00588     // of item labels (GetText)
00589     virtual int OnCompareItems(const wxTreeItemId& item1,
00590                                const wxTreeItemId& item2);
00591     // sort the children of this item using OnCompareItems
00592     //
00593     // NB: this function is not reentrant and not MT-safe (TODO)!
00594     void SortChildren(const wxTreeItemId& item, int column, bool reverseOrder);
00595 
00596     // searching
00597     bool MatchItemText (const wxString &itemText, const wxString &pattern, int mode);
00598     wxTreeItemId FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode = 0);
00599 
00600     // implementation only from now on
00601 
00602     // overridden base class virtuals
00603     virtual bool SetBackgroundColour(const wxColour& colour);
00604     virtual bool SetForegroundColour(const wxColour& colour);
00605 
00606     // drop over item
00607     void SetDragItem (const wxTreeItemId& item = (wxTreeItemId*)NULL);
00608 
00609     // callbacks
00610     void OnPaint( wxPaintEvent &event );
00611     void OnEraseBackground(wxEraseEvent& WXUNUSED(event)) { ;; } // to reduce flicker
00612     void OnSetFocus( wxFocusEvent &event );
00613     void OnKillFocus( wxFocusEvent &event );
00614     void OnChar( wxKeyEvent &event );
00615     void OnMouse( wxMouseEvent &event );
00616     void OnIdle( wxIdleEvent &event );
00617     void OnScroll(wxScrollWinEvent& event);
00618     void OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED(event)) { ;; }
00619 
00620     // implementation helpers
00621     int GetColumnCount() const
00622     { return m_owner->GetHeaderWindow()->GetColumnCount(); }
00623 
00624     void SetMainColumn (int column)
00625     { if ((column >= 0) && (column < GetColumnCount())) m_main_column = column; }
00626 
00627     int GetMainColumn() const { return m_main_column; }
00628     int GetCurrentColumn() const { return m_curColumn >= 0 ? m_curColumn : m_main_column; }
00629 
00630     int GetBestColumnWidth (int column, wxTreeItemId parent = wxTreeItemId());
00631     int GetItemWidth (int column, wxTreeListItem *item);
00632 
00633     void SetFocus();
00634 
00635 protected:
00636     wxTreeListCtrl* m_owner;
00637 
00638     wxFont               m_normalFont;
00639     wxFont               m_boldFont;
00640 
00641     wxTreeListItem       *m_rootItem; // root item
00642     wxTreeListItem       *m_curItem; // current item, either selected or marked
00643     wxTreeListItem       *m_shiftItem; // item, where the shift key was pressed
00644     wxTreeListItem       *m_selectItem; // current selected item, not with wxTR_MULTIPLE
00645 
00646     int                  m_main_column;
00647     int                  m_curColumn;
00648     int                  m_sortColumn;
00649     bool                 m_ReverseSortOrder;
00650 
00651     int                  m_btnWidth, m_btnWidth2;
00652     int                  m_btnHeight, m_btnHeight2;
00653     int                  m_imgWidth, m_imgWidth2;
00654     int                  m_imgHeight, m_imgHeight2;
00655     unsigned short       m_indent;
00656     int                  m_lineHeight;
00657     unsigned short       m_linespacing;
00658     wxPen                m_dottedPen;
00659     wxBrush             *m_hilightBrush,
00660                         *m_hilightUnfocusedBrush;
00661     bool                 m_hasFocus;
00662 public:
00663     bool                 m_dirty;
00664 protected:
00665     bool                 m_ownsImageListNormal,
00666                          m_ownsImageListState,
00667                          m_ownsImageListButtons;
00668     bool                 m_lastOnSame;  // last click on the same item as prev
00669     bool                 m_left_down_selection;
00670 
00671     wxImageList         *m_imageListNormal,
00672                         *m_imageListState,
00673                         *m_imageListButtons;
00674 
00675     bool                 m_isDragStarted;  // set at the very beginning of dragging
00676     bool                 m_isDragging; // set once a drag begin event was fired
00677     wxPoint              m_dragStartPos;  // set whenever m_isDragStarted is set to true
00678     wxTreeListItem      *m_dragItem;
00679     int                  m_dragCol;
00680 
00681     wxTreeListItem       *m_editItem; // item, which is currently edited
00682     wxTimer             *m_editTimer;
00683     bool                 m_editAccept;  // currently unused, OnRenameAccept() argument makes it redundant
00684     wxString             m_editRes;
00685     int                  m_editCol;
00686     wxEditTextCtrl      *m_editControl;
00687 
00688     // char navigation
00689     wxTimer             *m_findTimer;
00690     wxString             m_findStr;
00691 
00692     bool                 m_isItemToolTip;  // true if individual item tooltips were set (disable global tooltip)
00693     wxString             m_toolTip;  // global tooltip
00694     wxTreeListItem      *m_toolTipItem;  // item whose tip is currently shown (NULL==global, -1==not displayed)
00695 
00696     // the common part of all ctors
00697     void Init();
00698 
00699     // misc helpers
00700     wxTreeItemId DoInsertItem(const wxTreeItemId& parent,
00701                               size_t previous,
00702                               const wxString& text,
00703                               int image, int selectedImage,
00704                               wxTreeItemData *data);
00705     void DoDeleteItem (wxTreeListItem *item);
00706     void SetCurrentItem(wxTreeListItem *item);
00707     bool HasButtons(void) const
00708         { return (m_imageListButtons) || HasFlag (wxTR_TWIST_BUTTONS|wxTR_HAS_BUTTONS); }
00709 
00710     void CalculateLineHeight();
00711     int  GetLineHeight(wxTreeListItem *item) const;
00712     void PaintLevel( wxTreeListItem *item, wxDC& dc, int level, int &y,
00713                      int x_maincol);
00714     void PaintItem( wxTreeListItem *item, wxDC& dc);
00715 
00716     void CalculateLevel( wxTreeListItem *item, wxDC &dc, int level, int &y,
00717                          int x_maincol);
00718     void CalculatePositions();
00719     void CalculateSize( wxTreeListItem *item, wxDC &dc );
00720 
00721     void RefreshSubtree (wxTreeListItem *item);
00722     void RefreshLine (wxTreeListItem *item);
00723     // redraw all selected items
00724     void RefreshSelected();
00725     // RefreshSelected() recursive helper
00726     void RefreshSelectedUnder (wxTreeListItem *item);
00727 
00728     void OnRenameTimer();
00729     void OnRenameAccept(bool isCancelled);
00730 
00731     void FillArray(wxTreeListItem*, wxArrayTreeItemIds&) const;
00732     bool TagAllChildrenUntilLast (wxTreeListItem *crt_item, wxTreeListItem *last_item);
00733     bool TagNextChildren (wxTreeListItem *crt_item, wxTreeListItem *last_item);
00734     void UnselectAllChildren (wxTreeListItem *item );
00735     bool SendEvent(wxEventType event_type, wxTreeListItem *item = NULL, wxTreeEvent *event = NULL);  // returns true if processed
00736 
00737 private:
00738     DECLARE_EVENT_TABLE()
00739     DECLARE_DYNAMIC_CLASS(wxTreeListMainWindow)
00740 };
00741 
00742 
00743 //-----------------------------------------------------------------------------
00744 
00745 // timer used for enabling in-place edit
00746 class  wxTreeListRenameTimer: public wxTimer
00747 {
00748 public:
00749     wxTreeListRenameTimer( wxTreeListMainWindow *owner );
00750 
00751     void Notify();
00752 
00753 private:
00754     wxTreeListMainWindow   *m_owner;
00755 };
00756 
00757 
00758 //-----------------------------------------------------------------------------
00759 
00760 // control used for in-place edit
00761 class  wxEditTextCtrl: public wxTextCtrl
00762 {
00763 public:
00764     wxEditTextCtrl (wxWindow *parent,
00765                     const wxWindowID id,
00766                     bool *accept,
00767                     wxString *res,
00768                     wxTreeListMainWindow *owner,
00769                     const wxString &value = wxEmptyString,
00770                     const wxPoint &pos = wxDefaultPosition,
00771                     const wxSize &size = wxDefaultSize,
00772                     long style = 0,
00773                     const wxValidator& validator = wxDefaultValidator,
00774                     const wxString &name = wxTextCtrlNameStr );
00775     ~wxEditTextCtrl();
00776 
00777     virtual bool Destroy();  // wxWindow override
00778     void EndEdit(bool isCancelled);
00779     void SetOwner(wxTreeListMainWindow *owner) { m_owner = owner; }
00780 
00781     void OnChar( wxKeyEvent &event );
00782     void OnKeyUp( wxKeyEvent &event );
00783     void OnKillFocus( wxFocusEvent &event );
00784 
00785 
00786 private:
00787     wxTreeListMainWindow  *m_owner;
00788     bool               *m_accept;
00789     wxString           *m_res;
00790     wxString            m_startValue;
00791     bool                m_finished;  // true==deleting, don't process events anymore
00792 
00793     DECLARE_EVENT_TABLE()
00794 };
00795 
00796 
00797 //-----------------------------------------------------------------------------
00798 
00799 // list of per-column attributes for an item (wxTreeListItem)
00800 // since there can be very many of these, we save size by chosing
00801 // the smallest representation for the elements and by ordering
00802 // the members to avoid padding.
00803 class  wxTreeListItemCellAttr
00804 {
00805 public:
00806     wxTreeListItemCellAttr() {
00807         m_attr = NULL;
00808         m_data = NULL;
00809         m_isBold = 0;
00810         m_isBoldSet = 0;
00811         m_ownsAttr = 0;
00812         m_image = NO_IMAGE;
00813     };
00814     ~wxTreeListItemCellAttr() {
00815         if (m_ownsAttr) delete m_attr;
00816     }
00817 
00818     // generic attribute from wxWidgets lib
00819     wxTreeItemAttr      *m_attr;
00820 
00821     // other attributes
00822     wxTreeItemData      *m_data;        // user-provided data
00823     short                m_image;       // images for the various columns (!= main)
00824     int                  m_isBold :1;   // render the label in bold font
00825     int                  m_isBoldSet :1;   // was 'm_isBold' set ?
00826     int                  m_ownsAttr :1; // delete attribute when done
00827 };
00828 
00829 
00830 //-----------------------------------------------------------------------------
00831 
00832 // a tree item (NOTE: this class is storage only, does not generate events)
00833 class  wxTreeListItem
00834 {
00835 public:
00836     // ctors & dtor
00837     // ------------
00838     wxTreeListItem() { m_toolTip = NULL; }
00839     wxTreeListItem( wxTreeListMainWindow *owner,
00840                     wxTreeListItem *parent,
00841                     const wxArrayString& text,
00842                     int image,
00843                     int selImage,
00844                     wxTreeItemData *data );
00845 
00846     ~wxTreeListItem();
00847 
00848 
00849     // accessors (most properties have a default at row/item level)
00850     // ---------
00851     wxArrayTreeListItems& GetChildren() { return m_children; }
00852 
00853 //    const wxString GetText (          ) const { return GetText(m_owner->GetMainColumn());  }
00854     const wxString GetText (int column) const
00855     {
00856         if ( IsVirtual() )   return m_owner->GetItemText( m_props_row.m_data, column );
00857         if (column < (signed)m_text.GetCount()) return m_text[column];
00858         return wxEmptyString;
00859     };
00860 
00861     int GetImage (            wxTreeItemIcon which = wxTreeItemIcon_Normal) const { return m_images[which]; };
00862     int GetImage (int column, wxTreeItemIcon which = wxTreeItemIcon_Normal) const
00863     {
00864         // main column is special, more images available
00865         if(column == m_owner->GetMainColumn()) return m_images[which];
00866 
00867         // other columns ignore the 'which' parameter
00868         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00869         if (entry == m_props_cell.end()) return NO_IMAGE;
00870         return entry->second->m_image;
00871     };
00872 
00873     // data is special: it has a default value at row/item level
00874     wxTreeItemData *GetData()           const { return m_props_row.m_data; };
00875     wxTreeItemData *GetData(int column) const {
00876         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00877         if (entry == m_props_cell.end()) return NULL;
00878         return entry->second->m_data;
00879     };
00880 
00881     const wxString * GetToolTip() const  {  return m_toolTip;  };
00882 
00883     // returns the current image for the item (depending on its
00884     // selected/expanded/whatever state)
00885     int GetCurrentImage() const;
00886 
00887 
00888     // modifiers (most properties have a default at row/item level)
00889     // ---------
00890     void SetHasPlus(bool has = true) { m_hasPlus = has; };
00891 
00892     void SetText (int column, const wxString& text)
00893     {
00894         if (column < (int)m_text.GetCount()) {
00895             m_text[column] = text;
00896         } else if (column < m_owner->GetColumnCount()) {
00897             int howmany = m_owner->GetColumnCount();
00898             for (int i = (int)m_text.GetCount(); i < howmany; ++i) m_text.Add (wxEmptyString);
00899             m_text[column] = text;
00900         }
00901     };
00902     void SetImage (            int image, wxTreeItemIcon which) { m_images[which] = image; };
00903     void SetImage (int column, int image, wxTreeItemIcon which)
00904     {
00905         // main column is special, more images available
00906         if (column == m_owner->GetMainColumn()) m_images[which] = image;
00907         // other columns ignore the 'which' parameter
00908         else {
00909             wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00910             if (entry == m_props_cell.end()) {
00911                 m_props_cell[column] = new wxTreeListItemCellAttr();
00912                 m_props_cell[column]->m_image = image;
00913             } else {
00914                 entry->second->m_image = image;
00915             }
00916         }
00917     };
00918 
00919     // data is special: it has a default value at row/item level
00920     void SetData(            wxTreeItemData *data) { m_props_row.m_data = data; };
00921     void SetData(int column, wxTreeItemData *data)
00922     {
00923         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00924         if (entry == m_props_cell.end()) {
00925             m_props_cell[column] = new wxTreeListItemCellAttr();
00926             m_props_cell[column]->m_data = data;
00927         } else {
00928             entry->second->m_data = data;
00929         }
00930     }
00931 
00932     void SetBold(            bool bold) { m_props_row.m_isBold = bold; }
00933     void SetBold(int column, bool bold)
00934     {
00935         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00936         if (entry == m_props_cell.end()) {
00937             m_props_cell[column] = new wxTreeListItemCellAttr();
00938             m_props_cell[column]->m_isBold = bold;
00939             m_props_cell[column]->m_isBoldSet = 1;
00940         } else {
00941             entry->second->m_isBold = bold;
00942             entry->second->m_isBoldSet = 1;
00943         }
00944     }
00945 
00946 
00947     void SetToolTip(const wxString &tip) {
00948         if (m_toolTip)  { delete m_toolTip; m_toolTip = NULL; }
00949         if (tip.length() > 0) { m_toolTip = new wxString(tip); }
00950     };
00951 
00952 
00953     // status inquiries
00954     // ----------------
00955     bool HasChildren() const        { return !m_children.IsEmpty(); }
00956     bool IsSelected()  const        { return m_hasHilight != 0; }
00957     bool IsExpanded()  const        { return !m_isCollapsed; }
00958     bool HasPlus()     const        { return m_hasPlus || HasChildren(); }
00959     bool IsBold()      const        { return m_props_row.m_isBold != 0; }
00960     bool IsBold(int column) const
00961     {
00962         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
00963         if (entry == m_props_cell.end() || ! entry->second->m_isBoldSet) return IsBold();
00964         return (entry->second->m_isBold != 0);
00965     }
00966     bool IsVirtual()   const        { return m_owner->IsVirtual(); }
00967 
00968 
00969 
00970     int GetX() const { return m_x; }
00971     int GetY() const { return m_y; }
00972 
00973     void SetX (int x) { m_x = x; }
00974     void SetY (int y) { m_y = y; }
00975 
00976     int  GetHeight() const { return m_height; }
00977     int  GetWidth()  const { return m_width; }
00978 
00979     void SetHeight (int height) { m_height = height; }
00980     void SetWidth (int width) { m_width = width; }
00981 
00982     int GetTextX() const { return m_text_x; }
00983     void SetTextX (int text_x) { m_text_x = text_x; }
00984 
00985     wxTreeListItem *GetItemParent() const { return m_parent; }
00986     void SetItemParent(wxTreeListItem *parent) { m_parent = parent; }
00987 
00988     // get count of all children (and grand children if 'recursively')
00989     size_t GetChildrenCount(bool recursively = true) const;
00990 
00991     void GetSize( int &x, int &y, const wxTreeListMainWindow* );
00992 
00993     // return the item at given position (or NULL if no item), onButton is
00994     // true if the point belongs to the item's button, otherwise it lies
00995     // on the button's label
00996     wxTreeListItem *HitTest (const wxPoint& point,
00997                              const wxTreeListMainWindow *,
00998                              int &flags, int& column, int level);
00999 
01000 
01001     // operations
01002     // ----------
01003     // deletes all children
01004     void DeleteChildren();
01005 
01006     void Insert(wxTreeListItem *child, size_t index)
01007     { m_children.Insert(child, index); }
01008 
01009     void Expand() { m_isCollapsed = false; }
01010     void Collapse() { m_isCollapsed = true; }
01011 
01012     void SetHilight( bool set = true ) { m_hasHilight = set; }
01013 
01014 
01015     // attributes
01016     // ----------
01017 
01018     // get them - may be NULL (used to read attributes)
01019     // NOTE: fall back on default at row/item level is not defined for cell
01020     wxTreeItemAttr *GetAttributes(int column) const
01021     {
01022         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
01023         if (entry == m_props_cell.end()) return GetAttributes();
01024         return entry->second->m_attr;
01025     }
01026     wxTreeItemAttr *GetAttributes() const { return m_props_row.m_attr; }
01027 
01028     // get them ensuring that the pointer is not NULL (used to write attributes)
01029     wxTreeItemAttr& Attr(int column) {
01030         wxTreeListItemCellAttrHash::const_iterator entry = m_props_cell.find( column );
01031         if (entry == m_props_cell.end()) {
01032             m_props_cell[column] = new wxTreeListItemCellAttr();
01033             m_props_cell[column]->m_attr = new wxTreeItemAttr;
01034             m_props_cell[column]->m_ownsAttr = 1;
01035             return *(m_props_cell[column]->m_attr);
01036         } else {
01037             return *(entry->second->m_attr);
01038         }
01039     }
01040     wxTreeItemAttr& Attr()
01041     {
01042         if ( !m_props_row.m_attr )
01043         {
01044             m_props_row.m_attr = new wxTreeItemAttr;
01045             m_props_row.m_ownsAttr = 1;
01046         }
01047         return *m_props_row.m_attr;
01048     }
01049 /* ----- unused -----
01050     // set them
01051     void SetAttributes(wxTreeItemAttr *attr)
01052     {
01053         if ( m_props_row.m_ownsAttr ) delete m_props_row.m_attr;
01054         m_props_row.m_attr = attr;
01055         m_props_row.m_ownsAttr = 0;
01056     }
01057     // set them and delete when done
01058     void AssignAttributes(wxTreeItemAttr *attr)
01059     {
01060         SetAttributes(attr);
01061         m_props_row.m_ownsAttr = 1;
01062     }
01063 */
01064 
01065 private:
01066     wxTreeListMainWindow       *m_owner;        // control the item belongs to
01067 
01068     wxArrayTreeListItems        m_children;     // list of children
01069     wxTreeListItem             *m_parent;       // parent of this item
01070 
01071     // main column item positions
01072     wxCoord                     m_x;            // (virtual) offset from left (vertical line)
01073     wxCoord                     m_y;            // (virtual) offset from top
01074     wxCoord                     m_text_x;       // item offset from left
01075     short                       m_width;        // width of this item
01076     unsigned char               m_height;       // height of this item
01077 
01078     // for the normal, selected, expanded and expanded+selected states
01079     short                       m_images[wxTreeItemIcon_Max];
01080     // currently there is no tooltip at cell level
01081     wxString                   *m_toolTip;
01082 
01083     // use bitfields to save size
01084     int                         m_isCollapsed :1;
01085     int                         m_hasHilight  :1; // same as focused
01086     int                         m_hasPlus     :1; // used for item which doesn't have
01087                                                     // children but has a [+] button
01088 
01089     // here are all the properties which can be set per column
01090     wxArrayString               m_text;        // labels to be rendered for item
01091     wxTreeListItemCellAttr      m_props_row;   // default at row/item level for: data, attr
01092     wxTreeListItemCellAttrHash  m_props_cell;
01093 };
01094 
01095 
01096 // ===========================================================================
01097 // implementation
01098 // ===========================================================================
01099 
01100 // ---------------------------------------------------------------------------
01101 // wxTreeListRenameTimer (internal)
01102 // ---------------------------------------------------------------------------
01103 
01104 wxTreeListRenameTimer::wxTreeListRenameTimer( wxTreeListMainWindow *owner )
01105 {
01106     m_owner = owner;
01107 }
01108 
01109 void wxTreeListRenameTimer::Notify()
01110 {
01111     m_owner->OnRenameTimer();
01112 }
01113 
01114 //-----------------------------------------------------------------------------
01115 // wxEditTextCtrl (internal)
01116 //-----------------------------------------------------------------------------
01117 
01118 BEGIN_EVENT_TABLE (wxEditTextCtrl,wxTextCtrl)
01119     EVT_CHAR           (wxEditTextCtrl::OnChar)
01120     EVT_KEY_UP         (wxEditTextCtrl::OnKeyUp)
01121     EVT_KILL_FOCUS     (wxEditTextCtrl::OnKillFocus)
01122 END_EVENT_TABLE()
01123 
01124 wxEditTextCtrl::wxEditTextCtrl (wxWindow *parent,
01125                                 const wxWindowID id,
01126                                 bool *accept,
01127                                 wxString *res,
01128                                 wxTreeListMainWindow *owner,
01129                                 const wxString &value,
01130                                 const wxPoint &pos,
01131                                 const wxSize &size,
01132                                 long style,
01133                                 const wxValidator& validator,
01134                                 const wxString &name)
01135     : wxTextCtrl (parent, id, value, pos, size, style | wxSIMPLE_BORDER | wxTE_PROCESS_ENTER, validator, name)
01136 {
01137     m_res = res;
01138     m_accept = accept;
01139     m_owner = owner;
01140     (*m_accept) = false;
01141     (*m_res) = wxEmptyString;
01142     m_startValue = value;
01143     m_finished = false;
01144 }
01145 
01146 wxEditTextCtrl::~wxEditTextCtrl() {
01147     EndEdit(true); // cancelled
01148 }
01149 
01150 void wxEditTextCtrl::EndEdit(bool isCancelled) {
01151     if (m_finished) return;
01152     m_finished = true;
01153 
01154     if (m_owner) {
01155         (*m_accept) = ! isCancelled;
01156         (*m_res) = isCancelled ? m_startValue : GetValue();
01157         m_owner->OnRenameAccept(*m_res == m_startValue);
01158         m_owner->m_editControl = NULL;
01159         m_owner->m_editItem = NULL;
01160         m_owner->SetFocus(); // This doesn't work. TODO.
01161         m_owner = NULL;
01162     }
01163 
01164     Destroy();
01165 }
01166 
01167 bool wxEditTextCtrl::Destroy() {
01168     Hide();
01169 #if wxCHECK_VERSION(2,9,0)
01170     wxTheApp->ScheduleForDestruction(this);
01171 #else
01172     wxTheApp->GetTraits()->ScheduleForDestroy(this);
01173 #endif
01174     return true;
01175 }
01176 
01177 void wxEditTextCtrl::OnChar( wxKeyEvent &event )
01178 {
01179     if (m_finished)
01180     {
01181         event.Skip();
01182         return;
01183     }
01184     if (event.GetKeyCode() == WXK_RETURN)
01185     {
01186         EndEdit(false);  // not cancelled
01187         return;
01188     }
01189     if (event.GetKeyCode() == WXK_ESCAPE)
01190     {
01191         EndEdit(true);  // cancelled
01192         return;
01193     }
01194     event.Skip();
01195 }
01196 
01197 void wxEditTextCtrl::OnKeyUp( wxKeyEvent &event )
01198 {
01199     if (m_finished)
01200     {
01201         event.Skip();
01202         return;
01203     }
01204 
01205     // auto-grow the textctrl:
01206     wxSize parentSize = m_owner->GetSize();
01207     wxPoint myPos = GetPosition();
01208     wxSize mySize = GetSize();
01209     int sx, sy;
01210     GetTextExtent(GetValue() + _T("M"), &sx, &sy);
01211     if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
01212     if (mySize.x > sx) sx = mySize.x;
01213     SetSize(sx, -1);
01214 
01215     event.Skip();
01216 }
01217 
01218 void wxEditTextCtrl::OnKillFocus( wxFocusEvent &event )
01219 {
01220     if (m_finished)
01221     {
01222         event.Skip();
01223         return;
01224     }
01225 
01226     EndEdit(false);  // not cancelled
01227 }
01228 
01229 //-----------------------------------------------------------------------------
01230 //  wxTreeListHeaderWindow
01231 //-----------------------------------------------------------------------------
01232 
01233 IMPLEMENT_DYNAMIC_CLASS(wxTreeListHeaderWindow,wxWindow);
01234 
01235 BEGIN_EVENT_TABLE(wxTreeListHeaderWindow,wxWindow)
01236     EVT_PAINT         (wxTreeListHeaderWindow::OnPaint)
01237     EVT_ERASE_BACKGROUND(wxTreeListHeaderWindow::OnEraseBackground) // reduce flicker
01238     EVT_MOUSE_EVENTS  (wxTreeListHeaderWindow::OnMouse)
01239     EVT_SET_FOCUS     (wxTreeListHeaderWindow::OnSetFocus)
01240 END_EVENT_TABLE()
01241 
01242 
01243 void wxTreeListHeaderWindow::Init()
01244 {
01245     m_currentCursor = (wxCursor *) NULL;
01246     m_isDragging = false;
01247     m_dirty = false;
01248     m_total_col_width = 0;
01249 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
01250     m_hotTrackCol = -1;
01251 #endif
01252 
01253     // prevent any background repaint in order to reducing flicker
01254     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
01255 }
01256 
01257 wxTreeListHeaderWindow::wxTreeListHeaderWindow()
01258 {
01259     Init();
01260 
01261     m_owner = (wxTreeListMainWindow *) NULL;
01262     m_resizeCursor = (wxCursor *) NULL;
01263 }
01264 
01265 wxTreeListHeaderWindow::wxTreeListHeaderWindow( wxWindow *win,
01266                                                 wxWindowID id,
01267                                                 wxTreeListMainWindow *owner,
01268                                                 const wxPoint& pos,
01269                                                 const wxSize& size,
01270                                                 long style,
01271                                                 const wxString &name )
01272     : wxWindow( win, id, pos, size, style, name )
01273 {
01274     Init();
01275 
01276     m_owner = owner;
01277     m_resizeCursor = new wxCursor(wxCURSOR_SIZEWE);
01278 
01279 #if !wxCHECK_VERSION(2, 5, 0)
01280     SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNFACE));
01281 #else
01282     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNFACE));
01283 #endif
01284 }
01285 
01286 wxTreeListHeaderWindow::~wxTreeListHeaderWindow()
01287 {
01288     delete m_resizeCursor;
01289 }
01290 
01291 void wxTreeListHeaderWindow::DoDrawRect( wxDC *dc, int x, int y, int w, int h )
01292 {
01293 #if !wxCHECK_VERSION(2, 5, 0)
01294     wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
01295 #else
01296 #if wxCHECK_VERSION(3, 0, 0)
01297     wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxPENSTYLE_SOLID);
01298 #else
01299     wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW ), 1, wxSOLID);
01300 #endif
01301 #endif
01302 
01303     const int m_corner = 1;
01304 
01305     dc->SetBrush( *wxTRANSPARENT_BRUSH );
01306 #if defined( __WXMAC__  )
01307     dc->SetPen (pen);
01308 #else // !GTK, !Mac
01309     dc->SetPen( *wxBLACK_PEN );
01310 #endif
01311     dc->DrawLine( x+w-m_corner+1, y, x+w, y+h );  // right (outer)
01312     dc->DrawRectangle( x, y+h, w+1, 1 );          // bottom (outer)
01313 
01314 #if defined( __WXMAC__  )
01315     pen = wxPen( wxColour( 0x88 , 0x88 , 0x88 ), 1, wxSOLID );
01316 #endif
01317     dc->SetPen( pen );
01318     dc->DrawLine( x+w-m_corner, y, x+w-1, y+h );  // right (inner)
01319     dc->DrawRectangle( x+1, y+h-1, w-2, 1 );      // bottom (inner)
01320 
01321     dc->SetPen( *wxWHITE_PEN );
01322     dc->DrawRectangle( x, y, w-m_corner+1, 1 );   // top (outer)
01323     dc->DrawRectangle( x, y, 1, h );              // left (outer)
01324     dc->DrawLine( x, y+h-1, x+1, y+h-1 );
01325     dc->DrawLine( x+w-1, y, x+w-1, y+1 );
01326 }
01327 
01328 // shift the DC origin to match the position of the main window horz
01329 // scrollbar: this allows us to always use logical coords
01330 void wxTreeListHeaderWindow::AdjustDC(wxDC& dc)
01331 {
01332     int xpix;
01333     m_owner->GetScrollPixelsPerUnit( &xpix, NULL );
01334     int x;
01335     m_owner->GetViewStart( &x, NULL );
01336 
01337     // account for the horz scrollbar offset
01338     dc.SetDeviceOrigin( -x * xpix, 0 );
01339 }
01340 
01341 void wxTreeListHeaderWindow::OnPaint( wxPaintEvent &WXUNUSED(event) )
01342 {
01343     wxAutoBufferedPaintDC dc( this );
01344     AdjustDC( dc );
01345 
01346     int x = HEADER_OFFSET_X;
01347 
01348     // width and height of the entire header window
01349     int w, h;
01350     GetClientSize( &w, &h );
01351     m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
01352     dc.SetBackgroundMode(wxTRANSPARENT);
01353 
01354 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
01355     int numColumns = GetColumnCount();
01356     for ( int i = 0; i < numColumns && x < w; i++ )
01357     {
01358         if (!IsColumnShown (i)) continue; // do next column if not shown
01359 
01360         wxHeaderButtonParams params;
01361 
01362         // TODO: columnInfo should have label colours...
01363         params.m_labelColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
01364         params.m_labelFont = GetFont();
01365 
01366         wxTreeListColumnInfo& column = GetColumn(i);
01367         int wCol = column.GetWidth();
01368         int flags = 0;
01369         wxRect rect(x, 0, wCol, h);
01370         x += wCol;
01371 
01372         if ( i == m_hotTrackCol)
01373             flags |= wxCONTROL_CURRENT;
01374 
01375         params.m_labelText = column.GetText();
01376         params.m_labelAlignment = column.GetAlignment();
01377 
01378         int image = column.GetImage();
01379         wxImageList* imageList = m_owner->GetImageList();
01380         if ((image != -1) && imageList)
01381             params.m_labelBitmap = imageList->GetBitmap(image);
01382 
01383         wxRendererNative::Get().DrawHeaderButton(this, dc, rect, flags, wxHDR_SORT_ICON_NONE, &params);
01384     }
01385 
01386     if (x < w) {
01387         wxRect rect(x, 0, w-x, h);
01388         wxRendererNative::Get().DrawHeaderButton(this, dc, rect);
01389     }
01390 
01391 #else  // not 2.7.0.1+
01392 
01393     dc.SetFont( GetFont() );
01394 
01395     // do *not* use the listctrl colour for headers - one day we will have a
01396     // function to set it separately
01397     //dc.SetTextForeground( *wxBLACK );
01398 #if !wxCHECK_VERSION(2, 5, 0)
01399     dc.SetTextForeground (wxSystemSettings::GetSystemColour( wxSYS_COLOUR_WINDOWTEXT ));
01400 #else
01401     dc.SetTextForeground (wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT ));
01402 #endif
01403 
01404     int numColumns = GetColumnCount();
01405     for ( int i = 0; i < numColumns && x < w; i++ )
01406     {
01407         if (!IsColumnShown (i)) continue; // do next column if not shown
01408 
01409         wxTreeListColumnInfo& column = GetColumn(i);
01410         int wCol = column.GetWidth();
01411 
01412         // the width of the rect to draw: make it smaller to fit entirely
01413         // inside the column rect
01414         int cw = wCol - 2;
01415 
01416 #if !wxCHECK_VERSION(2, 7, 0)
01417         dc.SetPen( *wxWHITE_PEN );
01418         DoDrawRect( &dc, x, HEADER_OFFSET_Y, cw, h-2 );
01419 #else
01420         wxRect rect(x, HEADER_OFFSET_Y, cw, h-2);
01421         wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
01422 #endif
01423 
01424         // if we have an image, draw it on the right of the label
01425         int image = column.GetImage(); //item.m_image;
01426         int ix = -2, iy = 0;
01427         wxImageList* imageList = m_owner->GetImageList();
01428         if ((image != -1) && imageList) {
01429             imageList->GetSize (image, ix, iy);
01430         }
01431 
01432         // extra margins around the text label
01433         int text_width = 0;
01434         int text_x = x;
01435         int image_offset = cw - ix - 1;
01436 
01437         switch(column.GetAlignment()) {
01438         case wxALIGN_LEFT:
01439             text_x += EXTRA_WIDTH;
01440             cw -= ix + 2;
01441             break;
01442         case wxALIGN_RIGHT:
01443             dc.GetTextExtent (column.GetText(), &text_width, NULL);
01444             text_x += cw - text_width - EXTRA_WIDTH - MARGIN;
01445             image_offset = 0;
01446             break;
01447         case wxALIGN_CENTER:
01448             dc.GetTextExtent(column.GetText(), &text_width, NULL);
01449             text_x += (cw - text_width)/2 + ix + 2;
01450             image_offset = (cw - text_width - ix - 2)/2 - MARGIN;
01451             break;
01452         }
01453 
01454         // draw the image
01455         if ((image != -1) && imageList) {
01456             imageList->Draw (image, dc, x + image_offset/*cw - ix - 1*/,
01457                              HEADER_OFFSET_Y + (h - 4 - iy)/2,
01458                              wxIMAGELIST_DRAW_TRANSPARENT);
01459         }
01460 
01461         // draw the text clipping it so that it doesn't overwrite the column boundary
01462         wxDCClipper clipper(dc, x, HEADER_OFFSET_Y, cw, h - 4 );
01463         dc.DrawText (column.GetText(), text_x, HEADER_OFFSET_Y + EXTRA_HEIGHT );
01464 
01465         // next column
01466         x += wCol;
01467     }
01468 
01469     int more_w = m_owner->GetSize().x - x - HEADER_OFFSET_X;
01470     if (more_w > 0) {
01471 #if !wxCHECK_VERSION(2, 7, 0)
01472         DoDrawRect (&dc, x, HEADER_OFFSET_Y, more_w, h-2 );
01473 #else
01474         wxRect rect (x, HEADER_OFFSET_Y, more_w, h-2);
01475         wxRendererNative::GetDefault().DrawHeaderButton (this, dc, rect);
01476 #endif
01477     }
01478 
01479 #endif // 2.7.0.1
01480 }
01481 
01482 void wxTreeListHeaderWindow::DrawCurrent()
01483 {
01484     int x1 = m_currentX;
01485     int y1 = 0;
01486     ClientToScreen (&x1, &y1);
01487 
01488     int x2 = m_currentX-1;
01489 #ifdef __WXMSW__
01490     ++x2; // but why ????
01491 #endif
01492     int y2 = 0;
01493     m_owner->GetClientSize( NULL, &y2 );
01494     m_owner->ClientToScreen( &x2, &y2 );
01495 
01496     wxScreenDC dc;
01497     dc.SetLogicalFunction (wxINVERT);
01498 #if wxCHECK_VERSION(3, 0, 0)
01499     dc.SetPen (wxPen (*wxBLACK, 2, wxPENSTYLE_SOLID));
01500 #else
01501     dc.SetPen (wxPen (*wxBLACK, 2, wxSOLID));
01502 #endif
01503     dc.SetBrush (*wxTRANSPARENT_BRUSH);
01504 
01505     AdjustDC(dc);
01506     dc.DrawLine (x1, y1, x2, y2);
01507     dc.SetLogicalFunction (wxCOPY);
01508     dc.SetPen (wxNullPen);
01509     dc.SetBrush (wxNullBrush);
01510 }
01511 
01512 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
01513 int wxTreeListHeaderWindow::XToCol(int x)
01514 {
01515     int colLeft = 0;
01516     int numColumns = GetColumnCount();
01517     for ( int col = 0; col < numColumns; col++ )
01518     {
01519         if (!IsColumnShown(col)) continue;
01520         wxTreeListColumnInfo& column = GetColumn(col);
01521 
01522         if ( x < (colLeft + column.GetWidth()) )
01523              return col;
01524 
01525         colLeft += column.GetWidth();
01526     }
01527     return -1;
01528 }
01529 
01530 void wxTreeListHeaderWindow::RefreshColLabel(int col)
01531 {
01532     if ( col > GetColumnCount() )
01533         return;
01534 
01535     int x = 0;
01536     int width = 0;
01537     int idx = 0;
01538     do {
01539         if (!IsColumnShown(idx)) continue;
01540         wxTreeListColumnInfo& column = GetColumn(idx);
01541         x += width;
01542         width = column.GetWidth();
01543     } while (++idx <= col);
01544 
01545     m_owner->CalcScrolledPosition(x, 0, &x, NULL);
01546     RefreshRect(wxRect(x, 0, width, GetSize().GetHeight()));
01547 }
01548 #endif
01549 
01550 void wxTreeListHeaderWindow::OnMouse (wxMouseEvent &event) {
01551 
01552     // we want to work with logical coords
01553     int x;
01554     m_owner->CalcUnscrolledPosition(event.GetX(), 0, &x, NULL);
01555 
01556 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
01557     const int col = XToCol(x);
01558     if(col>=0 && col<GetColumnCount())
01559     {
01560         SetToolTip(m_columns[col].GetTooltip());
01561     }
01562     else
01563     {
01564         SetToolTip(wxEmptyString);
01565     };
01566     if ( event.Moving() )
01567     {
01568         if ( col != m_hotTrackCol )
01569         {
01570             // Refresh the col header so it will be painted with hot tracking
01571             // (if supported by the native renderer.)
01572             RefreshColLabel(col);
01573 
01574             // Also refresh the old hot header
01575             if ( m_hotTrackCol >= 0 )
01576                 RefreshColLabel(m_hotTrackCol);
01577 
01578             m_hotTrackCol = col;
01579         }
01580     }
01581 
01582     if ( event.Leaving() && m_hotTrackCol >= 0 )
01583     {
01584         // Leaving the window so clear any hot tracking indicator that may be present
01585         RefreshColLabel(m_hotTrackCol);
01586         m_hotTrackCol = -1;
01587     }
01588 #endif
01589 
01590     if (m_isDragging) {
01591 
01592         SendListEvent (wxEVT_COMMAND_LIST_COL_DRAGGING, event.GetPosition());
01593 
01594         // we don't draw the line beyond our window, but we allow dragging it
01595         // there
01596         int w = 0;
01597         GetClientSize( &w, NULL );
01598         m_owner->CalcUnscrolledPosition(w, 0, &w, NULL);
01599         w -= 6;
01600 
01601         // erase the line if it was drawn
01602         if (m_currentX < w) DrawCurrent();
01603 
01604         if (event.ButtonUp()) {
01605             m_isDragging = false;
01606             if (HasCapture()) ReleaseMouse();
01607             m_dirty = true;
01608             SetColumnWidth (m_column, m_currentX - m_minX);
01609             Refresh();
01610             SendListEvent (wxEVT_COMMAND_LIST_COL_END_DRAG, event.GetPosition());
01611         }else{
01612             m_currentX = wxMax (m_minX + 7, x);
01613 
01614             // draw in the new location
01615             if (m_currentX < w) DrawCurrent();
01616         }
01617 
01618     }else{ // not dragging
01619 
01620         m_minX = 0;
01621         bool hit_border = false;
01622 
01623         // end of the current column
01624         int xpos = 0;
01625 
01626         // find the column where this event occured
01627         int countCol = GetColumnCount();
01628         for (int column = 0; column < countCol; column++) {
01629             if (!IsColumnShown (column)) continue; // do next if not shown
01630 
01631             xpos += GetColumnWidth (column);
01632             m_column = column;
01633             if (abs (x-xpos) < 3) {
01634                 // near the column border
01635                 hit_border = true;
01636                 break;
01637             }
01638 
01639             if (x < xpos) {
01640                 // inside the column
01641                 break;
01642             }
01643 
01644             m_minX = xpos;
01645         }
01646 
01647         if (event.LeftDown() || event.RightUp()) {
01648             m_owner->EndEdit(true);  // cancelled
01649 
01650             if (hit_border && event.LeftDown()) {
01651                 m_isDragging = true;
01652                 CaptureMouse();
01653                 m_currentX = x;
01654                 DrawCurrent();
01655                 SendListEvent (wxEVT_COMMAND_LIST_COL_BEGIN_DRAG, event.GetPosition());
01656             }else{ // click on a column
01657                 wxEventType evt = event.LeftDown()? wxEVT_COMMAND_LIST_COL_CLICK:
01658                                                     wxEVT_COMMAND_LIST_COL_RIGHT_CLICK;
01659                 SendListEvent (evt, event.GetPosition());
01660             }
01661         }else if (event.LeftDClick() && hit_border) {
01662             SetColumnWidth (m_column, m_owner->GetBestColumnWidth (m_column));
01663             Refresh();
01664 
01665         }else if (event.Moving()) {
01666             bool setCursor;
01667             if (hit_border) {
01668                 setCursor = m_currentCursor == wxSTANDARD_CURSOR;
01669                 m_currentCursor = m_resizeCursor;
01670             }else{
01671                 setCursor = m_currentCursor != wxSTANDARD_CURSOR;
01672                 m_currentCursor = wxSTANDARD_CURSOR;
01673             }
01674             if (setCursor) SetCursor (*m_currentCursor);
01675         }
01676 
01677     }
01678 }
01679 
01680 void wxTreeListHeaderWindow::OnSetFocus (wxFocusEvent &WXUNUSED(event)) {
01681     m_owner->SetFocus();
01682 }
01683 
01684 void wxTreeListHeaderWindow::SendListEvent (wxEventType type, wxPoint pos) {
01685     wxWindow *parent = GetParent();
01686     wxListEvent le (type, parent->GetId());
01687     le.SetEventObject (parent);
01688     le.m_pointDrag = pos;
01689 
01690     // the position should be relative to the parent window, not
01691     // this one for compatibility with MSW and common sense: the
01692     // user code doesn't know anything at all about this header
01693     // window, so why should it get positions relative to it?
01694     le.m_pointDrag.y -= GetSize().y;
01695     le.m_col = m_column;
01696     parent->GetEventHandler()->ProcessEvent (le);
01697 }
01698 
01699 void wxTreeListHeaderWindow::AddColumn (const wxTreeListColumnInfo& colInfo) {
01700     m_columns.Add (colInfo);
01701     m_total_col_width += colInfo.GetWidth();
01702     m_owner->AdjustMyScrollbars();
01703     m_owner->m_dirty = true;
01704 }
01705 
01706 void wxTreeListHeaderWindow::SetColumnWidth (int column, int width) {
01707     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
01708     m_total_col_width -= m_columns[column].GetWidth();
01709     m_columns[column].SetWidth(width);
01710     m_total_col_width += m_columns[column].GetWidth();
01711     m_owner->AdjustMyScrollbars();
01712     m_owner->m_dirty = true;
01713 }
01714 
01715 void wxTreeListHeaderWindow::InsertColumn (int before, const wxTreeListColumnInfo& colInfo) {
01716     wxCHECK_RET ((before >= 0) && (before < GetColumnCount()), _T("Invalid column"));
01717     m_columns.Insert (colInfo, before);
01718     m_total_col_width += colInfo.GetWidth();
01719     m_owner->AdjustMyScrollbars();
01720     m_owner->m_dirty = true;
01721 }
01722 
01723 void wxTreeListHeaderWindow::RemoveColumn (int column) {
01724     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
01725     m_total_col_width -= m_columns[column].GetWidth();
01726     m_columns.RemoveAt (column);
01727     m_owner->AdjustMyScrollbars();
01728     m_owner->m_dirty = true;
01729 }
01730 
01731 void wxTreeListHeaderWindow::SetColumn (int column, const wxTreeListColumnInfo& info) {
01732     wxCHECK_RET ((column >= 0) && (column < GetColumnCount()), _T("Invalid column"));
01733     int w = m_columns[column].GetWidth();
01734     m_columns[column] = info;
01735     if (w != info.GetWidth()) {
01736         m_total_col_width -= w;
01737         m_total_col_width += info.GetWidth();
01738         m_owner->AdjustMyScrollbars();
01739     }
01740     m_owner->m_dirty = true;
01741 }
01742 
01743 // ---------------------------------------------------------------------------
01744 // wxTreeListItem
01745 // ---------------------------------------------------------------------------
01746 
01747 wxTreeListItem::wxTreeListItem (wxTreeListMainWindow *owner,
01748                                 wxTreeListItem *parent,
01749                                 const wxArrayString& text,
01750                                 int image, int selImage,
01751                                 wxTreeItemData *data)
01752               : m_text (text) {
01753 
01754     m_images[wxTreeItemIcon_Normal] = image;
01755     m_images[wxTreeItemIcon_Selected] = selImage;
01756     m_images[wxTreeItemIcon_Expanded] = NO_IMAGE;
01757     m_images[wxTreeItemIcon_SelectedExpanded] = NO_IMAGE;
01758 
01759     m_props_row.m_data = data;
01760     m_toolTip = NULL;
01761     m_x = 0;
01762     m_y = 0;
01763     m_text_x = 0;
01764 
01765     m_isCollapsed = true;
01766     m_hasHilight = false;
01767     m_hasPlus = false;
01768 
01769     m_owner = owner;
01770     m_parent = parent;
01771 
01772     // We don't know the height here yet.
01773     m_width = 0;
01774     m_height = 0;
01775 }
01776 
01777 wxTreeListItem::~wxTreeListItem() {
01778     if (m_toolTip) delete m_toolTip;
01779 
01780     wxTreeListItemCellAttrHash::iterator entry = m_props_cell.begin();
01781     while (entry != m_props_cell.end()) {
01782         if (entry->second) delete entry->second;
01783         ++entry;
01784     }
01785 
01786     wxASSERT_MSG( m_children.IsEmpty(), _T("please call DeleteChildren() before destructor"));
01787 }
01788 
01789 void wxTreeListItem::DeleteChildren () {
01790     m_children.Empty();
01791 }
01792 
01793 size_t wxTreeListItem::GetChildrenCount (bool recursively) const {
01794     size_t count = m_children.Count();
01795     if (!recursively) return count;
01796 
01797     size_t total = count;
01798     for (size_t n = 0; n < count; ++n) {
01799         total += m_children[n]->GetChildrenCount();
01800     }
01801     return total;
01802 }
01803 
01804 void wxTreeListItem::GetSize (int &x, int &y, const wxTreeListMainWindow *theButton) {
01805     int bottomY = m_y + theButton->GetLineHeight (this);
01806     if (y < bottomY) y = bottomY;
01807     int width = m_x +  GetWidth();
01808     if ( x < width ) x = width;
01809 
01810     if (IsExpanded()) {
01811         size_t count = m_children.Count();
01812         for (size_t n = 0; n < count; ++n ) {
01813             m_children[n]->GetSize (x, y, theButton);
01814         }
01815     }
01816 }
01817 
01818 wxTreeListItem *wxTreeListItem::HitTest (const wxPoint& point,
01819                                          const wxTreeListMainWindow *theCtrl,
01820                                          int &flags, int& column, int level) {
01821 
01822     // reset any previous hit infos
01823     flags = 0;
01824     column = -1;
01825 
01826     // for a hidden root node, don't evaluate it, but do evaluate children
01827     if (!theCtrl->HasFlag(wxTR_HIDE_ROOT) || (level > 0)) {
01828 
01829         wxTreeListHeaderWindow* header_win = theCtrl->m_owner->GetHeaderWindow();
01830 
01831         // check for right of all columns (outside)
01832         if (point.x > header_win->GetWidth()) return (wxTreeListItem*) NULL;
01833         // else find column
01834         for (int x = 0, j = 0; j < theCtrl->GetColumnCount(); ++j) {
01835             if (!header_win->IsColumnShown(j)) continue;
01836             int w = header_win->GetColumnWidth (j);
01837             if (point.x >= x && point.x < x+w) {
01838                 column = j;
01839                 break;
01840             }
01841             x += w;
01842         }
01843 
01844         // evaluate if y-pos is okay
01845         int h = theCtrl->GetLineHeight (this);
01846         if ((point.y >= m_y) && (point.y <= m_y + h)) {
01847 
01848             // check for above/below middle
01849             int y_mid = m_y + h/2;
01850             if (point.y < y_mid) {
01851                 flags |= wxTREE_HITTEST_ONITEMUPPERPART;
01852             }else{
01853                 flags |= wxTREE_HITTEST_ONITEMLOWERPART;
01854             }
01855 
01856             // check for button hit
01857             if (HasPlus() && theCtrl->HasButtons()) {
01858                 int bntX = m_x - theCtrl->m_btnWidth2;
01859                 int bntY = y_mid - theCtrl->m_btnHeight2;
01860                 if ((point.x >= bntX) && (point.x <= (bntX + theCtrl->m_btnWidth)) &&
01861                     (point.y >= bntY) && (point.y <= (bntY + theCtrl->m_btnHeight))) {
01862                     flags |= wxTREE_HITTEST_ONITEMBUTTON;
01863                     return this;
01864                 }
01865             }
01866 
01867             // check for image hit
01868             if (theCtrl->m_imgWidth > 0) {
01869                 int imgX = m_text_x - theCtrl->m_imgWidth - MARGIN;
01870                 int imgY = y_mid - theCtrl->m_imgHeight2;
01871                 if ((point.x >= imgX) && (point.x <= (imgX + theCtrl->m_imgWidth)) &&
01872                     (point.y >= imgY) && (point.y <= (imgY + theCtrl->m_imgHeight))) {
01873                     flags |= wxTREE_HITTEST_ONITEMICON;
01874                     return this;
01875                 }
01876             }
01877 
01878             // check for label hit
01879             if ((point.x >= m_text_x) && (point.x <= (m_text_x + GetWidth()))) {
01880                 flags |= wxTREE_HITTEST_ONITEMLABEL;
01881                 return this;
01882             }
01883 
01884             // check for indent hit after button and image hit
01885             if (point.x < m_x) {
01886                 flags |= wxTREE_HITTEST_ONITEMINDENT;
01887                 return this;
01888             }
01889 
01890             // check for right of label
01891             int end = 0;
01892             for (int i = 0; i <= theCtrl->GetMainColumn(); ++i) end += header_win->GetColumnWidth (i);
01893             if ((point.x > (m_text_x + GetWidth())) && (point.x <= end)) {
01894                 flags |= wxTREE_HITTEST_ONITEMRIGHT;
01895                 return this;
01896             }
01897 
01898             // else check for each column except main
01899             if (column >= 0 && column != theCtrl->GetMainColumn()) {
01900                 flags |= wxTREE_HITTEST_ONITEMCOLUMN;
01901                 return this;
01902             }
01903 
01904             // no special flag or column found
01905             return this;
01906 
01907         }
01908 
01909         // if children not expanded, return no item
01910         if (!IsExpanded()) return (wxTreeListItem*) NULL;
01911     }
01912 
01913     // in any case evaluate children
01914     wxTreeListItem *child;
01915     size_t count = m_children.Count();
01916     for (size_t n = 0; n < count; n++) {
01917         child = m_children[n]->HitTest (point, theCtrl, flags, column, level+1);
01918         if (child) return child;
01919     }
01920 
01921     // not found
01922     return (wxTreeListItem*) NULL;
01923 }
01924 
01925 int wxTreeListItem::GetCurrentImage() const {
01926     int image = NO_IMAGE;
01927     if (IsExpanded()) {
01928         if (IsSelected()) {
01929             image = GetImage (wxTreeItemIcon_SelectedExpanded);
01930         }else{
01931             image = GetImage (wxTreeItemIcon_Expanded);
01932         }
01933     }else{ // not expanded
01934         if (IsSelected()) {
01935             image = GetImage (wxTreeItemIcon_Selected);
01936         }else{
01937             image = GetImage (wxTreeItemIcon_Normal);
01938         }
01939     }
01940 
01941     // maybe it doesn't have the specific image, try the default one instead
01942     if (image == NO_IMAGE) image = GetImage();
01943 
01944     return image;
01945 }
01946 
01947 // ---------------------------------------------------------------------------
01948 // wxTreeListMainWindow implementation
01949 // ---------------------------------------------------------------------------
01950 
01951 IMPLEMENT_DYNAMIC_CLASS(wxTreeListMainWindow, wxScrolledWindow)
01952 
01953 BEGIN_EVENT_TABLE(wxTreeListMainWindow, wxScrolledWindow)
01954     EVT_PAINT          (wxTreeListMainWindow::OnPaint)
01955     EVT_ERASE_BACKGROUND(wxTreeListMainWindow::OnEraseBackground) // to reduce flicker
01956     EVT_MOUSE_EVENTS   (wxTreeListMainWindow::OnMouse)
01957     EVT_CHAR           (wxTreeListMainWindow::OnChar)
01958     EVT_SET_FOCUS      (wxTreeListMainWindow::OnSetFocus)
01959     EVT_KILL_FOCUS     (wxTreeListMainWindow::OnKillFocus)
01960     EVT_IDLE           (wxTreeListMainWindow::OnIdle)
01961     EVT_SCROLLWIN      (wxTreeListMainWindow::OnScroll)
01962     EVT_MOUSE_CAPTURE_LOST(wxTreeListMainWindow::OnCaptureLost)
01963 END_EVENT_TABLE()
01964 
01965 
01966 // ---------------------------------------------------------------------------
01967 // construction/destruction
01968 // ---------------------------------------------------------------------------
01969 
01970 
01971 void wxTreeListMainWindow::Init() {
01972 
01973     m_rootItem = (wxTreeListItem*)NULL;
01974     m_curItem = (wxTreeListItem*)NULL;
01975     m_shiftItem = (wxTreeListItem*)NULL;
01976     m_editItem = (wxTreeListItem*)NULL;
01977     m_selectItem = (wxTreeListItem*)NULL;
01978 
01979     m_curColumn = -1; // no current column
01980 
01981     m_hasFocus = false;
01982     m_dirty = false;
01983 
01984     m_lineHeight = LINEHEIGHT;
01985     m_indent = MININDENT; // min. indent
01986     m_linespacing = 4;
01987 
01988 #if !wxCHECK_VERSION(2, 5, 0)
01989     m_hilightBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
01990     m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
01991 #else
01992 #if wxCHECK_VERSION(3, 0, 0)
01993     m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxBRUSHSTYLE_SOLID);
01994     m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxBRUSHSTYLE_SOLID);
01995 #else
01996     m_hilightBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHT), wxSOLID);
01997     m_hilightUnfocusedBrush = new wxBrush (wxSystemSettings::GetColour (wxSYS_COLOUR_BTNSHADOW), wxSOLID);
01998 #endif
01999 #endif
02000 
02001     m_imageListNormal = (wxImageList *) NULL;
02002     m_imageListButtons = (wxImageList *) NULL;
02003     m_imageListState = (wxImageList *) NULL;
02004     m_ownsImageListNormal = m_ownsImageListButtons =
02005     m_ownsImageListState = false;
02006 
02007     m_imgWidth = 0, m_imgWidth2 = 0;
02008     m_imgHeight = 0, m_imgHeight2 = 0;
02009     m_btnWidth = 0, m_btnWidth2 = 0;
02010     m_btnHeight = 0, m_btnHeight2 = 0;
02011 
02012     m_isDragStarted = m_isDragging = false;
02013     m_dragItem = NULL;
02014     m_dragCol = -1;
02015 
02016     m_editTimer = new wxTreeListRenameTimer (this);
02017     m_editControl = NULL;
02018 
02019     m_lastOnSame = false;
02020     m_left_down_selection = false;
02021 
02022     m_findTimer = new wxTimer (this, -1);
02023 
02024 #if defined( __WXMAC__ ) && defined(__WXMAC_CARBON__)
02025     m_normalFont.MacCreateThemeFont (kThemeViewsFont);
02026 #else
02027     m_normalFont = wxSystemSettings::GetFont (wxSYS_DEFAULT_GUI_FONT);
02028 #endif
02029 #if wxCHECK_VERSION(3, 0, 0)
02030     m_boldFont = wxFont( m_normalFont.GetPointSize(),
02031                          m_normalFont.GetFamily(),
02032                          m_normalFont.GetStyle(),
02033                          wxFONTWEIGHT_BOLD,
02034                          m_normalFont.GetUnderlined(),
02035                          m_normalFont.GetFaceName(),
02036                          m_normalFont.GetEncoding());
02037 #else
02038     m_boldFont = wxFont( m_normalFont.GetPointSize(),
02039                          m_normalFont.GetFamily(),
02040                          m_normalFont.GetStyle(),
02041                          wxBOLD,
02042                          m_normalFont.GetUnderlined(),
02043                          m_normalFont.GetFaceName(),
02044                          m_normalFont.GetEncoding());
02045 #endif
02046     m_toolTip.clear();
02047     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed
02048     m_isItemToolTip = false;  // so far no item-specific tooltip
02049 }
02050 
02051 bool wxTreeListMainWindow::Create (wxTreeListCtrl *parent,
02052                                    wxWindowID id,
02053                                    const wxPoint& pos,
02054                                    const wxSize& size,
02055                                    long style,
02056                                    const wxValidator &validator,
02057                                    const wxString& name) {
02058 
02059 #ifdef __WXMAC__
02060  #if !wxCHECK_VERSION(2,9,0)
02061     if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
02062     if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
02063     style &= ~wxTR_LINES_AT_ROOT;
02064     style |= wxTR_NO_LINES;
02065 
02066     int major,minor;
02067     wxGetOsVersion( &major, &minor );
02068     if (major < 10) style |= wxTR_ROW_LINES;
02069  #endif
02070 #endif
02071 
02072     wxScrolledWindow::Create (parent, id, pos, size, style|wxHSCROLL|wxVSCROLL, name);
02073 
02074 #if wxUSE_VALIDATORS
02075     SetValidator(validator);
02076 #endif
02077 
02078 #if !wxCHECK_VERSION(2, 5, 0)
02079     SetBackgroundColour (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_LISTBOX));
02080 #else
02081     SetBackgroundColour (wxSystemSettings::GetColour (wxSYS_COLOUR_LISTBOX));
02082 #endif
02083     // prevent any background repaint in order to reducing flicker
02084     SetBackgroundStyle(wxBG_STYLE_CUSTOM);
02085 
02086 #ifdef __WXMSW__
02087     {
02088         int i, j;
02089         wxBitmap bmp(8, 8);
02090         wxMemoryDC bdc;
02091         bdc.SelectObject(bmp);
02092         bdc.SetPen(*wxGREY_PEN);
02093         bdc.DrawRectangle(-1, -1, 10, 10);
02094         for (i = 0; i < 8; i++) {
02095             for (j = 0; j < 8; j++) {
02096                 if (!((i + j) & 1)) {
02097                     bdc.DrawPoint(i, j);
02098                 }
02099             }
02100         }
02101 
02102         m_dottedPen = wxPen(bmp, 1);
02103     }
02104 #else
02105 //?    m_dottedPen = wxPen( *wxGREY_PEN, 1, wxDOT );  // too slow under XFree86
02106     m_dottedPen = wxPen( _T("grey"), 0, 0 ); // Bitmap based pen is not supported by GTK!
02107 #endif
02108 
02109     m_owner = parent;
02110     m_main_column = 0;
02111 
02112     return true;
02113 }
02114 
02115 wxTreeListMainWindow::~wxTreeListMainWindow() {
02116     delete m_hilightBrush;
02117     delete m_hilightUnfocusedBrush;
02118 
02119     delete m_editTimer;
02120     delete m_findTimer;
02121     if (m_ownsImageListNormal) delete m_imageListNormal;
02122     if (m_ownsImageListState) delete m_imageListState;
02123     if (m_ownsImageListButtons) delete m_imageListButtons;
02124 
02125     if (m_editControl) {
02126         m_editControl->SetOwner(NULL);    // prevent control from calling us during delete
02127         delete m_editControl;
02128     }
02129 
02130     DeleteRoot();
02131 }
02132 
02133 
02134 //-----------------------------------------------------------------------------
02135 // accessors
02136 //-----------------------------------------------------------------------------
02137 
02138 size_t wxTreeListMainWindow::GetCount() const {
02139     return m_rootItem == NULL? 0: m_rootItem->GetChildrenCount();
02140 }
02141 
02142 void wxTreeListMainWindow::SetIndent (unsigned int indent) {
02143     m_indent = wxMax ((unsigned)MININDENT, indent);
02144     m_dirty = true;
02145 }
02146 
02147 void wxTreeListMainWindow::SetLineSpacing (unsigned int spacing) {
02148     m_linespacing = spacing;
02149     m_dirty = true;
02150     CalculateLineHeight();
02151 }
02152 
02153 size_t wxTreeListMainWindow::GetChildrenCount (const wxTreeItemId& item,
02154                                                bool recursively) {
02155     wxCHECK_MSG (item.IsOk(), 0u, _T("invalid tree item"));
02156     return ((wxTreeListItem*)item.m_pItem)->GetChildrenCount (recursively);
02157 }
02158 
02159 void wxTreeListMainWindow::SetWindowStyle (const long styles) {
02160     // change to selection mode, reset selection
02161     if ((styles ^ m_windowStyle) & wxTR_MULTIPLE) { UnselectAll(); }
02162     // right now, just sets the styles.  Eventually, we may
02163     // want to update the inherited styles, but right now
02164     // none of the parents has updatable styles
02165     m_windowStyle = styles;
02166     m_dirty = true;
02167 }
02168 
02169 void wxTreeListMainWindow::SetToolTip(const wxString& tip) {
02170     m_isItemToolTip = false;
02171     m_toolTip = tip;
02172     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
02173 }
02174 void wxTreeListMainWindow::SetToolTip(wxToolTip *tip) {
02175     m_isItemToolTip = false;
02176     m_toolTip = (tip == NULL) ? wxString() : tip->GetTip();
02177     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
02178 }
02179 
02180 void wxTreeListMainWindow::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
02181     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02182     m_isItemToolTip = true;
02183     ((wxTreeListItem*) item.m_pItem)->SetToolTip(tip);
02184     m_toolTipItem = (wxTreeListItem *)-1;  // no tooltip displayed (force refresh)
02185 }
02186 
02187 
02188 //-----------------------------------------------------------------------------
02189 // functions to work with tree items
02190 //-----------------------------------------------------------------------------
02191 
02192 int wxTreeListMainWindow::GetItemImage (const wxTreeItemId& item, int column, wxTreeItemIcon which) const {
02193     wxCHECK_MSG (item.IsOk(), -1, _T("invalid tree item"));
02194     return ((wxTreeListItem*) item.m_pItem)->GetImage (column, which);
02195 }
02196 
02197 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item) const {
02198     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
02199     return ((wxTreeListItem*) item.m_pItem)->GetData();
02200 }
02201 wxTreeItemData *wxTreeListMainWindow::GetItemData (const wxTreeItemId& item, int column) const {
02202     wxCHECK_MSG (item.IsOk(), NULL, _T("invalid tree item"));
02203     return ((wxTreeListItem*) item.m_pItem)->GetData(column);
02204 }
02205 
02206 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item) const {
02207     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
02208     return ((wxTreeListItem *)item.m_pItem)->IsBold();
02209 }
02210 bool wxTreeListMainWindow::GetItemBold (const wxTreeItemId& item, int column) const {
02211     wxCHECK_MSG(item.IsOk(), false, _T("invalid tree item"));
02212     return ((wxTreeListItem *)item.m_pItem)->IsBold(column);
02213 }
02214 
02215 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item) const {
02216     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
02217     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02218     wxTreeItemAttr *attr = pItem->GetAttributes();
02219     if (attr && attr->HasTextColour()) {
02220         return attr->GetTextColour();
02221     } else {
02222         return GetForegroundColour();
02223     }
02224 }
02225 wxColour wxTreeListMainWindow::GetItemTextColour (const wxTreeItemId& item, int column) const {
02226     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
02227     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02228     wxTreeItemAttr *attr = pItem->GetAttributes(column);
02229     if (attr && attr->HasTextColour()) {
02230         return attr->GetTextColour();
02231     } else {
02232         return GetItemTextColour(item);
02233     }
02234 }
02235 
02236 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item) const {
02237     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
02238     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02239     wxTreeItemAttr *attr = pItem->GetAttributes();
02240     if (attr && attr->HasBackgroundColour()) {
02241         return attr->GetBackgroundColour();
02242     } else {
02243         return GetBackgroundColour();
02244     }
02245 }
02246 wxColour wxTreeListMainWindow::GetItemBackgroundColour (const wxTreeItemId& item, int column) const {
02247     wxCHECK_MSG (item.IsOk(), wxNullColour, _T("invalid tree item"));
02248     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02249     wxTreeItemAttr *attr = pItem->GetAttributes(column);
02250     if (attr && attr->HasBackgroundColour()) {
02251         return attr->GetBackgroundColour();
02252     } else {
02253         return GetItemBackgroundColour(item);
02254     }
02255 }
02256 
02257 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item) const {
02258     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
02259     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02260     wxTreeItemAttr *attr = pItem->GetAttributes();
02261     if (attr && attr->HasFont()) {
02262         return attr->GetFont();
02263     }else if (pItem->IsBold()) {
02264         return m_boldFont;
02265     } else {
02266         return m_normalFont;
02267     }
02268 }
02269 wxFont wxTreeListMainWindow::GetItemFont (const wxTreeItemId& item, int column) const {
02270     wxCHECK_MSG (item.IsOk(), wxNullFont, _T("invalid tree item"));
02271     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02272     wxTreeItemAttr *attr_cell = pItem->GetAttributes(column);
02273     wxTreeItemAttr *attr_row = pItem->GetAttributes();
02274     if (attr_cell && attr_cell->HasFont()) {
02275         return attr_cell->GetFont();
02276     } else if (attr_row && attr_row->HasFont()) {
02277         return attr_row->GetFont();
02278     } else if (pItem->IsBold(column)) {
02279         return m_boldFont;
02280     } else {
02281         return m_normalFont;
02282     }
02283 }
02284 
02285 void wxTreeListMainWindow::SetItemHasChildren (const wxTreeItemId& item, bool has) {
02286     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02287     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02288     pItem->SetHasPlus (has);
02289     RefreshLine (pItem);
02290 }
02291 
02292 void wxTreeListMainWindow::SetItemImage (const wxTreeItemId& item, int column, int image, wxTreeItemIcon which) {
02293     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02294     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02295     pItem->SetImage (column, image, which);
02296     wxClientDC dc (this);
02297     CalculateSize (pItem, dc);
02298     RefreshLine (pItem);
02299 }
02300 
02301 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item,             wxTreeItemData *data) {
02302     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02303     ((wxTreeListItem*) item.m_pItem)->SetData(data);
02304 }
02305 void wxTreeListMainWindow::SetItemData (const wxTreeItemId& item, int column, wxTreeItemData *data) {
02306     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02307     ((wxTreeListItem*) item.m_pItem)->SetData(column, data);
02308 }
02309 
02310 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item,             bool bold) {
02311     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02312     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02313     if (pItem->IsBold() != bold) { // avoid redrawing if no real change
02314         pItem->SetBold (bold);
02315         RefreshLine (pItem);
02316     }
02317 }
02318 void wxTreeListMainWindow::SetItemBold (const wxTreeItemId& item, int column, bool bold) {
02319     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02320     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02321 //    if (pItem->IsBold(column) != bold) { // avoid redrawing if no real change
02322         pItem->SetBold (column, bold);
02323         RefreshLine (pItem);
02324 //    }
02325 }
02326 
02327 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item,             const wxColour& colour) {
02328     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02329     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02330     pItem->Attr().SetTextColour (colour);
02331     RefreshLine (pItem);
02332 }
02333 void wxTreeListMainWindow::SetItemTextColour (const wxTreeItemId& item, int column, const wxColour& colour) {
02334     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02335     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02336     pItem->Attr(column).SetTextColour (colour);
02337     RefreshLine (pItem);
02338 }
02339 
02340 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item,             const wxColour& colour) {
02341     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02342     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02343     pItem->Attr().SetBackgroundColour (colour);
02344     RefreshLine (pItem);
02345 }
02346 void wxTreeListMainWindow::SetItemBackgroundColour (const wxTreeItemId& item, int column, const wxColour& colour) {
02347     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02348     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02349     pItem->Attr(column).SetBackgroundColour (colour);
02350     RefreshLine (pItem);
02351 }
02352 
02353 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item,             const wxFont& font) {
02354     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02355     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02356     pItem->Attr().SetFont (font);
02357     RefreshLine (pItem);
02358 }
02359 void wxTreeListMainWindow::SetItemFont (const wxTreeItemId& item, int column, const wxFont& font) {
02360     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02361     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02362     pItem->Attr(column).SetFont (font);
02363     RefreshLine (pItem);
02364 }
02365 
02366 
02367 bool wxTreeListMainWindow::SetFont (const wxFont &font) {
02368     wxScrolledWindow::SetFont (font);
02369     m_normalFont = font;
02370 #if wxCHECK_VERSION(3, 0, 0)
02371     m_boldFont = wxFont (m_normalFont.GetPointSize(),
02372                          m_normalFont.GetFamily(),
02373                          m_normalFont.GetStyle(),
02374                          wxFONTWEIGHT_BOLD,
02375                          m_normalFont.GetUnderlined(),
02376                          m_normalFont.GetFaceName());
02377 #else
02378     m_boldFont = wxFont (m_normalFont.GetPointSize(),
02379                          m_normalFont.GetFamily(),
02380                          m_normalFont.GetStyle(),
02381                          wxBOLD,
02382                          m_normalFont.GetUnderlined(),
02383                          m_normalFont.GetFaceName());
02384 #endif
02385     CalculateLineHeight();
02386     return true;
02387 }
02388 
02389 
02390 // ----------------------------------------------------------------------------
02391 // item status inquiries
02392 // ----------------------------------------------------------------------------
02393 
02394 bool wxTreeListMainWindow::IsVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
02395     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
02396 
02397     // An item is only visible if it's not a descendant of a collapsed item
02398     wxTreeListItem *pItem = (wxTreeListItem*) item.m_pItem;
02399     wxTreeListItem* parent = pItem->GetItemParent();
02400     while (parent) {
02401         if (parent == m_rootItem && HasFlag(wxTR_HIDE_ROOT)) break;
02402         if (!parent->IsExpanded()) return false;
02403         parent = parent->GetItemParent();
02404     }
02405 
02406     // and the item is only visible if it is currently (fully) within the view
02407     if (within) {
02408         wxSize clientSize = GetClientSize();
02409         wxRect rect;
02410         if ((!GetBoundingRect (item, rect)) ||
02411             ((!fullRow && rect.GetWidth() == 0) || rect.GetHeight() == 0) ||
02412             (rect.GetTop() < 0 || rect.GetBottom() >= clientSize.y) ||
02413             (!fullRow && (rect.GetLeft() < 0 || rect.GetRight() >= clientSize.x))) return false;
02414     }
02415 
02416     return true;
02417 }
02418 
02419 bool wxTreeListMainWindow::HasChildren (const wxTreeItemId& item) const {
02420     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
02421 
02422     // consider that the item does have children if it has the "+" button: it
02423     // might not have them (if it had never been expanded yet) but then it
02424     // could have them as well and it's better to err on this side rather than
02425     // disabling some operations which are restricted to the items with
02426     // children for an item which does have them
02427     return ((wxTreeListItem*) item.m_pItem)->HasPlus();
02428 }
02429 
02430 bool wxTreeListMainWindow::IsExpanded (const wxTreeItemId& item) const {
02431     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
02432     return ((wxTreeListItem*) item.m_pItem)->IsExpanded();
02433 }
02434 
02435 bool wxTreeListMainWindow::IsSelected (const wxTreeItemId& item) const {
02436     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
02437     return ((wxTreeListItem*) item.m_pItem)->IsSelected();
02438 }
02439 
02440 bool wxTreeListMainWindow::IsBold (const wxTreeItemId& item, int column) const {
02441     wxCHECK_MSG (item.IsOk(), false, _T("invalid tree item"));
02442     return ((wxTreeListItem*) item.m_pItem)->IsBold(column);
02443 }
02444 
02445 // ----------------------------------------------------------------------------
02446 // navigation
02447 // ----------------------------------------------------------------------------
02448 
02449 wxTreeItemId wxTreeListMainWindow::GetItemParent (const wxTreeItemId& item) const {
02450     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02451     return ((wxTreeListItem*) item.m_pItem)->GetItemParent();
02452 }
02453 
02454 #if !wxCHECK_VERSION(2, 5, 0)
02455 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
02456                                                   long& cookie) const {
02457 #else
02458 wxTreeItemId wxTreeListMainWindow::GetFirstChild (const wxTreeItemId& item,
02459                                                   wxTreeItemIdValue& cookie) const {
02460 #endif
02461     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02462     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
02463     cookie = 0;
02464     return (!children.IsEmpty())? wxTreeItemId(children.Item(0)): wxTreeItemId();
02465 }
02466 
02467 #if !wxCHECK_VERSION(2, 5, 0)
02468 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
02469                                                  long& cookie) const {
02470 #else
02471 wxTreeItemId wxTreeListMainWindow::GetNextChild (const wxTreeItemId& item,
02472                                                  wxTreeItemIdValue& cookie) const {
02473 #endif
02474     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02475     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
02476     // it's ok to cast cookie to long, we never have indices which overflow "void*"
02477     long *pIndex = ((long*)&cookie);
02478     return ((*pIndex)+1 < (long)children.Count())? wxTreeItemId(children.Item(++(*pIndex))): wxTreeItemId();
02479 }
02480 
02481 #if !wxCHECK_VERSION(2, 5, 0)
02482 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
02483                                                  long& cookie) const {
02484 #else
02485 wxTreeItemId wxTreeListMainWindow::GetPrevChild (const wxTreeItemId& item,
02486                                                  wxTreeItemIdValue& cookie) const {
02487 #endif
02488     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02489     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
02490     // it's ok to cast cookie to long, we never have indices which overflow "void*"
02491     long *pIndex = (long*)&cookie;
02492     return ((*pIndex)-1 >= 0)? wxTreeItemId(children.Item(--(*pIndex))): wxTreeItemId();
02493 }
02494 
02495 #if !wxCHECK_VERSION(2, 5, 0)
02496 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
02497                                                  long& cookie) const {
02498 #else
02499 wxTreeItemId wxTreeListMainWindow::GetLastChild (const wxTreeItemId& item,
02500                                                  wxTreeItemIdValue& cookie) const {
02501 #endif
02502     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02503     wxArrayTreeListItems& children = ((wxTreeListItem*) item.m_pItem)->GetChildren();
02504     // it's ok to cast cookie to long, we never have indices which overflow "void*"
02505     long *pIndex = ((long*)&cookie);
02506     (*pIndex) = (long)children.Count();
02507     return (!children.IsEmpty())? wxTreeItemId(children.Last()): wxTreeItemId();
02508 }
02509 
02510 wxTreeItemId wxTreeListMainWindow::GetNextSibling (const wxTreeItemId& item) const {
02511     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02512 
02513     // get parent
02514     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
02515     wxTreeListItem *parent = i->GetItemParent();
02516     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
02517 
02518     // get index
02519     wxArrayTreeListItems& siblings = parent->GetChildren();
02520     size_t index = siblings.Index (i);
02521     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
02522     return (index < siblings.Count()-1)? wxTreeItemId(siblings[index+1]): wxTreeItemId();
02523 }
02524 
02525 wxTreeItemId wxTreeListMainWindow::GetPrevSibling (const wxTreeItemId& item) const {
02526     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02527 
02528     // get parent
02529     wxTreeListItem *i = (wxTreeListItem*) item.m_pItem;
02530     wxTreeListItem *parent = i->GetItemParent();
02531     if (!parent) return wxTreeItemId(); // root item doesn't have any siblings
02532 
02533     // get index
02534     wxArrayTreeListItems& siblings = parent->GetChildren();
02535     size_t index = siblings.Index(i);
02536     wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
02537     return (index >= 1)? wxTreeItemId(siblings[index-1]): wxTreeItemId();
02538 }
02539 
02540 // Only for internal use right now, but should probably be public
02541 wxTreeItemId wxTreeListMainWindow::GetNext (const wxTreeItemId& item, bool fulltree) const {
02542     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02543 
02544     // if there are any children, return first child
02545     if (fulltree || ((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
02546         wxArrayTreeListItems& children = ((wxTreeListItem*)item.m_pItem)->GetChildren();
02547         if (children.GetCount() > 0) return children.Item (0);
02548     }
02549 
02550     // get sibling of this item or of the ancestors instead
02551     wxTreeItemId next;
02552     wxTreeItemId parent = item;
02553     do {
02554         next = GetNextSibling (parent);
02555         parent = GetItemParent (parent);
02556     } while (!next.IsOk() && parent.IsOk());
02557     return next;
02558 }
02559 
02560 // Only for internal use right now, but should probably be public
02561 wxTreeItemId wxTreeListMainWindow::GetPrev (const wxTreeItemId& item, bool fulltree) const {
02562     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02563 
02564     // if there are no previous sibling get parent
02565     wxTreeItemId prev = GetPrevSibling (item);
02566     if (! prev.IsOk()) return GetItemParent (item);
02567 
02568     // while previous sibling has children, return last
02569     while (fulltree || ((wxTreeListItem*)prev.m_pItem)->IsExpanded()) {
02570         wxArrayTreeListItems& children = ((wxTreeListItem*)prev.m_pItem)->GetChildren();
02571         if (children.GetCount() == 0) break;
02572         prev = children.Item (children.GetCount() - 1);
02573     }
02574 
02575     return prev;
02576 }
02577 
02578 wxTreeItemId wxTreeListMainWindow::GetFirstExpandedItem() const {
02579     return GetNextExpanded (GetRootItem());
02580 }
02581 
02582 wxTreeItemId wxTreeListMainWindow::GetNextExpanded (const wxTreeItemId& item) const {
02583     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02584     return GetNext (item, false);
02585 }
02586 
02587 wxTreeItemId wxTreeListMainWindow::GetPrevExpanded (const wxTreeItemId& item) const {
02588     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02589     return GetPrev (item, false);
02590 }
02591 
02592 wxTreeItemId wxTreeListMainWindow::GetFirstVisible(bool fullRow, bool within) const {
02593     if (HasFlag(wxTR_HIDE_ROOT) || ! IsVisible(GetRootItem(), fullRow, within)) {
02594         return GetNextVisible (GetRootItem(), fullRow, within);
02595     } else {
02596         return GetRootItem();
02597     }
02598 }
02599 
02600 wxTreeItemId wxTreeListMainWindow::GetNextVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
02601     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02602     wxTreeItemId id = GetNext (item, false);
02603     while (id.IsOk()) {
02604         if (IsVisible (id, fullRow, within)) return id;
02605         id = GetNext (id, false);
02606     }
02607     return wxTreeItemId();
02608 }
02609 
02610 wxTreeItemId wxTreeListMainWindow::GetLastVisible ( bool fullRow, bool within) const {
02611     wxCHECK_MSG (GetRootItem().IsOk(), wxTreeItemId(), _T("invalid tree item"));
02612     wxTreeItemId id = GetRootItem();
02613     wxTreeItemId res = id;
02614     while ((id = GetNext (id, false)).IsOk()) {
02615         if (IsVisible (id, fullRow, within)) res = id;
02616     }
02617     return res;
02618 }
02619 
02620 wxTreeItemId wxTreeListMainWindow::GetPrevVisible (const wxTreeItemId& item, bool fullRow, bool within) const {
02621     wxCHECK_MSG (item.IsOk(), wxTreeItemId(), _T("invalid tree item"));
02622     wxTreeItemId id = GetPrev (item, true);
02623     while (id.IsOk()) {
02624         if (IsVisible (id, fullRow, within)) return id;
02625         id = GetPrev(id, true);
02626     }
02627     return wxTreeItemId();
02628 }
02629 
02630 // ----------------------------------------------------------------------------
02631 // operations
02632 // ----------------------------------------------------------------------------
02633 
02634 // ----------------------------  ADD OPERATION  -------------------------------
02635 
02636 wxTreeItemId wxTreeListMainWindow::DoInsertItem (const wxTreeItemId& parentId,
02637                                                  size_t previous,
02638                                                  const wxString& text,
02639                                                  int image, int selImage,
02640                                                  wxTreeItemData *data) {
02641     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
02642     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
02643     m_dirty = true; // do this first so stuff below doesn't cause flicker
02644 
02645     wxArrayString arr;
02646     arr.Alloc (GetColumnCount());
02647     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
02648     arr[m_main_column] = text;
02649     wxTreeListItem *item = new wxTreeListItem (this, parent, arr, image, selImage, data);
02650     if (data != NULL) {
02651 #if !wxCHECK_VERSION(2, 5, 0)
02652         data->SetId ((long)item);
02653 #else
02654         data->SetId (item);
02655 #endif
02656     }
02657     parent->Insert (item, previous);
02658 
02659     return item;
02660 }
02661 
02662 wxTreeItemId wxTreeListMainWindow::AddRoot (const wxString& text,
02663                                             int image, int selImage,
02664                                             wxTreeItemData *data) {
02665     wxCHECK_MSG(!m_rootItem, wxTreeItemId(), _T("tree can have only one root"));
02666     wxCHECK_MSG(GetColumnCount(), wxTreeItemId(), _T("Add column(s) before adding the root item"));
02667     m_dirty = true; // do this first so stuff below doesn't cause flicker
02668 
02669     wxArrayString arr;
02670     arr.Alloc (GetColumnCount());
02671     for (int i = 0; i < (int)GetColumnCount(); ++i) arr.Add (wxEmptyString);
02672     arr[m_main_column] = text;
02673     m_rootItem = new wxTreeListItem (this, (wxTreeListItem *)NULL, arr, image, selImage, data);
02674     if (data != NULL) {
02675 #if !wxCHECK_VERSION(2, 5, 0)
02676         data->SetId((long)m_rootItem);
02677 #else
02678         data->SetId(m_rootItem);
02679 #endif
02680     }
02681     if (HasFlag(wxTR_HIDE_ROOT)) {
02682         // if we will hide the root, make sure children are visible
02683         m_rootItem->SetHasPlus();
02684         m_rootItem->Expand();
02685 #if !wxCHECK_VERSION(2, 5, 0)
02686         long cookie = 0;
02687 #else
02688         wxTreeItemIdValue cookie = 0;
02689 #endif
02690         SetCurrentItem(GetFirstChild(m_rootItem, cookie));
02691     }
02692     return m_rootItem;
02693 }
02694 
02695 wxTreeItemId wxTreeListMainWindow::PrependItem (const wxTreeItemId& parent,
02696                                                 const wxString& text,
02697                                                 int image, int selImage,
02698                                                 wxTreeItemData *data) {
02699     return DoInsertItem (parent, 0u, text, image, selImage, data);
02700 }
02701 
02702 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
02703                                                const wxTreeItemId& idPrevious,
02704                                                const wxString& text,
02705                                                int image, int selImage,
02706                                                wxTreeItemData *data) {
02707     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
02708     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
02709 
02710     int index = parent->GetChildren().Index((wxTreeListItem*) idPrevious.m_pItem);
02711     wxASSERT_MSG( index != wxNOT_FOUND,
02712                   _T("previous item in wxTreeListMainWindow::InsertItem() is not a sibling") );
02713 
02714     return DoInsertItem (parentId, ++index, text, image, selImage, data);
02715 }
02716 
02717 wxTreeItemId wxTreeListMainWindow::InsertItem (const wxTreeItemId& parentId,
02718                                                size_t before,
02719                                                const wxString& text,
02720                                                int image, int selImage,
02721                                                wxTreeItemData *data) {
02722     wxTreeListItem *parent = (wxTreeListItem*)parentId.m_pItem;
02723     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
02724 
02725     return DoInsertItem (parentId, before, text, image, selImage, data);
02726 }
02727 
02728 wxTreeItemId wxTreeListMainWindow::AppendItem (const wxTreeItemId& parentId,
02729                                                const wxString& text,
02730                                                int image, int selImage,
02731                                                wxTreeItemData *data) {
02732     wxTreeListItem *parent = (wxTreeListItem*) parentId.m_pItem;
02733     wxCHECK_MSG (parent, wxTreeItemId(), _T("item must have a parent, at least root!") );
02734 
02735     return DoInsertItem (parent, parent->GetChildren().Count(), text, image, selImage, data);
02736 }
02737 
02738 
02739 // --------------------------  DELETE OPERATION  ------------------------------
02740 
02741 void wxTreeListMainWindow::Delete (const wxTreeItemId& itemId) {
02742     if (! itemId.IsOk()) return;
02743     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02744     wxTreeListItem *parent = item->GetItemParent();
02745     wxCHECK_RET (item != m_rootItem, _T("invalid item, root may not be deleted this way!"));
02746 
02747     // recursive delete
02748     DoDeleteItem(item);
02749 
02750     // update parent --CAUTION: must come after delete itself, so that item's
02751     //  siblings may be found
02752     if (parent) {
02753         parent->GetChildren().Remove (item);  // remove by value
02754     }
02755 }
02756 
02757 
02758 void wxTreeListMainWindow::DeleteRoot() {
02759     if (! m_rootItem) return;
02760 
02761     SetCurrentItem((wxTreeListItem*)NULL);
02762     m_selectItem = (wxTreeListItem*)NULL;
02763     m_shiftItem = (wxTreeListItem*)NULL;
02764 
02765     DeleteChildren (m_rootItem);
02766     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, m_rootItem);
02767     delete m_rootItem; m_rootItem = NULL;
02768 }
02769 
02770 
02771 void wxTreeListMainWindow::DeleteChildren (const wxTreeItemId& itemId) {
02772     if (! itemId.IsOk()) return;
02773     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02774 
02775     // recursive delete on all children, starting from the right to prevent
02776     //  multiple selection changes (see m_curItem handling in DoDeleteItem() )
02777     wxArrayTreeListItems& children = item->GetChildren();
02778     for (size_t n = children.GetCount(); n>0; n--) {
02779         DoDeleteItem(children[n-1]);
02780         // immediately remove child from array, otherwise it might get selected
02781         // as current item (see m_curItem handling in DoDeleteItem() )
02782         children.RemoveAt(n-1);
02783     }
02784 }
02785 
02786 
02787 void wxTreeListMainWindow::DoDeleteItem(wxTreeListItem *item) {
02788     wxCHECK_RET (item, _T("invalid item for delete!"));
02789 
02790     m_dirty = true; // do this first so stuff below doesn't cause flicker
02791 
02792     // cancel any editing
02793 
02794     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
02795 
02796     // cancel any dragging
02797     if (item == m_dragItem) {
02798         // stop dragging
02799         m_isDragStarted = m_isDragging = false;
02800         if (HasCapture()) ReleaseMouse();
02801     }
02802 
02803     // don't stay with invalid m_curItem: take next sibling or reset to NULL
02804     // NOTE: this might be slighty inefficient when deleting a whole tree
02805     //  but has the advantage that all deletion side-effects are handled here
02806     if (item == m_curItem) {
02807         SetCurrentItem(item->GetItemParent());
02808         if (m_curItem) {
02809             wxArrayTreeListItems& siblings = m_curItem->GetChildren();
02810             size_t index = siblings.Index (item);
02811             wxASSERT (index != (size_t)wxNOT_FOUND); // I'm not a child of my parent?
02812             SetCurrentItem(index < siblings.Count()-1 ? siblings[index+1]: (wxTreeListItem*)NULL);
02813         }
02814     }
02815     // don't stay with invalid m_shiftItem: reset it to NULL
02816     if (item == m_shiftItem) m_shiftItem = (wxTreeListItem*)NULL;
02817     // don't stay with invalid m_selectItem: default to current item
02818     if (item == m_selectItem) {
02819         m_selectItem = m_curItem;
02820         SelectItem(m_selectItem, (wxTreeItemId*)NULL, true);  // unselect others
02821     }
02822 
02823     // recurse children, starting from the right to prevent multiple selection
02824     //  changes (see m_curItem handling above)
02825     wxArrayTreeListItems& children = item->GetChildren();
02826     for (size_t n = children.GetCount(); n>0; n--) {
02827         DoDeleteItem(children[n-1]);
02828         // immediately remove child from array, otherwise it might get selected
02829         // as current item (see m_curItem handling above)
02830         children.RemoveAt(n-1);
02831     }
02832 
02833     // delete item itself
02834     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
02835     delete item;
02836 }
02837 
02838 
02839 // ----------------------------------------------------------------------------
02840 
02841 void wxTreeListMainWindow::SetItemParent(const wxTreeItemId& parentId, const wxTreeItemId& itemId) {
02842 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02843 wxTreeListItem *parent_new = (wxTreeListItem*) parentId.m_pItem;
02844 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::SetItemParent") );
02845 wxCHECK_RET (parent_new, _T("invalid parent in wxTreeListMainWindow::SetItemParent") );
02846 wxCHECK_RET (item != m_rootItem, _T("invalid root as item in wxTreeListMainWindow::SetItemParent!") );
02847 wxTreeListItem *parent_old = item->GetItemParent();
02848 
02849     m_dirty = true; // do this first so stuff below doesn't cause flicker
02850 
02851     parent_old->GetChildren().Remove (item);
02852     parent_new->Insert(item, parent_new->GetChildren().Count());
02853     item->SetItemParent(parent_new);
02854     // new parent was a leaf, show its new child
02855     if (parent_new->GetChildren().Count() == 1) parent_new->Expand();
02856 }
02857 
02858 
02859 // ----------------------------------------------------------------------------
02860 
02861 void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
02862   SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
02863 }
02864 void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
02865 wxTreeListItem *old_item;
02866 
02867     old_item = m_curItem; m_curItem = item;
02868 
02869     // change of item, redraw previous
02870     if (old_item != NULL && old_item != item) {
02871         RefreshLine(old_item);
02872     }
02873 
02874 }
02875 
02876 // ----------------------------------------------------------------------------
02877 
02878 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
02879     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02880     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
02881 
02882     if (!item->HasPlus() || item->IsExpanded()) return;
02883 
02884     // send event to user code
02885     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
02886     event.SetInt(m_curColumn);
02887     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled
02888 
02889     item->Expand();
02890     m_dirty = true;
02891 
02892     // send event to user code
02893     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
02894     SendEvent(0, NULL, &event);
02895 }
02896 
02897 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
02898     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
02899 
02900     Expand (itemId);
02901     if (!IsExpanded (itemId)) return;
02902 #if !wxCHECK_VERSION(2, 5, 0)
02903     long cookie;
02904 #else
02905     wxTreeItemIdValue cookie;
02906 #endif
02907     wxTreeItemId child = GetFirstChild (itemId, cookie);
02908     while (child.IsOk()) {
02909         ExpandAll (child);
02910         child = GetNextChild (itemId, cookie);
02911     }
02912 }
02913 
02914 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
02915     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02916     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
02917 
02918     if (!item->HasPlus() || !item->IsExpanded()) return;
02919 
02920     // send event to user code
02921     wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 );
02922     event.SetInt(m_curColumn);
02923     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled
02924 
02925     item->Collapse();
02926     m_dirty = true;
02927 
02928     // send event to user code
02929     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
02930     SendEvent(0, NULL, &event);
02931 }
02932 
02933 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
02934     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02935 
02936     Collapse (item);
02937     DeleteChildren (item);
02938 }
02939 
02940 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
02941     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
02942 
02943     if (IsExpanded (itemId)) {
02944         Collapse (itemId);
02945     }else{
02946         Expand (itemId);
02947     }
02948 }
02949 
02950 void wxTreeListMainWindow::Unselect() {
02951     if (m_selectItem) {
02952         m_selectItem->SetHilight (false);
02953         RefreshLine (m_selectItem);
02954         m_selectItem = (wxTreeListItem*)NULL;
02955     }
02956 }
02957 
02958 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
02959     wxCHECK_RET (item, _T("invalid tree item"));
02960 
02961     if (item->IsSelected()) {
02962         item->SetHilight (false);
02963         RefreshLine (item);
02964         if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
02965         if (item != m_curItem) m_lastOnSame = false;  // selection change, so reset edit marker
02966     }
02967     if (item->HasChildren()) {
02968         wxArrayTreeListItems& children = item->GetChildren();
02969         size_t count = children.Count();
02970         for (size_t n = 0; n < count; ++n) {
02971             UnselectAllChildren (children[n]);
02972         }
02973     }
02974 }
02975 
02976 void wxTreeListMainWindow::UnselectAll() {
02977     UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
02978 }
02979 
02980 // Recursive function !
02981 // To stop we must have crt_item<last_item
02982 // Algorithm :
02983 // Tag all next children, when no more children,
02984 // Move to parent (not to tag)
02985 // Keep going... if we found last_item, we stop.
02986 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
02987                                             wxTreeListItem *last_item) {
02988     wxTreeListItem *parent = crt_item->GetItemParent();
02989 
02990     if (!parent) {// This is root item
02991         return TagAllChildrenUntilLast (crt_item, last_item);
02992     }
02993 
02994     wxArrayTreeListItems& children = parent->GetChildren();
02995     int index = children.Index(crt_item);
02996     wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
02997 
02998     if ((parent->HasChildren() && parent->IsExpanded()) ||
02999         ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
03000         size_t count = children.Count();
03001         for (size_t n = (index+1); n < count; ++n) {
03002             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
03003         }
03004     }
03005 
03006     return TagNextChildren (parent, last_item);
03007 }
03008 
03009 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
03010                                                     wxTreeListItem *last_item) {
03011     crt_item->SetHilight (true);
03012     RefreshLine(crt_item);
03013 
03014     if (crt_item==last_item) return true;
03015 
03016     if (crt_item->HasChildren() && crt_item->IsExpanded()) {
03017         wxArrayTreeListItems& children = crt_item->GetChildren();
03018         size_t count = children.Count();
03019         for (size_t n = 0; n < count; ++n) {
03020             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
03021         }
03022     }
03023 
03024     return false;
03025 }
03026 
03027 bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
03028                                        const wxTreeItemId& lastId,
03029                                        bool unselect_others) {
03030 
03031     wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
03032 
03033     // send selecting event to the user code
03034     wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
03035     event.SetInt(m_curColumn);
03036 #if !wxCHECK_VERSION(2, 5, 0)
03037     event.SetOldItem ((long)m_curItem);
03038 #else
03039     event.SetOldItem (m_curItem);
03040 #endif
03041     if (SendEvent(0, item, &event) && !event.IsAllowed()) return false;  // veto on selection change
03042 
03043     // unselect all if unselect other items
03044     bool bUnselectedAll = false; // see that UnselectAll is done only once
03045     if (unselect_others) {
03046         if (HasFlag(wxTR_MULTIPLE)) {
03047             UnselectAll(); bUnselectedAll = true;
03048         }else{
03049             Unselect(); // to speed up thing
03050         }
03051     }
03052 
03053     // select item range
03054     if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
03055 
03056         if (! bUnselectedAll) UnselectAll();
03057         wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
03058 
03059         // ensure that the position of the item it calculated in any case
03060         if (m_dirty) CalculatePositions();
03061 
03062         // select item range according Y-position
03063         if (last->GetY() < item->GetY()) {
03064             if (!TagAllChildrenUntilLast (last, item)) {
03065                 TagNextChildren (last, item);
03066             }
03067         }else{
03068             if (!TagAllChildrenUntilLast (item, last)) {
03069                 TagNextChildren (item, last);
03070             }
03071         }
03072 
03073     // or select single item
03074     }else if (itemId.IsOk()) {
03075 
03076         // select item according its old selection
03077         item->SetHilight (!item->IsSelected());
03078         RefreshLine (item);
03079         if (unselect_others) {
03080             m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
03081         }
03082 
03083     // or select nothing
03084     } else {
03085         if (! bUnselectedAll) UnselectAll();
03086     }
03087 
03088     // send event to user code
03089     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
03090     SendEvent(0, NULL, &event);
03091 
03092     return true;
03093 }
03094 
03095 void wxTreeListMainWindow::SelectAll() {
03096     wxTreeItemId root = GetRootItem();
03097     wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
03098     wxCHECK_RET (root.IsOk(), _T("no tree"));
03099 
03100     // send event to user code
03101     wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
03102 #if !wxCHECK_VERSION(2, 5, 0)
03103     event.SetOldItem ((long)m_curItem);
03104 #else
03105     event.SetOldItem (m_curItem);
03106 #endif
03107     event.SetInt (-1); // no colum clicked
03108     if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return;  // selection change vetoed
03109 
03110 #if !wxCHECK_VERSION(2, 5, 0)
03111     long cookie = 0;
03112 #else
03113     wxTreeItemIdValue cookie = 0;
03114 #endif
03115     wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
03116     wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
03117     if (!TagAllChildrenUntilLast (first, last)) {
03118         TagNextChildren (first, last);
03119     }
03120 
03121     // send event to user code
03122     event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
03123     SendEvent(0, NULL, &event);
03124 }
03125 
03126 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
03127                                       wxArrayTreeItemIds &array) const {
03128     if (item->IsSelected()) array.Add (wxTreeItemId(item));
03129 
03130     if (item->HasChildren()) {
03131         wxArrayTreeListItems& children = item->GetChildren();
03132         size_t count = children.GetCount();
03133         for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
03134     }
03135 }
03136 
03137 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
03138     array.Empty();
03139     wxTreeItemId idRoot = GetRootItem();
03140     if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
03141     return array.Count();
03142 }
03143 
03144 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
03145     if (!item.IsOk()) return; // do nothing if no item
03146 
03147     // first expand all parent branches
03148     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
03149     wxTreeListItem *parent = gitem->GetItemParent();
03150     while (parent) {
03151         Expand (parent);
03152         parent = parent->GetItemParent();
03153     }
03154 
03155     ScrollTo (item);
03156     RefreshLine (gitem);
03157 }
03158 
03159 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
03160     if (!item.IsOk()) return; // do nothing if no item
03161 
03162     // ensure that the position of the item it calculated in any case
03163     if (m_dirty) CalculatePositions();
03164 
03165     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
03166 
03167     // now scroll to the item
03168     int item_y = gitem->GetY();
03169 
03170     int xUnit, yUnit;
03171     GetScrollPixelsPerUnit (&xUnit, &yUnit);
03172     int start_x = 0;
03173     int start_y = 0;
03174     GetViewStart (&start_x, &start_y);
03175     start_y *= yUnit;
03176 
03177     int client_h = 0;
03178     int client_w = 0;
03179     GetClientSize (&client_w, &client_h);
03180 
03181     int x = 0;
03182     int y = 0;
03183     m_rootItem->GetSize (x, y, this);
03184     x = m_owner->GetHeaderWindow()->GetWidth();
03185     y += yUnit + 2; // one more scrollbar unit + 2 pixels
03186     int x_pos = GetScrollPos( wxHORIZONTAL );
03187 
03188     if (item_y < start_y+3) {
03189         // going down, item should appear at top
03190         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
03191     }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
03192         // going up, item should appear at bottom
03193         item_y += yUnit + 2;
03194         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
03195     }
03196 }
03197 
03198 // TODO: tree sorting functions are not reentrant and not MT-safe!
03199 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
03200 
03201 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2)
03202 {
03203     wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
03204     return s_treeBeingSorted->OnCompareItems(*item1, *item2);
03205 }
03206 
03207 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
03208 {
03209     return (m_sortColumn == -1
03210         ? m_owner->OnCompareItems (item1, item2)
03211         : (m_ReverseSortOrder
03212             ? m_owner->OnCompareItems (item2, item1, m_sortColumn)
03213             : m_owner->OnCompareItems (item1, item2, m_sortColumn)
03214         )
03215     );
03216 }
03217 
03218 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId, int column, bool reverseOrder) {
03219     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
03220 
03221     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
03222 
03223     wxCHECK_RET (!s_treeBeingSorted,
03224                  _T("wxTreeListMainWindow::SortChildren is not reentrant") );
03225 
03226     wxArrayTreeListItems& children = item->GetChildren();
03227     if ( children.Count() > 1 ) {
03228         m_dirty = true;
03229         s_treeBeingSorted = this;
03230         m_sortColumn = column;  // -1 indicates legacy mode
03231         m_ReverseSortOrder = reverseOrder;
03232         children.Sort(tree_ctrl_compare_func);
03233         s_treeBeingSorted = NULL;
03234     }
03235 }
03236 
03237 bool wxTreeListMainWindow::MatchItemText(const wxString &itemText, const wxString &pattern, int mode) {
03238 wxString searchText;
03239 
03240    if (mode & wxTL_MODE_FIND_PARTIAL) {
03241        searchText = itemText.Mid (0, pattern.Length());
03242    }else{
03243        searchText = itemText;
03244    }
03245    if (mode & wxTL_MODE_FIND_NOCASE) {
03246        if (searchText.CmpNoCase (pattern) == 0) return true;
03247    }else{
03248        if (searchText.Cmp (pattern) == 0) return true;
03249    }
03250 
03251    return false;
03252 }
03253 
03254 
03255 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode) {
03256 #if !wxCHECK_VERSION(2, 5, 0)
03257     long cookie = 0;
03258 #else
03259     wxTreeItemIdValue cookie = 0;
03260 #endif
03261     wxTreeItemId next = item;
03262 
03263     // start checking the next items
03264     wxString itemText;
03265     int col, col_start, col_end;
03266     if (column >= 0) { col_start = col_end = column; }
03267     else { col_start = 0; col_end = GetColumnCount() - 1; }
03268 
03269     // navigate tree
03270     while (true) {
03271         // go to next item
03272         if (next.IsOk()) {
03273             if (mode & wxTL_MODE_NAV_LEVEL) {
03274                 next = GetNextSibling (next);
03275             }else if (mode & wxTL_MODE_NAV_VISIBLE) {
03276                 next = GetNextVisible (next, false, true);
03277             }else if (mode & wxTL_MODE_NAV_EXPANDED) {
03278                 next = GetNextExpanded (next);
03279             }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
03280                 next = GetNext (next, true);
03281             }
03282         // not a valid item, start at the top of the tree
03283         } else {
03284             next = GetRootItem();
03285             if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) {
03286                 next = GetFirstChild (GetRootItem(), cookie);
03287             }
03288         }
03289         // end of tree (or back to beginning) ?
03290         if (! next.IsOk() || next == item) return (wxTreeItemId*)NULL;
03291         // check for a match
03292         for (col=col_start; col<=col_end; col++) {
03293             if (MatchItemText(GetItemText (next, col),str, mode)) return next;
03294         }
03295     }
03296     // should never get here
03297     return (wxTreeItemId*)NULL;
03298 }
03299 
03300 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
03301     wxTreeListItem *prevItem = m_dragItem;
03302     m_dragItem = (wxTreeListItem*) item.m_pItem;
03303     if (prevItem) RefreshLine (prevItem);
03304     if (m_dragItem) RefreshLine (m_dragItem);
03305 }
03306 
03307 void wxTreeListMainWindow::CalculateLineHeight() {
03308     wxClientDC dc (this);
03309     dc.SetFont (m_normalFont);
03310     m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
03311 
03312     if (m_imageListNormal) {
03313         // Calculate a m_lineHeight value from the normal Image sizes.
03314         // May be toggle off. Then wxTreeListMainWindow will spread when
03315         // necessary (which might look ugly).
03316         int n = m_imageListNormal->GetImageCount();
03317         for (int i = 0; i < n ; i++) {
03318             int width = 0, height = 0;
03319             m_imageListNormal->GetSize(i, width, height);
03320             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
03321         }
03322     }
03323 
03324     if (m_imageListButtons) {
03325         // Calculate a m_lineHeight value from the Button image sizes.
03326         // May be toggle off. Then wxTreeListMainWindow will spread when
03327         // necessary (which might look ugly).
03328         int n = m_imageListButtons->GetImageCount();
03329         for (int i = 0; i < n ; i++) {
03330             int width = 0, height = 0;
03331             m_imageListButtons->GetSize(i, width, height);
03332             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
03333         }
03334     }
03335 
03336     if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
03337         m_lineHeight += 2; // minimal 2 pixel space
03338     }else{
03339         m_lineHeight += m_lineHeight / 10; // otherwise 10% space
03340     }
03341 }
03342 
03343 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
03344     if (m_ownsImageListNormal) delete m_imageListNormal;
03345     m_imageListNormal = imageList;
03346     m_ownsImageListNormal = false;
03347     m_dirty = true;
03348     CalculateLineHeight();
03349 }
03350 
03351 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
03352     if (m_ownsImageListState) delete m_imageListState;
03353     m_imageListState = imageList;
03354     m_ownsImageListState = false;
03355 }
03356 
03357 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
03358     if (m_ownsImageListButtons) delete m_imageListButtons;
03359     m_imageListButtons = imageList;
03360     m_ownsImageListButtons = false;
03361     m_dirty = true;
03362     CalculateLineHeight();
03363 }
03364 
03365 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
03366     SetImageList(imageList);
03367     m_ownsImageListNormal = true;
03368 }
03369 
03370 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
03371     SetStateImageList(imageList);
03372     m_ownsImageListState = true;
03373 }
03374 
03375 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
03376     SetButtonsImageList(imageList);
03377     m_ownsImageListButtons = true;
03378 }
03379 
03380 // ----------------------------------------------------------------------------
03381 // helpers
03382 // ----------------------------------------------------------------------------
03383 
03384 void wxTreeListMainWindow::AdjustMyScrollbars() {
03385     if (m_rootItem) {
03386         int xUnit, yUnit;
03387         GetScrollPixelsPerUnit (&xUnit, &yUnit);
03388         if (xUnit == 0) xUnit = GetCharWidth();
03389         if (yUnit == 0) yUnit = m_lineHeight;
03390         int x = 0, y = 0;
03391         m_rootItem->GetSize (x, y, this);
03392         y += yUnit + 2; // one more scrollbar unit + 2 pixels
03393         int x_pos = GetScrollPos (wxHORIZONTAL);
03394         int y_pos = GetScrollPos (wxVERTICAL);
03395         x = m_owner->GetHeaderWindow()->GetWidth() + 2;
03396         if (x < GetClientSize().GetWidth()) x_pos = 0;
03397         SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
03398     }else{
03399         SetScrollbars (0, 0, 0, 0);
03400     }
03401 }
03402 
03403 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
03404     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
03405         return item->GetHeight();
03406     }else{
03407         return m_lineHeight;
03408     }
03409 }
03410 
03411 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
03412 
03413 // read attributes constant for all item cells
03414     wxColour colText = GetItemTextColour(item);
03415     wxColour colBg = GetItemBackgroundColour(item);
03416 #if !wxCHECK_VERSION(2, 5, 0)
03417     wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
03418 #else
03419     wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
03420 #endif
03421     int total_w = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetMainWindow()->GetClientSize().GetWidth());
03422     int total_h = GetLineHeight(item);
03423     int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
03424     int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
03425     wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
03426     // compute text height based on main col
03427     int text_h = 0;
03428     dc.GetTextExtent( item->GetText(GetMainColumn()).size() > 0
03429             ? item->GetText(GetMainColumn())
03430             : _T("M"),  // dummy text to avoid zero height and no highlight width
03431         NULL, &text_h );
03432 
03433 // determine background and show it
03434 // in wxTR_FULL_ROW_HIGHLIGHT mode, some drawing can be done already now
03435 #if wxCHECK_VERSION(3, 0, 0)
03436     dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03437 #else
03438     dc.SetBrush (wxBrush ( colBg, wxSOLID));
03439 #endif
03440     dc.SetPen (*wxTRANSPARENT_PEN);
03441     if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
03442         if (item->IsSelected()) {
03443             if (! m_isDragging && m_hasFocus) {
03444                 dc.SetBrush (*m_hilightBrush);
03445 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03446                 dc.SetPen (*wxBLACK_PEN);
03447 #endif // !__WXMAC__
03448             }else{
03449                 dc.SetBrush (*m_hilightUnfocusedBrush);
03450 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03451                 dc.SetPen (*wxTRANSPARENT_PEN);
03452 #endif // !__WXMAC__
03453             }
03454             dc.SetTextForeground (colTextHilight);
03455         }else {
03456             dc.SetTextForeground (GetItemTextColour(item));
03457             if (item == m_curItem) {
03458                 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
03459             }
03460         }
03461         dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
03462     }
03463 
03464 // iterate through all cells
03465     int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
03466     int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
03467     int x_colstart = 0;
03468     for (int i = 0; i < GetColumnCount(); ++i ) {
03469         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
03470         int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
03471         if (col_w <= 0) continue;  // workaround for probable GTK2 bug [wxCode-Bugs-#3061215]
03472         wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
03473 
03474         // read variable attributes
03475         dc.SetFont (GetItemFont (item, i));
03476         colText = GetItemTextColour(item, i);
03477         colBg = GetItemBackgroundColour(item, i);
03478 
03479         //
03480         int x = 0;
03481         int image = NO_IMAGE;
03482         int image_w = 0;
03483         if(i == GetMainColumn()) {
03484             x = item->GetX() + MARGIN;
03485             if (HasButtons()) {
03486                 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
03487             }else{
03488                 x -= m_indent/2;
03489             }
03490             if (m_imageListNormal) image = item->GetCurrentImage();
03491         }else{
03492             x = x_colstart + MARGIN;
03493             image = item->GetImage(i);
03494         }
03495         if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
03496 
03497         // honor text alignment
03498         int w = 0, text_w = 0;
03499         wxString text = item->GetText(i);
03500         dc.GetTextExtent (text, &text_w, NULL);
03501         switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
03502         case wxALIGN_LEFT:
03503             // nothing to do, already left aligned
03504             break;
03505         case wxALIGN_RIGHT:
03506             w = col_w - (image_w + text_w + off_w + MARGIN);
03507             x += (w > 0)? w: 0;
03508             break;
03509         case wxALIGN_CENTER:
03510             w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
03511             x += (w > 0)? w: 0;
03512             break;
03513         }
03514         int text_x = x + image_w;
03515         if (i == GetMainColumn()) item->SetTextX (text_x);
03516 
03517         // draw background (in non wxTR_FULL_ROW_HIGHLIGHT mode)
03518         // cell-specific settings are used --excepted for selection:
03519         if ( ! HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
03520             // cursor: indicate current cell
03521             bool drawCursor = false;
03522 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03523             drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
03524 #endif // !__WXMAC__
03525             // selection: main col only, overrides colors + separate draw
03526             if (item->IsSelected() && i == GetMainColumn()) {
03527                 // draw normal background
03528                 dc.SetPen (*wxTRANSPARENT_PEN);
03529 #if wxCHECK_VERSION(3, 0, 0)
03530                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03531 #else
03532                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
03533 #endif
03534                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
03535                 // draw selection & optionally cursor
03536                 dc.SetPen (drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
03537                 dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
03538                 dc.SetTextForeground (colTextHilight);
03539                 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
03540             // normal FG / BG from attributes
03541             } else {
03542                 // draw normal background & optionally cursor
03543                 dc.SetPen (drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
03544 #if wxCHECK_VERSION(3, 0, 0)
03545                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03546 #else
03547                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
03548 #endif
03549                 dc.SetTextForeground (colText);
03550                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
03551                 // on main col draw a separate cursor
03552                 if (drawCursor && i == GetMainColumn()) {
03553                     dc.SetPen (*wxBLACK_PEN);
03554                     dc.SetBackgroundMode (wxTRANSPARENT);
03555                     dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
03556                 }
03557             }
03558         }
03559 
03560         // draw vertical column lines
03561         if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
03562 #if !wxCHECK_VERSION(2, 5, 0)
03563             wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03564 #else
03565 #if wxCHECK_VERSION(3, 0, 0)
03566             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxPENSTYLE_SOLID);
03567 #else
03568             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03569 #endif
03570 #endif
03571             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
03572             dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
03573         }
03574 
03575         dc.SetBackgroundMode (wxTRANSPARENT);
03576 
03577         // draw image
03578         if (image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
03579             int y = item->GetY() + img_extraH;
03580             m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
03581         }
03582 
03583         // draw text
03584         int text_y = item->GetY() + text_extraH;
03585         dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
03586 
03587         x_colstart += col_w;
03588     }
03589 
03590     // restore normal font
03591     dc.SetFont( m_normalFont );
03592 }
03593 
03594 // Now y stands for the top of the item, whereas it used to stand for middle !
03595 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
03596                                        int level, int &y, int x_maincol) {
03597 
03598     // Handle hide root (only level 0)
03599     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
03600         wxArrayTreeListItems& children = item->GetChildren();
03601         for (size_t n = 0; n < children.Count(); n++) {
03602             PaintLevel (children[n], dc, 1, y, x_maincol);
03603         }
03604         // end after expanding root
03605         return;
03606     }
03607 
03608     // calculate position of vertical lines
03609     int x = x_maincol + MARGIN; // start of column
03610     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
03611     if (HasButtons()) {
03612         x += (m_btnWidth-m_btnWidth2); // half button space
03613     }else{
03614         x += (m_indent-m_indent/2);
03615     }
03616     if (HasFlag(wxTR_HIDE_ROOT)) {
03617         x += m_indent * (level-1); // indent but not level 1
03618     }else{
03619         x += m_indent * level; // indent according to level
03620     }
03621 
03622     // set position of vertical line
03623     item->SetX (x);
03624     item->SetY (y);
03625 
03626     int h = GetLineHeight (item);
03627     int y_top = y;
03628     int y_mid = y_top + (h/2);
03629     y += h;
03630 
03631     int exposed_x = dc.LogicalToDeviceX(0);
03632     int exposed_y = dc.LogicalToDeviceY(y_top);
03633 
03634     if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
03635 
03636         if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
03637             //dc.DestroyClippingRegion();
03638             int total_width = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetClientSize().GetWidth());
03639             // if the background colour is white, choose a
03640             // contrasting color for the lines
03641 #if !wxCHECK_VERSION(2, 5, 0)
03642             wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03643 #else
03644 #if wxCHECK_VERSION(3, 0, 0)
03645             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxPENSTYLE_SOLID);
03646 #else
03647             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03648 #endif
03649 #endif
03650             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
03651             dc.DrawLine (0, y_top, total_width, y_top);
03652             dc.DrawLine (0, y_top+h, total_width, y_top+h);
03653         }
03654 
03655         // draw item
03656         PaintItem (item, dc);
03657 
03658         // restore DC objects
03659         dc.SetBrush(*wxWHITE_BRUSH);
03660         dc.SetPen(m_dottedPen);
03661 
03662         // clip to the column width
03663         int clip_width = m_owner->GetHeaderWindow()->
03664                             GetColumn(m_main_column).GetWidth();
03665         wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
03666 
03667         if (!HasFlag(wxTR_NO_LINES)) { // connection lines
03668 
03669             // draw the horizontal line here
03670             dc.SetPen(m_dottedPen);
03671             int x2 = x - m_indent;
03672             if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
03673             int x3 = x + (m_btnWidth-m_btnWidth2);
03674             if (HasButtons()) {
03675                 if (item->HasPlus()) {
03676                     dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
03677                     dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
03678                 }else{
03679                     dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
03680                 }
03681             }else{
03682                 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
03683             }
03684         }
03685 
03686         if (item->HasPlus() && HasButtons()) { // should the item show a button?
03687 
03688             if (m_imageListButtons) {
03689 
03690                 // draw the image button here
03691                 int image = wxTreeItemIcon_Normal;
03692                 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
03693                 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
03694                 int xx = x - m_btnWidth2 + MARGIN;
03695                 int yy = y_mid - m_btnHeight2;
03696                 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
03697                 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
03698                 dc.DestroyClippingRegion();
03699 
03700             }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
03701 
03702                 // draw the twisty button here
03703                 dc.SetPen(*wxBLACK_PEN);
03704                 dc.SetBrush(*m_hilightBrush);
03705                 wxPoint button[3];
03706                 if (item->IsExpanded()) {
03707                     button[0].x = x - (m_btnWidth2+1);
03708                     button[0].y = y_mid - (m_btnHeight/3);
03709                     button[1].x = x + (m_btnWidth2+1);
03710                     button[1].y = button[0].y;
03711                     button[2].x = x;
03712                     button[2].y = button[0].y + (m_btnHeight2+1);
03713                 }else{
03714                     button[0].x = x - (m_btnWidth/3);
03715                     button[0].y = y_mid - (m_btnHeight2+1);
03716                     button[1].x = button[0].x;
03717                     button[1].y = y_mid + (m_btnHeight2+1);
03718                     button[2].x = button[0].x + (m_btnWidth2+1);
03719                     button[2].y = y_mid;
03720                 }
03721                 dc.DrawPolygon(3, button);
03722 
03723             }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
03724 
03725                 // draw the plus sign here
03726 #if !wxCHECK_VERSION(2, 7, 0)
03727                 dc.SetPen(*wxGREY_PEN);
03728                 dc.SetBrush(*wxWHITE_BRUSH);
03729                 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
03730                 dc.SetPen(*wxBLACK_PEN);
03731                 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
03732                 if (!item->IsExpanded()) { // change "-" to "+"
03733                     dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
03734                 }
03735 #else
03736                 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
03737                 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
03738                 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
03739 #endif
03740 
03741             }
03742 
03743         }
03744 
03745     }
03746 
03747     // restore DC objects
03748     dc.SetBrush(*wxWHITE_BRUSH);
03749     dc.SetPen(m_dottedPen);
03750     dc.SetTextForeground(*wxBLACK);
03751 
03752     if (item->IsExpanded())
03753     {
03754         wxArrayTreeListItems& children = item->GetChildren();
03755 
03756         // clip to the column width
03757         int clip_width = m_owner->GetHeaderWindow()->
03758                             GetColumn(m_main_column).GetWidth();
03759 
03760         // process lower levels
03761         int oldY;
03762         if (m_imgWidth > 0) {
03763             oldY = y_mid + m_imgHeight2;
03764         }else{
03765             oldY = y_mid + h/2;
03766         }
03767         int y2;
03768         for (size_t n = 0; n < children.Count(); ++n) {
03769 
03770             y2 = y + h/2;
03771             PaintLevel (children[n], dc, level+1, y, x_maincol);
03772 
03773             // draw vertical line
03774             wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
03775             if (!HasFlag (wxTR_NO_LINES)) {
03776                 x = item->GetX();
03777                 dc.DrawLine (x, oldY, x, y2);
03778                 oldY = y2;
03779             }
03780         }
03781     }
03782 }
03783 
03784 
03785 // ----------------------------------------------------------------------------
03786 // wxWindows callbacks
03787 // ----------------------------------------------------------------------------
03788 
03789 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
03790 
03791     // init device context, clear background (BEFORE changing DC origin...)
03792     wxAutoBufferedPaintDC dc (this);
03793 #if wxCHECK_VERSION(3, 0, 0)
03794     wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
03795 #else
03796     wxBrush brush(GetBackgroundColour(), wxSOLID);
03797 #endif
03798     dc.SetBackground(brush);
03799     dc.Clear();
03800     DoPrepareDC (dc);
03801 
03802     if (!m_rootItem || (GetColumnCount() <= 0)) return;
03803 
03804     // calculate button size
03805     if (m_imageListButtons) {
03806         m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
03807     }else if (HasButtons()) {
03808         m_btnWidth = BTNWIDTH;
03809         m_btnHeight = BTNHEIGHT;
03810     }
03811     m_btnWidth2 = m_btnWidth/2;
03812     m_btnHeight2 = m_btnHeight/2;
03813 
03814     // calculate image size
03815     if (m_imageListNormal) {
03816         m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
03817     }
03818     m_imgWidth2 = m_imgWidth/2;
03819     m_imgHeight2 = m_imgHeight/2;
03820 
03821     // calculate indent size
03822     if (m_imageListButtons) {
03823         m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
03824     }else if (HasButtons()) {
03825         m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
03826     }
03827 
03828     // set default values
03829     dc.SetFont( m_normalFont );
03830     dc.SetPen( m_dottedPen );
03831 
03832     // calculate column start and paint
03833     int x_maincol = 0;
03834     int i = 0;
03835     for (i = 0; i < (int)GetMainColumn(); ++i) {
03836         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
03837         x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
03838     }
03839     int y = 0;
03840     PaintLevel (m_rootItem, dc, 0, y, x_maincol);
03841 }
03842 
03843 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
03844     m_hasFocus = true;
03845     RefreshSelected();
03846     if (m_curItem) RefreshLine (m_curItem);
03847     event.Skip();
03848 }
03849 
03850 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
03851 {
03852     m_hasFocus = false;
03853     RefreshSelected();
03854     if (m_curItem) RefreshLine (m_curItem);
03855     event.Skip();
03856 }
03857 
03858 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
03859     // send event to user code
03860     wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 );
03861     nevent.SetInt(m_curColumn);
03862     nevent.SetKeyEvent (event);
03863     if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
03864 
03865     // if no item current, select root
03866     bool curItemSet = false;
03867     if (!m_curItem) {
03868         if (! GetRootItem().IsOk()) return;
03869         SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
03870         if (HasFlag(wxTR_HIDE_ROOT)) {
03871 #if !wxCHECK_VERSION(2, 5, 0)
03872             long cookie = 0;
03873 #else
03874             wxTreeItemIdValue cookie = 0;
03875 #endif
03876             SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
03877         }
03878         SelectItem(m_curItem, (wxTreeItemId*)NULL, true);  // unselect others
03879         curItemSet = true;
03880     }
03881 
03882     // remember item at shift down
03883     if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
03884         if (!m_shiftItem) m_shiftItem = m_curItem;
03885     }else{
03886         m_shiftItem = (wxTreeListItem*)NULL;
03887     }
03888 
03889     if (curItemSet) return;  // if no item was current until now, do nothing more
03890 
03891     // process all cases
03892     wxTreeItemId newItem = (wxTreeItemId*)NULL;
03893     switch (event.GetKeyCode()) {
03894 
03895         // '+': Expand subtree
03896         case '+':
03897         case WXK_ADD: {
03898             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
03899         }break;
03900 
03901         // '-': collapse subtree
03902         case '-':
03903         case WXK_SUBTRACT: {
03904             if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
03905         }break;
03906 
03907         // '*': expand/collapse all subtrees // TODO: Mak it more useful
03908         case '*':
03909         case WXK_MULTIPLY: {
03910             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
03911                 ExpandAll (m_curItem);
03912             }else if (m_curItem->HasPlus()) {
03913                 Collapse (m_curItem); // TODO: CollapseAll
03914             }
03915         }break;
03916 
03917         // ' ': toggle current item
03918         case ' ': {
03919             SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
03920         }break;
03921 
03922         // <RETURN>: activate current item
03923         case WXK_RETURN: {
03924             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
03925 
03926                 // if the user code didn't process the activate event,
03927                 // handle it ourselves by toggling the item when it is
03928                 // double clicked
03929                 if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
03930             }
03931         }break;
03932 
03933         // <BKSP>: go to the parent without collapsing
03934         case WXK_BACK: {
03935             newItem = GetItemParent (m_curItem);
03936             if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03937                 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
03938             }
03939         }break;
03940 
03941         // <HOME>: go to first visible
03942         case WXK_HOME: {
03943             newItem = GetFirstVisible(false, false);
03944         }break;
03945 
03946         // <PAGE-UP>: go to the top of the page, or if we already are then one page back
03947         case WXK_PAGEUP: {
03948         int flags = 0;
03949         int col = 0;
03950         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
03951         // PAGE-UP: first go the the first visible row
03952             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03953             newItem = GetFirstVisible(false, true);
03954         // if we are already there then scroll back one page
03955             if (newItem == m_curItem) {
03956                 abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
03957                 if (abs_p.y < 0) abs_p.y = 0;
03958                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03959             }
03960             // newItem should never be NULL
03961         } break;
03962 
03963         // <UP>: go to the previous sibling or for the last of its children, to the parent
03964         case WXK_UP: {
03965             newItem = GetPrevSibling (m_curItem);
03966             if (newItem) {
03967 #if !wxCHECK_VERSION(2, 5, 0)
03968                 long cookie = 0;
03969 #else
03970                 wxTreeItemIdValue cookie = 0;
03971 #endif
03972                 while (IsExpanded (newItem) && HasChildren (newItem)) {
03973                     newItem = GetLastChild (newItem, cookie);
03974                 }
03975             }else {
03976                 newItem = GetItemParent (m_curItem);
03977                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03978                     newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
03979                 }
03980             }
03981         }break;
03982 
03983         // <LEFT>: if expanded collapse subtree, else go to the parent
03984         case WXK_LEFT: {
03985             if (IsExpanded (m_curItem)) {
03986                 Collapse (m_curItem);
03987             }else{
03988                 newItem = GetItemParent (m_curItem);
03989                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03990                     newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
03991                 }
03992             }
03993         }break;
03994 
03995         // <RIGHT>: if possible expand subtree, else go go to the first child
03996         case WXK_RIGHT: {
03997             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
03998                 Expand (m_curItem);
03999             }else{
04000                 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
04001 #if !wxCHECK_VERSION(2, 5, 0)
04002                     long cookie = 0;
04003 #else
04004                     wxTreeItemIdValue cookie = 0;
04005 #endif
04006                     newItem = GetFirstChild (m_curItem, cookie);
04007                 }
04008             }
04009         }break;
04010 
04011         // <DOWN>: if expanded go to the first child, else to the next sibling, ect
04012         case WXK_DOWN: {
04013             if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
04014 #if !wxCHECK_VERSION(2, 5, 0)
04015                 long cookie = 0;
04016 #else
04017                 wxTreeItemIdValue cookie = 0;
04018 #endif
04019                 newItem = GetFirstChild( m_curItem, cookie );
04020             }
04021             if (!newItem) {
04022                 wxTreeItemId parent = m_curItem;
04023                 do {
04024                     newItem = GetNextSibling (parent);
04025                     parent = GetItemParent (parent);
04026                 } while (!newItem && parent);
04027             }
04028         }break;
04029 
04030         // <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
04031         case WXK_PAGEDOWN: {
04032         int flags = 0;
04033         int col = 0;
04034         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
04035         // PAGE-UP: first go the the first visible row
04036             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
04037             newItem = GetLastVisible(false, true);
04038         // if we are already there then scroll down one page
04039             if (newItem == m_curItem) {
04040                 abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
04041 //                if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
04042                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
04043             }
04044         // if we reached the empty area below the rows, return last item instead
04045             if (! newItem) newItem = GetLastVisible(false, false);
04046         } break;
04047 
04048         // <END>: go to last item of the root
04049         case WXK_END: {
04050             newItem = GetLastVisible (false, false);
04051         }break;
04052 
04053         // any char: go to the next matching string
04054         default:
04055             wxChar key = event.GetUnicodeKey();
04056 #if wxCHECK_VERSION(3,0,0)
04057             if (key == WXK_NONE) key = (wxChar)event.GetKeyCode();
04058 #else
04059             if (key == 0) key = (wxChar)event.GetKeyCode();
04060 #endif
04061             if (key  >= 32) {
04062                 // prepare search parameters
04063                 int mode = wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE;
04064                 if (!m_findTimer->IsRunning()) m_findStr.Clear();
04065                 m_findStr.Append (key);
04066                 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
04067                 wxTreeItemId prev = (wxTreeItemId*)NULL;
04068                 // try if current item or one of its followers matches
04069                 if (m_curItem) {
04070                     prev = (wxTreeItemId*)m_curItem;
04071                     for (int col=0; col<=GetColumnCount() - 1; col++) {
04072                         if (MatchItemText(GetItemText(prev, col), m_findStr, mode)) {
04073                             newItem = prev;
04074                             break;
04075                         }
04076                     }
04077                     if (! newItem) {
04078                         newItem = FindItem (prev, -1, m_findStr, mode);
04079                     };
04080                 }
04081                 // current item or does not match: try to find next
04082                 // still not match: search from beginning (but only if there was a current item i.e.we did not start from root already)
04083                 if (! newItem) {
04084                     prev = (wxTreeItemId*)NULL;
04085                     newItem = FindItem (prev, -1, m_findStr, mode);
04086                 }
04087                 // no match at all: remove just typed char to allow try with another extension
04088                 if (! newItem) m_findStr.RemoveLast();
04089             }
04090             event.Skip();
04091 
04092     }
04093 
04094     // select and show the new item
04095     if (newItem) {
04096         if (!event.ControlDown()) {
04097             bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
04098                                       HasFlag(wxTR_MULTIPLE));
04099             SelectItem (newItem, m_shiftItem, unselect_others);
04100         }
04101         EnsureVisible (newItem);
04102         wxTreeListItem *oldItem = m_curItem;
04103         SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
04104         RefreshLine (oldItem);
04105     }
04106 
04107 }
04108 
04109 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
04110 
04111     int w, h;
04112     GetSize(&w, &h);
04113     flags=0;
04114     column = -1;
04115     if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
04116     if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
04117     if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
04118     if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
04119     if (flags) return wxTreeItemId();
04120 
04121     if (!m_rootItem) {
04122         flags = wxTREE_HITTEST_NOWHERE;
04123         column = -1;
04124         return wxTreeItemId();
04125     }
04126 
04127     wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
04128                                                this, flags, column, 0);
04129     if (!hit) {
04130         flags = wxTREE_HITTEST_NOWHERE;
04131         column = -1;
04132         return wxTreeItemId();
04133     }
04134     return hit;
04135 }
04136 
04137 // get the bounding rectangle of the item (or of its label only)
04138 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
04139                                             bool WXUNUSED(textOnly)) const {
04140     wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
04141 
04142     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
04143 
04144     int xUnit, yUnit;
04145     GetScrollPixelsPerUnit (&xUnit, &yUnit);
04146     int startX, startY;
04147     GetViewStart(& startX, & startY);
04148 
04149     rect.x = item->GetX() - startX * xUnit;
04150     rect.y = item->GetY() - startY * yUnit;
04151     rect.width = item->GetWidth();
04152     rect.height = GetLineHeight (item);
04153 
04154     return true;
04155 }
04156 
04157 /* **** */
04158 
04159 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
04160 
04161 // validate
04162     if (!item.IsOk()) return;
04163     if (!((column >= 0) && (column < GetColumnCount()))) return;
04164 
04165 // cancel any editing
04166     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
04167 
04168 // prepare edit (position)
04169     m_editItem = (wxTreeListItem*) item.m_pItem;
04170 
04171     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
04172     te.SetInt (column);
04173     SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
04174 
04175     // ensure that the position of the item it calculated in any case
04176     if (m_dirty) CalculatePositions();
04177 
04178     wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
04179 
04180     // position & size are rather unpredictable (tsssk, tssssk) so were
04181     //  set by trial & error (on Win 2003 pre-XP style)
04182     int x = 0;
04183     int w = +4;  // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
04184     int y = m_editItem->GetY() + 1;  // this is cell, not text
04185     int h = m_editItem->GetHeight() - 1;  // consequence from above
04186     long style = 0;
04187     if (column == GetMainColumn()) {
04188         x += m_editItem->GetTextX() - 2;  // wrong by 2, don't know why
04189         w += m_editItem->GetWidth();
04190     } else {
04191         for (int i = 0; i < column; ++i) {
04192             if ( header_win->IsColumnShown(i) ) {
04193                 x += header_win->GetColumnWidth (i); // start of column
04194             }
04195                 }
04196         w += header_win->GetColumnWidth (column);  // currently non-main column width not pre-computed
04197     }
04198     switch (header_win->GetColumnAlignment (column)) {
04199         case wxALIGN_LEFT:   {style = wxTE_LEFT;   x -= 1; break;}
04200         case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
04201         case wxALIGN_RIGHT:  {style = wxTE_RIGHT;  x += 0; break;}  // yes, strange but that's the way it is
04202     }
04203     // wxTextCtrl simple border style requires 2 extra pixels before and after
04204     //  (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
04205     y -= 2; x -= 2;
04206     w += 4; h += 4;
04207 
04208     wxClientDC dc (this);
04209     PrepareDC (dc);
04210     x = dc.LogicalToDeviceX (x);
04211     y = dc.LogicalToDeviceY (y);
04212 
04213 // now do edit (change state, show control)
04214     m_editCol = column;  // only used in OnRenameAccept()
04215     m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
04216                                                this, m_editItem->GetText (column),
04217                                                wxPoint (x, y), wxSize (w, h), style);
04218     m_editControl->SelectAll();
04219     m_editControl->SetFocus();
04220 }
04221 
04222 void wxTreeListMainWindow::OnRenameTimer() {
04223     EditLabel (m_curItem, GetCurrentColumn());
04224 }
04225 
04226 void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
04227 
04228     // TODO if the validator fails this causes a crash
04229     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
04230     le.SetLabel( m_editRes );
04231     le.SetEditCanceled(isCancelled);
04232     le.SetInt(m_editCol);
04233     SendEvent(0, m_editItem, &le); if (! isCancelled  && le.IsAllowed())
04234     {
04235         SetItemText (m_editItem, le.GetInt(), le.GetLabel());
04236     }
04237 }
04238 
04239 void wxTreeListMainWindow::EndEdit(bool isCancelled) {
04240     if (m_editControl) { m_editControl->EndEdit(true); }
04241 }
04242 
04243 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
04244 bool mayDrag = true;
04245 bool maySelect = true;  // may change selection
04246 bool mayClick = true;  // may process DOWN clicks to expand, send click events
04247 bool mayDoubleClick = true;  // implies mayClick
04248 bool bSkip = true;
04249 
04250     // send event to user code
04251     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
04252     if (!m_rootItem) return;
04253 
04254 
04255 // ---------- DETERMINE EVENT ----------
04256 /*
04257 wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
04258     event.LeftDown(), event.MiddleDown(), event.RightDown(),
04259     event.LeftUp(), event.MiddleUp(), event.RightUp(),
04260     event.LeftDClick(), event.Dragging());
04261 */
04262     wxPoint p = wxPoint (event.GetX(), event.GetY());
04263     int flags = 0;
04264     wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
04265                                                 this, flags, m_curColumn, 0);
04266     bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
04267     // we were dragging
04268     if (m_isDragging) {
04269         maySelect = mayDoubleClick = false;
04270     }
04271     // we are starting or continuing to drag
04272     if (event.Dragging()) {
04273         maySelect = mayDoubleClick = mayClick = false;
04274     }
04275     // crosshair area is special
04276     if (bCrosshair) {
04277         // left click does not select
04278         if (event.LeftDown()) maySelect = false;
04279         // double click is ignored
04280         mayDoubleClick = false;
04281     }
04282     // double click only if simple click
04283     if (mayDoubleClick) mayDoubleClick = mayClick;
04284     // selection conditions --remember also that selection exludes editing
04285     if (maySelect) maySelect = mayClick;  // yes, select/unselect requires a click
04286     if (maySelect) {
04287 
04288         // multiple selection mode complicates things, sometimes we
04289         //  select on button-up instead of down:
04290         if (HasFlag(wxTR_MULTIPLE)) {
04291 
04292             // CONTROL/SHIFT key used, don't care about anything else, will
04293             //  toggle on key down
04294             if (event.ControlDown() || event.ShiftDown()) {
04295                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04296                 m_lastOnSame = false;  // prevent editing when keys are used
04297 
04298             // already selected item: to allow drag or contextual menu for multiple
04299             //  items, we only select/unselect on click-up --and only on LEFT
04300             // click, right is reserved for contextual menu
04301             } else if ((item != NULL && item->IsSelected())) {
04302                 maySelect = maySelect && event.LeftUp();
04303 
04304             // non-selected items: select on click-down like simple select (so
04305             //  that a right-click contextual menu may be chained)
04306             } else {
04307                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04308             }
04309 
04310         // single-select is simply on left or right click-down
04311         } else {
04312             maySelect = maySelect && (event.LeftDown() || event.RightDown());
04313         }
04314     }
04315 
04316 
04317 // ----------  GENERAL ACTIONS  ----------
04318 
04319     // set focus if window clicked
04320     if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
04321 
04322     // tooltip change ?
04323     if (item != m_toolTipItem) {
04324 
04325         // not over an item, use global tip
04326         if (item == NULL) {
04327             m_toolTipItem = NULL;
04328             wxScrolledWindow::SetToolTip(m_toolTip);
04329 
04330         // over an item
04331         } else {
04332             const wxString *tip = item->GetToolTip();
04333 
04334             // is there an item-specific tip ?
04335             if (tip) {
04336                 m_toolTipItem = item;
04337                 wxScrolledWindow::SetToolTip(*tip);
04338 
04339             // no item tip, but we are in item-specific mode (SetItemToolTip()
04340             //  was called after SetToolTip() )
04341             } else if (m_isItemToolTip) {
04342                 m_toolTipItem = item;
04343                 wxScrolledWindow::SetToolTip(wxString());
04344 
04345             // no item tip, display global tip instead; item change ignored
04346             } else if (m_toolTipItem != NULL) {
04347                 m_toolTipItem = NULL;
04348                 wxScrolledWindow::SetToolTip(m_toolTip);
04349             }
04350         }
04351     }
04352 
04353 
04354 // ----------  HANDLE SIMPLE-CLICKS  (selection change, contextual menu) ----------
04355     if (mayClick) {
04356 
04357         // 2nd left-click on an item might trigger edit
04358         if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
04359 
04360         // left-click on haircross is expand (and no select)
04361         if (bCrosshair && event.LeftDown()) {
04362 
04363             bSkip = false;
04364 
04365             // note that we only toggle the item for a single click, double
04366             // click on the button doesn't do anything
04367             Toggle (item);
04368         }
04369 
04370         if (maySelect) {
04371             bSkip = false;
04372 
04373             // set / remember item at shift down before current item gets changed
04374             if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
04375                 if (!m_shiftItem) m_shiftItem = m_curItem;
04376             }else{
04377                 m_shiftItem = (wxTreeListItem*)NULL;
04378             }
04379 
04380             // how is selection altered
04381             // keep or discard already selected ?
04382             bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
04383                 event.ShiftDown()
04384              || event.ControlDown()
04385             ));
04386 
04387             // check is selection change is not vetoed
04388             if (SelectItem(item, m_shiftItem, unselect_others)) {
04389                 // make the new item the current item
04390                 EnsureVisible (item);
04391                 SetCurrentItem(item);
04392             }
04393         }
04394 
04395         // generate click & menu events
04396         if (event.MiddleDown()) {
04397             // our own event to set point
04398             wxTreeEvent nevent(0, 0);
04399             nevent.SetPoint(p);
04400             nevent.SetInt(m_curColumn);
04401             bSkip = false;
04402             SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item, &nevent);
04403         }
04404         if (event.RightDown()) {
04405             // our own event to set point
04406             wxTreeEvent nevent(0, 0);
04407             nevent.SetPoint(p);
04408             nevent.SetInt(m_curColumn);
04409             bSkip = false;
04410             SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item, &nevent);
04411         }
04412         if (event.RightUp()) {
04413             // our own event to set point
04414             wxTreeEvent nevent(0, 0);
04415             nevent.SetPoint(p);
04416             nevent.SetInt(m_curColumn);
04417             SendEvent(wxEVT_COMMAND_TREE_ITEM_MENU, item, &nevent);
04418         }
04419 
04420         // if 2nd left click finishes on same item, will edit it
04421         if (m_lastOnSame && event.LeftUp()) {
04422             if ((item == m_curItem) && (m_curColumn != -1) &&
04423                 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
04424                 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
04425             ){
04426                 m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
04427                 bSkip = false;
04428             }
04429             m_lastOnSame = false;
04430         }
04431     }
04432 
04433 
04434 // ----------  HANDLE DOUBLE-CLICKS  ----------
04435     if (mayDoubleClick && event.LeftDClick()) {
04436 
04437         bSkip = false;
04438 
04439         // double clicking should not start editing the item label
04440         m_editTimer->Stop();
04441         m_lastOnSame = false;
04442 
04443         // selection reset to that single item which was double-clicked
04444         if (SelectItem(item, (wxTreeItemId*)NULL, true)) {  // unselect others --return false if vetoed
04445 
04446             // selection change not vetoed, send activate event
04447             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
04448 
04449                 // if the user code didn't process the activate event,
04450                 // handle it ourselves by toggling the item when it is
04451                 // double clicked
04452                 if (item && item->HasPlus()) Toggle(item);
04453             }
04454         }
04455     }
04456 
04457 
04458 // ----------  HANDLE DRAGGING  ----------
04459 // NOTE: drag itself makes no change to selection
04460     if (mayDrag) {  // actually this is always true
04461 
04462         // CASE 1: we were dragging => continue, end, abort
04463         if (m_isDragging) {
04464 
04465             // CASE 1.1: click aborts drag:
04466             if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
04467 
04468                 bSkip = false;
04469 
04470                 // stop dragging
04471                 m_isDragStarted = m_isDragging = false;
04472                 if (HasCapture()) ReleaseMouse();
04473                 RefreshSelected();
04474 
04475             // CASE 1.2: still dragging
04476             } else if (event.Dragging()) {
04477 
04478                 ;; // nothing to do
04479 
04480             // CASE 1.3: dragging now ends normally
04481             } else {
04482 
04483                 bSkip = false;
04484 
04485                 // stop dragging
04486                 m_isDragStarted = m_isDragging = false;
04487                 if (HasCapture()) ReleaseMouse();
04488                 RefreshSelected();
04489 
04490                 // send drag end event
04491                 // our own event to set point
04492                 wxTreeEvent nevent(0, 0);
04493                 nevent.SetPoint(p);
04494                 nevent.SetInt(m_curColumn);
04495                 SendEvent(wxEVT_COMMAND_TREE_END_DRAG, item, &nevent);
04496             }
04497 
04498         // CASE 2: not were not dragging => continue, start
04499         } else if (event.Dragging()) {
04500 
04501             // We will really start dragging if we've moved beyond a few pixels
04502             if (m_isDragStarted) {
04503                 const int tolerance = 3;
04504                 int dx = abs(p.x - m_dragStartPos.x);
04505                 int dy = abs(p.y - m_dragStartPos.y);
04506                 if (dx <= tolerance && dy <= tolerance)
04507                     return;
04508             // determine drag start
04509             } else {
04510                 m_dragStartPos = p;
04511                 m_dragCol = GetCurrentColumn();
04512                 m_dragItem = item;
04513                 m_isDragStarted = true;
04514                 return;
04515             }
04516 
04517             bSkip = false;
04518 
04519             // we are now dragging
04520             m_isDragging = true;
04521             RefreshSelected();
04522             CaptureMouse(); // TODO: usefulness unclear
04523 
04524             wxTreeEvent nevent(0, 0);
04525             nevent.SetPoint(p);
04526             nevent.SetInt(m_dragCol);
04527             nevent.Veto();
04528             SendEvent(event.LeftIsDown()
04529                                   ? wxEVT_COMMAND_TREE_BEGIN_DRAG
04530                                   : wxEVT_COMMAND_TREE_BEGIN_RDRAG,
04531                       m_dragItem, &nevent);
04532         }
04533     }
04534 
04535 
04536     if (bSkip) event.Skip();
04537 }
04538 
04539 
04540 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
04541     /* after all changes have been done to the tree control,
04542      * we actually redraw the tree when everything is over */
04543 
04544     if (!m_dirty) return;
04545 
04546     m_dirty = false;
04547 
04548     CalculatePositions();
04549     Refresh();
04550     AdjustMyScrollbars();
04551 }
04552 
04553 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
04554 
04555     // send event to wxTreeListCtrl (for user code)
04556     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
04557 
04558     // TODO
04559 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__)
04560     wxScrolledWindow::OnScroll(event);
04561 #else
04562     HandleOnScroll( event );
04563 #endif
04564 
04565     if(event.GetOrientation() == wxHORIZONTAL) {
04566         m_owner->GetHeaderWindow()->Refresh();
04567         m_owner->GetHeaderWindow()->Update();
04568     }
04569 }
04570 
04571 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
04572     wxCoord text_w = 0;
04573     wxCoord text_h = 0;
04574 
04575     dc.SetFont (GetItemFont (item));
04576     dc.GetTextExtent (item->GetText(m_main_column).size() > 0
04577             ? item->GetText (m_main_column)
04578             : _T(" "),  // blank to avoid zero height and no highlight width
04579         &text_w, &text_h);
04580     // restore normal font
04581     dc.SetFont (m_normalFont);
04582 
04583     int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
04584     if (max_h < 30) { // add 10% space if greater than 30 pixels
04585         max_h += 2; // minimal 2 pixel space
04586     }else{
04587         max_h += max_h / 10; // otherwise 10% space
04588     }
04589 
04590     item->SetHeight (max_h);
04591     if (max_h > m_lineHeight) m_lineHeight = max_h;
04592     item->SetWidth(m_imgWidth + text_w+2);
04593 }
04594 
04595 // -----------------------------------------------------------------------------
04596 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
04597                                            int level, int &y, int x_colstart) {
04598 
04599     // calculate position of vertical lines
04600     int x = x_colstart + MARGIN; // start of column
04601     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
04602     if (HasButtons()) {
04603         x += (m_btnWidth-m_btnWidth2); // half button space
04604     }else{
04605         x += (m_indent-m_indent/2);
04606     }
04607     if (HasFlag(wxTR_HIDE_ROOT)) {
04608         x += m_indent * (level-1); // indent but not level 1
04609     }else{
04610         x += m_indent * level; // indent according to level
04611     }
04612 
04613     // a hidden root is not evaluated, but its children are always
04614     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
04615 
04616     CalculateSize( item, dc );
04617 
04618     // set its position
04619     item->SetX (x);
04620     item->SetY (y);
04621     y += GetLineHeight(item);
04622 
04623     // we don't need to calculate collapsed branches
04624     if ( !item->IsExpanded() ) return;
04625 
04626 Recurse:
04627     wxArrayTreeListItems& children = item->GetChildren();
04628     long n, count = (long)children.Count();
04629     ++level;
04630     for (n = 0; n < count; ++n) {
04631         CalculateLevel( children[n], dc, level, y, x_colstart );  // recurse
04632     }
04633 }
04634 
04635 void wxTreeListMainWindow::CalculatePositions() {
04636     if ( !m_rootItem ) return;
04637 
04638     wxClientDC dc(this);
04639     PrepareDC( dc );
04640 
04641     dc.SetFont( m_normalFont );
04642 
04643     dc.SetPen( m_dottedPen );
04644     //if(GetImageList() == NULL)
04645     // m_lineHeight = (int)(dc.GetCharHeight() + 4);
04646 
04647     int y = 2;
04648     int x_colstart = 0;
04649     for (int i = 0; i < (int)GetMainColumn(); ++i) {
04650         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
04651         x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
04652     }
04653     CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
04654 }
04655 
04656 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
04657     if (m_dirty) return;
04658 
04659     wxClientDC dc(this);
04660     PrepareDC(dc);
04661 
04662     int cw = 0;
04663     int ch = 0;
04664     GetVirtualSize( &cw, &ch );
04665 
04666     wxRect rect;
04667     rect.x = dc.LogicalToDeviceX( 0 );
04668     rect.width = cw;
04669     rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
04670     rect.height = ch;
04671 
04672     Refresh (true, &rect );
04673     AdjustMyScrollbars();
04674 }
04675 
04676 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
04677     if (m_dirty) return;
04678 
04679     wxClientDC dc(this);
04680     PrepareDC( dc );
04681 
04682     int cw = 0;
04683     int ch = 0;
04684     GetVirtualSize( &cw, &ch );
04685 
04686     wxRect rect;
04687     rect.x = dc.LogicalToDeviceX( 0 );
04688     rect.y = dc.LogicalToDeviceY( item->GetY() );
04689     rect.width = cw;
04690     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
04691 
04692     Refresh (true, &rect);
04693 }
04694 
04695 void wxTreeListMainWindow::RefreshSelected() {
04696     // TODO: this is awfully inefficient, we should keep the list of all
04697     //       selected items internally, should be much faster
04698     if (m_rootItem) {
04699         RefreshSelectedUnder (m_rootItem);
04700     }
04701 }
04702 
04703 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
04704     if (item->IsSelected()) {
04705         RefreshLine (item);
04706     }
04707 
04708     const wxArrayTreeListItems& children = item->GetChildren();
04709     long count = (long)children.GetCount();
04710     for (long n = 0; n < count; n++ ) {
04711         RefreshSelectedUnder (children[n]);
04712     }
04713 }
04714 
04715 // ----------------------------------------------------------------------------
04716 // changing colours: we need to refresh the tree control
04717 // ----------------------------------------------------------------------------
04718 
04719 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
04720     if (!wxWindow::SetBackgroundColour(colour)) return false;
04721 
04722     Refresh();
04723     return true;
04724 }
04725 
04726 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
04727     if (!wxWindow::SetForegroundColour(colour)) return false;
04728 
04729     Refresh();
04730     return true;
04731 }
04732 
04733 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
04734     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
04735 
04736     if (this->IsFrozen())
04737     {
04738         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04739         item->SetText(column, text);
04740         m_dirty = true;
04741     }
04742     else
04743     {
04744         wxClientDC dc(this);
04745         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04746         item->SetText(column, text);
04747         CalculateSize(item, dc);
04748         RefreshLine(item);
04749     };
04750 }
04751 
04752 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
04753     wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
04754 
04755     if( IsVirtual() )   return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
04756     else                return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
04757 }
04758 
04759 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
04760    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
04761    return m_owner->OnGetItemText(item, column);
04762 }
04763 
04764 void wxTreeListMainWindow::SetFocus() {
04765     wxWindow::SetFocus();
04766 }
04767 
04768 
04769 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
04770     if (!item) return 0;
04771 
04772     // determine item width
04773     int w = 0, h = 0;
04774     wxFont font = GetItemFont (item);
04775     GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
04776     w += 2*MARGIN;
04777 
04778     // calculate width
04779     int width = w + 2*MARGIN;
04780     if (column == GetMainColumn()) {
04781         width += MARGIN;
04782         if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
04783         if (HasButtons()) width += m_btnWidth + LINEATROOT;
04784         if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
04785 
04786         // count indent level
04787         int level = 0;
04788         wxTreeListItem *parent = item->GetItemParent();
04789         wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
04790         while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
04791             level++;
04792             parent = parent->GetItemParent();
04793         }
04794         if (level) width += level * GetIndent();
04795     }
04796 
04797     return width;
04798 }
04799 
04800 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
04801     int maxWidth, h;
04802     GetClientSize (&maxWidth, &h);
04803     int width = 0;
04804 
04805     // get root if on item
04806     if (!parent.IsOk()) parent = GetRootItem();
04807 
04808     // add root width
04809     if (!HasFlag(wxTR_HIDE_ROOT)) {
04810         int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
04811         if (width < w) width = w;
04812         if (width > maxWidth) return maxWidth;
04813     }
04814 
04815     wxTreeItemIdValue cookie = 0;
04816     wxTreeItemId item = GetFirstChild (parent, cookie);
04817     while (item.IsOk()) {
04818         int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
04819         if (width < w) width = w;
04820         if (width > maxWidth) return maxWidth;
04821 
04822         // check the children of this item
04823         if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
04824             int w = GetBestColumnWidth (column, item);
04825             if (width < w) width = w;
04826             if (width > maxWidth) return maxWidth;
04827         }
04828 
04829         // next sibling
04830         item = GetNextChild (parent, cookie);
04831     }
04832 
04833     return width;
04834 }
04835 
04836 
04837 bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
04838 wxTreeEvent nevent (event_type, 0);
04839 
04840     if (event == NULL) {
04841         event = &nevent;
04842         event->SetInt (m_curColumn); // the mouse colum
04843     } else if (event_type) {
04844         event->SetEventType(event_type);
04845     }
04846 
04847     event->SetEventObject (m_owner);
04848     event->SetId(m_owner->GetId());
04849     if (item) {
04850 #if !wxCHECK_VERSION(2, 5, 0)
04851         event->SetItem ((long)item);
04852 #else
04853         event->SetItem (item);
04854 #endif
04855     }
04856 
04857     return m_owner->GetEventHandler()->ProcessEvent (*event);
04858 }
04859 
04860 
04861 //-----------------------------------------------------------------------------
04862 //  wxTreeListCtrl
04863 //-----------------------------------------------------------------------------
04864 
04865 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
04866 
04867 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
04868     EVT_SIZE(wxTreeListCtrl::OnSize)
04869 END_EVENT_TABLE();
04870 
04871 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
04872                             const wxPoint& pos,
04873                             const wxSize& size,
04874                             long style, const wxValidator &validator,
04875                             const wxString& name)
04876 {
04877     long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE |
04878                                 wxBORDER_RAISED | wxBORDER_STATIC);
04879     main_style |= wxWANTS_CHARS ;
04880     long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
04881 
04882     if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
04883        return false;
04884     }
04885     m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
04886                                            main_style, validator);
04887     m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
04888                                                wxPoint(0, 0), wxDefaultSize,
04889                                                wxTAB_TRAVERSAL);
04890     CalculateAndSetHeaderHeight();
04891     return true;
04892 }
04893 
04894 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
04895 {
04896     if (m_header_win) {
04897 
04898         // we use 'g' to get the descent, too
04899         int h;
04900 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
04901 #ifdef __WXMSW__
04902         h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
04903 #else
04904         h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
04905 #endif
04906 #else
04907         int w, d;
04908         m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
04909         h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
04910 #endif
04911 
04912         // only update if changed
04913         if (h != m_headerHeight) {
04914             m_headerHeight = h;
04915             DoHeaderLayout();
04916         }
04917     }
04918 }
04919 
04920 void wxTreeListCtrl::DoHeaderLayout()
04921 {
04922     int w, h;
04923     GetClientSize(&w, &h);
04924     if (m_header_win) {
04925         m_header_win->SetSize (0, 0, w, m_headerHeight);
04926         m_header_win->Refresh();
04927     }
04928     if (m_main_win) {
04929         m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
04930     }
04931 }
04932 
04933 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
04934 {
04935     DoHeaderLayout();
04936 }
04937 
04938 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
04939 
04940 unsigned int wxTreeListCtrl::GetIndent() const
04941 { return m_main_win->GetIndent(); }
04942 
04943 void wxTreeListCtrl::SetIndent(unsigned int indent)
04944 { m_main_win->SetIndent(indent); }
04945 
04946 unsigned int wxTreeListCtrl::GetLineSpacing() const
04947 { return m_main_win->GetLineSpacing(); }
04948 
04949 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
04950 { m_main_win->SetLineSpacing(spacing); }
04951 
04952 wxImageList* wxTreeListCtrl::GetImageList() const
04953 { return m_main_win->GetImageList(); }
04954 
04955 wxImageList* wxTreeListCtrl::GetStateImageList() const
04956 { return m_main_win->GetStateImageList(); }
04957 
04958 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
04959 { return m_main_win->GetButtonsImageList(); }
04960 
04961 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
04962 { m_main_win->SetImageList(imageList); }
04963 
04964 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
04965 { m_main_win->SetStateImageList(imageList); }
04966 
04967 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
04968 { m_main_win->SetButtonsImageList(imageList); }
04969 
04970 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
04971 { m_main_win->AssignImageList(imageList); }
04972 
04973 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
04974 { m_main_win->AssignStateImageList(imageList); }
04975 
04976 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
04977 { m_main_win->AssignButtonsImageList(imageList); }
04978 
04979 
04980 
04981 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
04982 { return m_main_win->GetItemText (item, column); }
04983 
04984 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
04985 { return m_main_win->GetItemImage(item, which); }
04986 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
04987 { return m_main_win->GetItemImage(item, column); }
04988 
04989 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
04990 { return m_main_win->GetItemData(item); }
04991 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
04992 { return m_main_win->GetItemData(item, column); }
04993 
04994 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
04995 { return m_main_win->GetItemBold(item); }
04996 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
04997 { return m_main_win->GetItemBold(item, column); }
04998 
04999 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
05000 { return m_main_win->GetItemTextColour(item); }
05001 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
05002 { return m_main_win->GetItemTextColour(item, column); }
05003 
05004 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
05005 { return m_main_win->GetItemBackgroundColour(item); }
05006 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
05007 { return m_main_win->GetItemBackgroundColour(item, column); }
05008 
05009 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
05010 { return m_main_win->GetItemFont(item); }
05011 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
05012 { return m_main_win->GetItemFont(item, column); }
05013 
05014 
05015 
05016 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
05017 { m_main_win->SetItemHasChildren(item, has); }
05018 
05019 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
05020 { m_main_win->SetItemText (item, column, text); }
05021 
05022 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
05023 { m_main_win->SetItemImage(item, image, which); }
05024 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
05025 { m_main_win->SetItemImage(item, column, image); }
05026 
05027 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data)
05028 { m_main_win->SetItemData(item, data); }
05029 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
05030 { m_main_win->SetItemData(item, column, data); }
05031 
05032 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold)
05033 { m_main_win->SetItemBold(item, bold); }
05034 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
05035 { m_main_win->SetItemBold(item, column, bold); }
05036 
05037 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour)
05038 { m_main_win->SetItemTextColour(item, colour); }
05039 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
05040 { m_main_win->SetItemTextColour(item, column, colour); }
05041 
05042 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour)
05043 { m_main_win->SetItemBackgroundColour(item, colour); }
05044 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
05045 { m_main_win->SetItemBackgroundColour(item, column, colour); }
05046 
05047 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font)
05048 { m_main_win->SetItemFont(item, font); }
05049 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
05050 { m_main_win->SetItemFont(item, column, font); }
05051 
05052 
05053 
05054 bool wxTreeListCtrl::SetFont(const wxFont& font)
05055 {
05056     if (m_header_win) {
05057         m_header_win->SetFont(font);
05058         CalculateAndSetHeaderHeight();
05059         m_header_win->Refresh();
05060     }
05061     if (m_main_win) {
05062         return m_main_win->SetFont(font);
05063     }else{
05064         return false;
05065     }
05066 }
05067 
05068 void wxTreeListCtrl::SetWindowStyleFlag(long style)
05069 {
05070     if (m_main_win)
05071     {
05072         long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE | wxBORDER_RAISED | wxBORDER_STATIC);
05073         main_style |= wxWANTS_CHARS;
05074         m_main_win->SetWindowStyle(main_style);
05075     };
05076     m_windowStyle = style & ~(wxVSCROLL | wxHSCROLL);
05077     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
05078 }
05079 
05080 long wxTreeListCtrl::GetWindowStyleFlag() const
05081 {
05082     long style = m_windowStyle;
05083     if(m_main_win)
05084         style |= m_main_win->GetWindowStyle();
05085     return style;
05086 }
05087 
05088 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05089 { return m_main_win->IsVisible(item, fullRow, within); }
05090 
05091 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
05092 { return m_main_win->HasChildren(item); }
05093 
05094 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
05095 { return m_main_win->IsExpanded(item); }
05096 
05097 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
05098 { return m_main_win->IsSelected(item); }
05099 
05100 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
05101 { return m_main_win->GetChildrenCount(item, rec); }
05102 
05103 wxTreeItemId wxTreeListCtrl::GetRootItem() const
05104 { return m_main_win->GetRootItem(); }
05105 
05106 wxTreeItemId wxTreeListCtrl::GetSelection() const
05107 { return m_main_win->GetSelection(); }
05108 
05109 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
05110 { return m_main_win->GetSelections(arr); }
05111 
05112 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
05113 { return m_main_win->GetItemParent(item); }
05114 
05115 #if !wxCHECK_VERSION(2, 5, 0)
05116 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
05117                                             long& cookie) const
05118 #else
05119 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
05120                                             wxTreeItemIdValue& cookie) const
05121 #endif
05122 { return m_main_win->GetFirstChild(item, cookie); }
05123 
05124 #if !wxCHECK_VERSION(2, 5, 0)
05125 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
05126                                            long& cookie) const
05127 #else
05128 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
05129                                            wxTreeItemIdValue& cookie) const
05130 #endif
05131 { return m_main_win->GetNextChild(item, cookie); }
05132 
05133 #if !wxCHECK_VERSION(2, 5, 0)
05134 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
05135                                            long& cookie) const
05136 #else
05137 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
05138                                            wxTreeItemIdValue& cookie) const
05139 #endif
05140 { return m_main_win->GetPrevChild(item, cookie); }
05141 
05142 #if !wxCHECK_VERSION(2, 5, 0)
05143 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
05144                                            long& cookie) const
05145 #else
05146 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
05147                                            wxTreeItemIdValue& cookie) const
05148 #endif
05149 { return m_main_win->GetLastChild(item, cookie); }
05150 
05151 
05152 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
05153 { return m_main_win->GetNextSibling(item); }
05154 
05155 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
05156 { return m_main_win->GetPrevSibling(item); }
05157 
05158 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
05159 { return m_main_win->GetNext(item, true); }
05160 
05161 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
05162 { return m_main_win->GetPrev(item, true); }
05163 
05164 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
05165 { return m_main_win->GetFirstExpandedItem(); }
05166 
05167 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
05168 { return m_main_win->GetNextExpanded(item); }
05169 
05170 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
05171 { return m_main_win->GetPrevExpanded(item); }
05172 
05173 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
05174 { return GetFirstVisible(fullRow); }
05175 wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
05176 { return m_main_win->GetFirstVisible(fullRow, within); }
05177 
05178 wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
05179 { return m_main_win->GetLastVisible(fullRow, within); }
05180 
05181 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05182 { return m_main_win->GetNextVisible(item, fullRow, within); }
05183 
05184 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05185 { return m_main_win->GetPrevVisible(item, fullRow, within); }
05186 
05187 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
05188                                       int selectedImage, wxTreeItemData* data)
05189 { return m_main_win->AddRoot (text, image, selectedImage, data); }
05190 
05191 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
05192                                          const wxString& text, int image,
05193                                          int selectedImage,
05194                                          wxTreeItemData* data)
05195 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
05196 
05197 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
05198                                         const wxTreeItemId& previous,
05199                                         const wxString& text, int image,
05200                                         int selectedImage,
05201                                         wxTreeItemData* data)
05202 {
05203     return m_main_win->InsertItem(parent, previous, text, image,
05204                                   selectedImage, data);
05205 }
05206 
05207 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
05208                                         size_t index,
05209                                         const wxString& text, int image,
05210                                         int selectedImage,
05211                                         wxTreeItemData* data)
05212 {
05213     return m_main_win->InsertItem(parent, index, text, image,
05214                                   selectedImage, data);
05215 }
05216 
05217 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
05218                                         const wxString& text, int image,
05219                                         int selectedImage,
05220                                         wxTreeItemData* data)
05221 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
05222 
05223 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
05224 { m_main_win->Delete(item); }
05225 
05226 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
05227 { m_main_win->DeleteChildren(item); }
05228 
05229 void wxTreeListCtrl::DeleteRoot()
05230 { m_main_win->DeleteRoot(); }
05231 
05232 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
05233 { m_main_win->Expand(item); }
05234 
05235 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
05236 { m_main_win->ExpandAll(item); }
05237 
05238 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
05239 { m_main_win->Collapse(item); }
05240 
05241 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
05242 { m_main_win->CollapseAndReset(item); }
05243 
05244 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
05245 { m_main_win->Toggle(item); }
05246 
05247 void wxTreeListCtrl::Unselect()
05248 { m_main_win->Unselect(); }
05249 
05250 void wxTreeListCtrl::UnselectAll()
05251 { m_main_win->UnselectAll(); }
05252 
05253 bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
05254                                 bool unselect_others)
05255 { return m_main_win->SelectItem (item, last, unselect_others); }
05256 
05257 void wxTreeListCtrl::SelectAll()
05258 { m_main_win->SelectAll(); }
05259 
05260 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
05261 { m_main_win->EnsureVisible(item); }
05262 
05263 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
05264 { m_main_win->ScrollTo(item); }
05265 
05266 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
05267 {
05268     wxPoint p = pos;
05269     return m_main_win->HitTest (p, flags, column);
05270 }
05271 
05272 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
05273                                      bool textOnly) const
05274 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
05275 
05276 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
05277     { m_main_win->EditLabel (item, column); }
05278 void wxTreeListCtrl::EndEdit(bool isCancelled)
05279     { m_main_win->EndEdit(isCancelled); }
05280 
05281 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
05282 {
05283     // do the comparison here and not in m_main_win in order to allow
05284     // override in child class
05285     return wxStrcmp(GetItemText(item1), GetItemText(item2));
05286 }
05287 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
05288 {
05289     // do the comparison here and not in m_main_win in order to allow
05290     // override in child class
05291     return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
05292 }
05293 
05294 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
05295 { m_main_win->SortChildren(item, column, reverseOrder); }
05296 
05297 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
05298 { return m_main_win->FindItem (item, column, str, mode); }
05299 
05300 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
05301 { m_main_win->SetDragItem (item); }
05302 
05303 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
05304 {
05305     if (!m_main_win) return false;
05306     return m_main_win->SetBackgroundColour(colour);
05307 }
05308 
05309 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
05310 {
05311     if (!m_main_win) return false;
05312     return m_main_win->SetForegroundColour(colour);
05313 }
05314 
05315 int wxTreeListCtrl::GetColumnCount() const
05316 { return m_main_win->GetColumnCount(); }
05317 
05318 void wxTreeListCtrl::SetColumnWidth(int column, int width)
05319 {
05320     m_header_win->SetColumnWidth (column, width);
05321     m_header_win->Refresh();
05322 }
05323 
05324 int wxTreeListCtrl::GetColumnWidth(int column) const
05325 { return m_header_win->GetColumnWidth(column); }
05326 
05327 void wxTreeListCtrl::SetMainColumn(int column)
05328 { m_main_win->SetMainColumn(column); }
05329 
05330 int wxTreeListCtrl::GetMainColumn() const
05331 { return m_main_win->GetMainColumn(); }
05332 
05333 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
05334 {
05335     m_header_win->SetColumnText (column, text);
05336     m_header_win->Refresh();
05337 }
05338 
05339 wxString wxTreeListCtrl::GetColumnText(int column) const
05340 { return m_header_win->GetColumnText(column); }
05341 
05342 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
05343 {
05344     m_header_win->AddColumn (colInfo);
05345     DoHeaderLayout();
05346 }
05347 
05348 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
05349 {
05350     m_header_win->InsertColumn (before, colInfo);
05351     m_header_win->Refresh();
05352 }
05353 
05354 void wxTreeListCtrl::RemoveColumn(int column)
05355 {
05356     m_header_win->RemoveColumn (column);
05357     m_header_win->Refresh();
05358 }
05359 
05360 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
05361 {
05362     m_header_win->SetColumn (column, colInfo);
05363     m_header_win->Refresh();
05364 }
05365 
05366 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
05367 { return m_header_win->GetColumn(column); }
05368 
05369 wxTreeListColumnInfo wxTreeListCtrl::GetColumn(int column)
05370 { return m_header_win->GetColumn(column); }
05371 
05372 void wxTreeListCtrl::SetColumnImage(int column, int image)
05373 {
05374     m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
05375     m_header_win->Refresh();
05376 }
05377 
05378 int wxTreeListCtrl::GetColumnImage(int column) const
05379 {
05380     return m_header_win->GetColumn(column).GetImage();
05381 }
05382 
05383 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
05384 {
05385     m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
05386 }
05387 
05388 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
05389 {
05390     wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
05391     m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
05392     m_header_win->Refresh();
05393 }
05394 
05395 bool wxTreeListCtrl::IsColumnEditable(int column) const
05396 {
05397     return m_header_win->GetColumn(column).IsEditable();
05398 }
05399 
05400 bool wxTreeListCtrl::IsColumnShown(int column) const
05401 {
05402     return m_header_win->GetColumn(column).IsShown();
05403 }
05404 
05405 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
05406 {
05407     m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
05408     m_header_win->Refresh();
05409 }
05410 
05411 int wxTreeListCtrl::GetColumnAlignment(int column) const
05412 {
05413     return m_header_win->GetColumn(column).GetAlignment();
05414 }
05415 
05416 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
05417 {
05418     m_main_win->Refresh (erase, rect);
05419     m_header_win->Refresh (erase, rect);
05420 }
05421 
05422 void wxTreeListCtrl::SetFocus()
05423 { m_main_win->SetFocus(); }
05424 
05425 wxSize wxTreeListCtrl::DoGetBestSize() const
05426 {
05427     wxSize bestSizeHeader = m_header_win->GetBestSize();
05428     wxSize bestSizeMain = m_main_win->GetBestSize();
05429     return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
05430 }
05431 
05432 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
05433 {
05434     return wxEmptyString;
05435 }
05436 
05437 void wxTreeListCtrl::SetToolTip(const wxString& tip) {
05438     m_header_win->SetToolTip(tip);
05439     m_main_win->SetToolTip(tip);
05440 }
05441 void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
05442     m_header_win->SetToolTip(tip);
05443     m_main_win->SetToolTip(tip);
05444 }
05445 
05446 void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
05447     m_main_win->SetItemToolTip(item, tip);
05448 }
05449 
05450 void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
05451     m_main_win->SetCurrentItem(itemId);
05452 }
05453 
05454 void wxTreeListCtrl::SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item) {
05455     m_main_win->SetItemParent(parent, item);
05456 }
05457 
05458 //-----------------------------------------------------------------------------
05459 // wxTreeListCtrlXmlHandler - XRC support for wxTreeListCtrl
05460 //-----------------------------------------------------------------------------
05461 
05462 #if wxUSE_XRC
05463 
05464 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrlXmlHandler, wxXmlResourceHandler)
05465 
05466 wxTreeListCtrlXmlHandler::wxTreeListCtrlXmlHandler() : wxXmlResourceHandler() {
05467 
05468 #define wxTR_NO_BUTTONS              0x0000     // for convenience
05469 #define wxTR_HAS_BUTTONS             0x0001     // draw collapsed/expanded btns
05470 #define wxTR_NO_LINES                0x0004     // don't draw lines at all
05471 #define wxTR_LINES_AT_ROOT           0x0008     // connect top-level nodes
05472 #define wxTR_TWIST_BUTTONS           0x0010     // still used by wxTreeListCtrl
05473 
05474 #define wxTR_SINGLE                  0x0000     // for convenience
05475 #define wxTR_MULTIPLE                0x0020     // can select multiple items
05476 #define wxTR_EXTENDED                0x0040     // TODO: allow extended selection
05477 #define wxTR_HAS_VARIABLE_ROW_HEIGHT 0x0080     // what it says
05478 
05479 #define wxTR_EDIT_LABELS             0x0200     // can edit item labels
05480 #define wxTR_ROW_LINES               0x0400     // put border around items
05481 #define wxTR_HIDE_ROOT               0x0800     // don't display root node
05482 
05483 #define wxTR_FULL_ROW_HIGHLIGHT      0x2000     // highlight full horz space
05484 
05485 #ifdef __WXGTK20__
05486 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_NO_LINES)
05487 #else
05488 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT)
05489 #endif
05490 
05491 // wxTreeCtrl styles, taken from treebase.h
05492         XRC_ADD_STYLE(wxTR_NO_BUTTONS);
05493         XRC_ADD_STYLE(wxTR_HAS_BUTTONS);
05494         XRC_ADD_STYLE(wxTR_NO_LINES);
05495         XRC_ADD_STYLE(wxTR_LINES_AT_ROOT);
05496         XRC_ADD_STYLE(wxTR_TWIST_BUTTONS);
05497 
05498         XRC_ADD_STYLE(wxTR_SINGLE);
05499         XRC_ADD_STYLE(wxTR_MULTIPLE);
05500 #if WXWIN_COMPATIBILITY_2_8
05501     // according to wxWidgets release notes, wxTR_EXTENDED is deprecated
05502     XRC_ADD_STYLE(wxTR_EXTENDED);
05503 #endif // WXWIN_COMPATIBILITY_2_8
05504     XRC_ADD_STYLE(wxTR_HAS_VARIABLE_ROW_HEIGHT);
05505 
05506     XRC_ADD_STYLE(wxTR_EDIT_LABELS);
05507     XRC_ADD_STYLE(wxTR_ROW_LINES);
05508     XRC_ADD_STYLE(wxTR_HIDE_ROOT);
05509 
05510     XRC_ADD_STYLE(wxTR_FULL_ROW_HIGHLIGHT);
05511 
05512     XRC_ADD_STYLE(wxTR_DEFAULT_STYLE);
05513 
05514 // wxTreeListCtrl-specific styles
05515     XRC_ADD_STYLE(wxTR_COLUMN_LINES);
05516     XRC_ADD_STYLE(wxTR_VIRTUAL);
05517 
05518 // standard wxWidgets styles
05519         AddWindowStyles();
05520 }
05521 
05522 wxObject *wxTreeListCtrlXmlHandler::DoCreateResource() {
05523         XRC_MAKE_INSTANCE(tlc, wxTreeListCtrl);
05524         tlc->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName());
05525     SetupWindow(tlc);
05526         return tlc;
05527 }
05528 
05529 bool wxTreeListCtrlXmlHandler::CanHandle(wxXmlNode * node) {
05530         return IsOfClass(node, wxT("TreeListCtrl"));
05531 }
05532 
05533 #endif  // wxUSE_XRC
05534 
05535 #if wxCHECK_VERSION(2,9,0)
05536 } // namespace wxcode
05537 #endif

Generated on 30 Aug 2015 for Hugintrunk by  doxygen 1.4.7