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 occurred
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     wxTreeItemData* data = GetItemData(item);
02835     if (data != NULL)
02836     {
02837         delete data;
02838     };
02839     SendEvent(wxEVT_COMMAND_TREE_DELETE_ITEM, item);
02840     delete item;
02841 }
02842 
02843 
02844 // ----------------------------------------------------------------------------
02845 
02846 void wxTreeListMainWindow::SetItemParent(const wxTreeItemId& parentId, const wxTreeItemId& itemId) {
02847 wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02848 wxTreeListItem *parent_new = (wxTreeListItem*) parentId.m_pItem;
02849 wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::SetItemParent") );
02850 wxCHECK_RET (parent_new, _T("invalid parent in wxTreeListMainWindow::SetItemParent") );
02851 wxCHECK_RET (item != m_rootItem, _T("invalid root as item in wxTreeListMainWindow::SetItemParent!") );
02852 wxTreeListItem *parent_old = item->GetItemParent();
02853 
02854     m_dirty = true; // do this first so stuff below doesn't cause flicker
02855 
02856     parent_old->GetChildren().Remove (item);
02857     parent_new->Insert(item, parent_new->GetChildren().Count());
02858     item->SetItemParent(parent_new);
02859     // new parent was a leaf, show its new child
02860     if (parent_new->GetChildren().Count() == 1) parent_new->Expand();
02861 }
02862 
02863 
02864 // ----------------------------------------------------------------------------
02865 
02866 void wxTreeListMainWindow::SetCurrentItem(const wxTreeItemId& itemId) {
02867   SetCurrentItem((wxTreeListItem *)(itemId ? itemId.m_pItem : NULL));
02868 }
02869 void wxTreeListMainWindow::SetCurrentItem(wxTreeListItem *item) {
02870 wxTreeListItem *old_item;
02871 
02872     old_item = m_curItem; m_curItem = item;
02873 
02874     // change of item, redraw previous
02875     if (old_item != NULL && old_item != item) {
02876         RefreshLine(old_item);
02877     }
02878 
02879 }
02880 
02881 // ----------------------------------------------------------------------------
02882 
02883 void wxTreeListMainWindow::Expand (const wxTreeItemId& itemId) {
02884     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02885     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Expand") );
02886 
02887     if (!item->HasPlus() || item->IsExpanded()) return;
02888 
02889     // send event to user code
02890     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, 0);
02891     event.SetInt(m_curColumn);
02892     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // expand canceled
02893 
02894     item->Expand();
02895     m_dirty = true;
02896 
02897     // send event to user code
02898     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_EXPANDED);
02899     SendEvent(0, NULL, &event);
02900 }
02901 
02902 void wxTreeListMainWindow::ExpandAll (const wxTreeItemId& itemId) {
02903     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
02904 
02905     Expand (itemId);
02906     if (!IsExpanded (itemId)) return;
02907 #if !wxCHECK_VERSION(2, 5, 0)
02908     long cookie;
02909 #else
02910     wxTreeItemIdValue cookie;
02911 #endif
02912     wxTreeItemId child = GetFirstChild (itemId, cookie);
02913     while (child.IsOk()) {
02914         ExpandAll (child);
02915         child = GetNextChild (itemId, cookie);
02916     }
02917 }
02918 
02919 void wxTreeListMainWindow::Collapse (const wxTreeItemId& itemId) {
02920     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
02921     wxCHECK_RET (item, _T("invalid item in wxTreeListMainWindow::Collapse") );
02922 
02923     if (!item->HasPlus() || !item->IsExpanded()) return;
02924 
02925     // send event to user code
02926     wxTreeEvent event (wxEVT_COMMAND_TREE_ITEM_COLLAPSING, 0 );
02927     event.SetInt(m_curColumn);
02928     if (SendEvent(0, item, &event) && !event.IsAllowed()) return; // collapse canceled
02929 
02930     item->Collapse();
02931     m_dirty = true;
02932 
02933     // send event to user code
02934     event.SetEventType (wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
02935     SendEvent(0, NULL, &event);
02936 }
02937 
02938 void wxTreeListMainWindow::CollapseAndReset (const wxTreeItemId& item) {
02939     wxCHECK_RET (item.IsOk(), _T("invalid tree item"));
02940 
02941     Collapse (item);
02942     DeleteChildren (item);
02943 }
02944 
02945 void wxTreeListMainWindow::Toggle (const wxTreeItemId& itemId) {
02946     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
02947 
02948     if (IsExpanded (itemId)) {
02949         Collapse (itemId);
02950     }else{
02951         Expand (itemId);
02952     }
02953 }
02954 
02955 void wxTreeListMainWindow::Unselect() {
02956     if (m_selectItem) {
02957         m_selectItem->SetHilight (false);
02958         RefreshLine (m_selectItem);
02959         m_selectItem = (wxTreeListItem*)NULL;
02960     }
02961 }
02962 
02963 void wxTreeListMainWindow::UnselectAllChildren (wxTreeListItem *item) {
02964     wxCHECK_RET (item, _T("invalid tree item"));
02965 
02966     if (item->IsSelected()) {
02967         item->SetHilight (false);
02968         RefreshLine (item);
02969         if (item == m_selectItem) m_selectItem = (wxTreeListItem*)NULL;
02970         if (item != m_curItem) m_lastOnSame = false;  // selection change, so reset edit marker
02971     }
02972     if (item->HasChildren()) {
02973         wxArrayTreeListItems& children = item->GetChildren();
02974         size_t count = children.Count();
02975         for (size_t n = 0; n < count; ++n) {
02976             UnselectAllChildren (children[n]);
02977         }
02978     }
02979 }
02980 
02981 void wxTreeListMainWindow::UnselectAll() {
02982     UnselectAllChildren ((wxTreeListItem*)GetRootItem().m_pItem);
02983 }
02984 
02985 // Recursive function !
02986 // To stop we must have crt_item<last_item
02987 // Algorithm :
02988 // Tag all next children, when no more children,
02989 // Move to parent (not to tag)
02990 // Keep going... if we found last_item, we stop.
02991 bool wxTreeListMainWindow::TagNextChildren (wxTreeListItem *crt_item,
02992                                             wxTreeListItem *last_item) {
02993     wxTreeListItem *parent = crt_item->GetItemParent();
02994 
02995     if (!parent) {// This is root item
02996         return TagAllChildrenUntilLast (crt_item, last_item);
02997     }
02998 
02999     wxArrayTreeListItems& children = parent->GetChildren();
03000     int index = children.Index(crt_item);
03001     wxASSERT (index != wxNOT_FOUND); // I'm not a child of my parent?
03002 
03003     if ((parent->HasChildren() && parent->IsExpanded()) ||
03004         ((parent == (wxTreeListItem*)GetRootItem().m_pItem) && HasFlag(wxTR_HIDE_ROOT))) {
03005         size_t count = children.Count();
03006         for (size_t n = (index+1); n < count; ++n) {
03007             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
03008         }
03009     }
03010 
03011     return TagNextChildren (parent, last_item);
03012 }
03013 
03014 bool wxTreeListMainWindow::TagAllChildrenUntilLast (wxTreeListItem *crt_item,
03015                                                     wxTreeListItem *last_item) {
03016     crt_item->SetHilight (true);
03017     RefreshLine(crt_item);
03018 
03019     if (crt_item==last_item) return true;
03020 
03021     if (crt_item->HasChildren() && crt_item->IsExpanded()) {
03022         wxArrayTreeListItems& children = crt_item->GetChildren();
03023         size_t count = children.Count();
03024         for (size_t n = 0; n < count; ++n) {
03025             if (TagAllChildrenUntilLast (children[n], last_item)) return true;
03026         }
03027     }
03028 
03029     return false;
03030 }
03031 
03032 bool wxTreeListMainWindow::SelectItem (const wxTreeItemId& itemId,
03033                                        const wxTreeItemId& lastId,
03034                                        bool unselect_others) {
03035 
03036     wxTreeListItem *item = itemId.IsOk() ? (wxTreeListItem*) itemId.m_pItem : NULL;
03037 
03038     // send selecting event to the user code
03039     wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
03040     event.SetInt(m_curColumn);
03041 #if !wxCHECK_VERSION(2, 5, 0)
03042     event.SetOldItem ((long)m_curItem);
03043 #else
03044     event.SetOldItem (m_curItem);
03045 #endif
03046     if (SendEvent(0, item, &event) && !event.IsAllowed()) return false;  // veto on selection change
03047 
03048     // unselect all if unselect other items
03049     bool bUnselectedAll = false; // see that UnselectAll is done only once
03050     if (unselect_others) {
03051         if (HasFlag(wxTR_MULTIPLE)) {
03052             UnselectAll(); bUnselectedAll = true;
03053         }else{
03054             Unselect(); // to speed up thing
03055         }
03056     }
03057 
03058     // select item range
03059     if (lastId.IsOk() && itemId.IsOk() && (itemId != lastId)) {
03060 
03061         if (! bUnselectedAll) UnselectAll();
03062         wxTreeListItem *last = (wxTreeListItem*) lastId.m_pItem;
03063 
03064         // ensure that the position of the item it calculated in any case
03065         if (m_dirty) CalculatePositions();
03066 
03067         // select item range according Y-position
03068         if (last->GetY() < item->GetY()) {
03069             if (!TagAllChildrenUntilLast (last, item)) {
03070                 TagNextChildren (last, item);
03071             }
03072         }else{
03073             if (!TagAllChildrenUntilLast (item, last)) {
03074                 TagNextChildren (item, last);
03075             }
03076         }
03077 
03078     // or select single item
03079     }else if (itemId.IsOk()) {
03080 
03081         // select item according its old selection
03082         item->SetHilight (!item->IsSelected());
03083         RefreshLine (item);
03084         if (unselect_others) {
03085             m_selectItem = (item->IsSelected())? item: (wxTreeListItem*)NULL;
03086         }
03087 
03088     // or select nothing
03089     } else {
03090         if (! bUnselectedAll) UnselectAll();
03091     }
03092 
03093     // send event to user code
03094     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
03095     SendEvent(0, NULL, &event);
03096 
03097     return true;
03098 }
03099 
03100 void wxTreeListMainWindow::SelectAll() {
03101     wxTreeItemId root = GetRootItem();
03102     wxCHECK_RET (HasFlag(wxTR_MULTIPLE), _T("invalid tree style"));
03103     wxCHECK_RET (root.IsOk(), _T("no tree"));
03104 
03105     // send event to user code
03106     wxTreeEvent event (wxEVT_COMMAND_TREE_SEL_CHANGING, 0);
03107 #if !wxCHECK_VERSION(2, 5, 0)
03108     event.SetOldItem ((long)m_curItem);
03109 #else
03110     event.SetOldItem (m_curItem);
03111 #endif
03112     event.SetInt (-1); // no colum clicked
03113     if (SendEvent(0, m_rootItem, &event) && !event.IsAllowed()) return;  // selection change vetoed
03114 
03115 #if !wxCHECK_VERSION(2, 5, 0)
03116     long cookie = 0;
03117 #else
03118     wxTreeItemIdValue cookie = 0;
03119 #endif
03120     wxTreeListItem *first = (wxTreeListItem *)GetFirstChild (root, cookie).m_pItem;
03121     wxTreeListItem *last = (wxTreeListItem *)GetLastChild (root, cookie).m_pItem;
03122     if (!TagAllChildrenUntilLast (first, last)) {
03123         TagNextChildren (first, last);
03124     }
03125 
03126     // send event to user code
03127     event.SetEventType (wxEVT_COMMAND_TREE_SEL_CHANGED);
03128     SendEvent(0, NULL, &event);
03129 }
03130 
03131 void wxTreeListMainWindow::FillArray (wxTreeListItem *item,
03132                                       wxArrayTreeItemIds &array) const {
03133     if (item->IsSelected()) array.Add (wxTreeItemId(item));
03134 
03135     if (item->HasChildren()) {
03136         wxArrayTreeListItems& children = item->GetChildren();
03137         size_t count = children.GetCount();
03138         for (size_t n = 0; n < count; ++n) FillArray (children[n], array);
03139     }
03140 }
03141 
03142 size_t wxTreeListMainWindow::GetSelections (wxArrayTreeItemIds &array) const {
03143     array.Empty();
03144     wxTreeItemId idRoot = GetRootItem();
03145     if (idRoot.IsOk()) FillArray ((wxTreeListItem*) idRoot.m_pItem, array);
03146     return array.Count();
03147 }
03148 
03149 void wxTreeListMainWindow::EnsureVisible (const wxTreeItemId& item) {
03150     if (!item.IsOk()) return; // do nothing if no item
03151 
03152     // first expand all parent branches
03153     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
03154     wxTreeListItem *parent = gitem->GetItemParent();
03155     while (parent) {
03156         Expand (parent);
03157         parent = parent->GetItemParent();
03158     }
03159 
03160     ScrollTo (item);
03161     RefreshLine (gitem);
03162 }
03163 
03164 void wxTreeListMainWindow::ScrollTo (const wxTreeItemId &item) {
03165     if (!item.IsOk()) return; // do nothing if no item
03166 
03167     // ensure that the position of the item it calculated in any case
03168     if (m_dirty) CalculatePositions();
03169 
03170     wxTreeListItem *gitem = (wxTreeListItem*) item.m_pItem;
03171 
03172     // now scroll to the item
03173     int item_y = gitem->GetY();
03174 
03175     int xUnit, yUnit;
03176     GetScrollPixelsPerUnit (&xUnit, &yUnit);
03177     int start_x = 0;
03178     int start_y = 0;
03179     GetViewStart (&start_x, &start_y);
03180     start_y *= yUnit;
03181 
03182     int client_h = 0;
03183     int client_w = 0;
03184     GetClientSize (&client_w, &client_h);
03185 
03186     int x = 0;
03187     int y = 0;
03188     m_rootItem->GetSize (x, y, this);
03189     x = m_owner->GetHeaderWindow()->GetWidth();
03190     y += yUnit + 2; // one more scrollbar unit + 2 pixels
03191     int x_pos = GetScrollPos( wxHORIZONTAL );
03192 
03193     if (item_y < start_y+3) {
03194         // going down, item should appear at top
03195         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? item_y/yUnit : 0);
03196     }else if (item_y+GetLineHeight(gitem) > start_y+client_h) {
03197         // going up, item should appear at bottom
03198         item_y += yUnit + 2;
03199         SetScrollbars (xUnit, yUnit, xUnit ? x/xUnit : 0, yUnit ? y/yUnit : 0, x_pos, yUnit ? (item_y+GetLineHeight(gitem)-client_h)/yUnit : 0 );
03200     }
03201 }
03202 
03203 // TODO: tree sorting functions are not reentrant and not MT-safe!
03204 static wxTreeListMainWindow *s_treeBeingSorted = NULL;
03205 
03206 static int LINKAGEMODE tree_ctrl_compare_func(wxTreeListItem **item1, wxTreeListItem **item2)
03207 {
03208     wxCHECK_MSG (s_treeBeingSorted, 0, _T("bug in wxTreeListMainWindow::SortChildren()") );
03209     return s_treeBeingSorted->OnCompareItems(*item1, *item2);
03210 }
03211 
03212 int wxTreeListMainWindow::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
03213 {
03214     return (m_sortColumn == -1
03215         ? m_owner->OnCompareItems (item1, item2)
03216         : (m_ReverseSortOrder
03217             ? m_owner->OnCompareItems (item2, item1, m_sortColumn)
03218             : m_owner->OnCompareItems (item1, item2, m_sortColumn)
03219         )
03220     );
03221 }
03222 
03223 void wxTreeListMainWindow::SortChildren (const wxTreeItemId& itemId, int column, bool reverseOrder) {
03224     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
03225 
03226     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
03227 
03228     wxCHECK_RET (!s_treeBeingSorted,
03229                  _T("wxTreeListMainWindow::SortChildren is not reentrant") );
03230 
03231     wxArrayTreeListItems& children = item->GetChildren();
03232     if ( children.Count() > 1 ) {
03233         m_dirty = true;
03234         s_treeBeingSorted = this;
03235         m_sortColumn = column;  // -1 indicates legacy mode
03236         m_ReverseSortOrder = reverseOrder;
03237         children.Sort(tree_ctrl_compare_func);
03238         s_treeBeingSorted = NULL;
03239     }
03240 }
03241 
03242 bool wxTreeListMainWindow::MatchItemText(const wxString &itemText, const wxString &pattern, int mode) {
03243 wxString searchText;
03244 
03245    if (mode & wxTL_MODE_FIND_PARTIAL) {
03246        searchText = itemText.Mid (0, pattern.Length());
03247    }else{
03248        searchText = itemText;
03249    }
03250    if (mode & wxTL_MODE_FIND_NOCASE) {
03251        if (searchText.CmpNoCase (pattern) == 0) return true;
03252    }else{
03253        if (searchText.Cmp (pattern) == 0) return true;
03254    }
03255 
03256    return false;
03257 }
03258 
03259 
03260 wxTreeItemId wxTreeListMainWindow::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode) {
03261 #if !wxCHECK_VERSION(2, 5, 0)
03262     long cookie = 0;
03263 #else
03264     wxTreeItemIdValue cookie = 0;
03265 #endif
03266     wxTreeItemId next = item;
03267 
03268     // start checking the next items
03269     wxString itemText;
03270     int col, col_start, col_end;
03271     if (column >= 0) { col_start = col_end = column; }
03272     else { col_start = 0; col_end = GetColumnCount() - 1; }
03273 
03274     // navigate tree
03275     while (true) {
03276         // go to next item
03277         if (next.IsOk()) {
03278             if (mode & wxTL_MODE_NAV_LEVEL) {
03279                 next = GetNextSibling (next);
03280             }else if (mode & wxTL_MODE_NAV_VISIBLE) {
03281                 next = GetNextVisible (next, false, true);
03282             }else if (mode & wxTL_MODE_NAV_EXPANDED) {
03283                 next = GetNextExpanded (next);
03284             }else{ // (mode & wxTL_MODE_NAV_FULLTREE) default
03285                 next = GetNext (next, true);
03286             }
03287         // not a valid item, start at the top of the tree
03288         } else {
03289             next = GetRootItem();
03290             if (next.IsOk() && HasFlag(wxTR_HIDE_ROOT)) {
03291                 next = GetFirstChild (GetRootItem(), cookie);
03292             }
03293         }
03294         // end of tree (or back to beginning) ?
03295         if (! next.IsOk() || next == item) return (wxTreeItemId*)NULL;
03296         // check for a match
03297         for (col=col_start; col<=col_end; col++) {
03298             if (MatchItemText(GetItemText (next, col),str, mode)) return next;
03299         }
03300     }
03301     // should never get here
03302     return (wxTreeItemId*)NULL;
03303 }
03304 
03305 void wxTreeListMainWindow::SetDragItem (const wxTreeItemId& item) {
03306     wxTreeListItem *prevItem = m_dragItem;
03307     m_dragItem = (wxTreeListItem*) item.m_pItem;
03308     if (prevItem) RefreshLine (prevItem);
03309     if (m_dragItem) RefreshLine (m_dragItem);
03310 }
03311 
03312 void wxTreeListMainWindow::CalculateLineHeight() {
03313     wxClientDC dc (this);
03314     dc.SetFont (m_normalFont);
03315     m_lineHeight = (int)(dc.GetCharHeight() + m_linespacing);
03316 
03317     if (m_imageListNormal) {
03318         // Calculate a m_lineHeight value from the normal Image sizes.
03319         // May be toggle off. Then wxTreeListMainWindow will spread when
03320         // necessary (which might look ugly).
03321         int n = m_imageListNormal->GetImageCount();
03322         for (int i = 0; i < n ; i++) {
03323             int width = 0, height = 0;
03324             m_imageListNormal->GetSize(i, width, height);
03325             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
03326         }
03327     }
03328 
03329     if (m_imageListButtons) {
03330         // Calculate a m_lineHeight value from the Button image sizes.
03331         // May be toggle off. Then wxTreeListMainWindow will spread when
03332         // necessary (which might look ugly).
03333         int n = m_imageListButtons->GetImageCount();
03334         for (int i = 0; i < n ; i++) {
03335             int width = 0, height = 0;
03336             m_imageListButtons->GetSize(i, width, height);
03337             if (height > m_lineHeight) m_lineHeight = height + m_linespacing;
03338         }
03339     }
03340 
03341     if (m_lineHeight < 30) { // add 10% space if greater than 30 pixels
03342         m_lineHeight += 2; // minimal 2 pixel space
03343     }else{
03344         m_lineHeight += m_lineHeight / 10; // otherwise 10% space
03345     }
03346 }
03347 
03348 void wxTreeListMainWindow::SetImageList (wxImageList *imageList) {
03349     if (m_ownsImageListNormal) delete m_imageListNormal;
03350     m_imageListNormal = imageList;
03351     m_ownsImageListNormal = false;
03352     m_dirty = true;
03353     CalculateLineHeight();
03354 }
03355 
03356 void wxTreeListMainWindow::SetStateImageList (wxImageList *imageList) {
03357     if (m_ownsImageListState) delete m_imageListState;
03358     m_imageListState = imageList;
03359     m_ownsImageListState = false;
03360 }
03361 
03362 void wxTreeListMainWindow::SetButtonsImageList (wxImageList *imageList) {
03363     if (m_ownsImageListButtons) delete m_imageListButtons;
03364     m_imageListButtons = imageList;
03365     m_ownsImageListButtons = false;
03366     m_dirty = true;
03367     CalculateLineHeight();
03368 }
03369 
03370 void wxTreeListMainWindow::AssignImageList (wxImageList *imageList) {
03371     SetImageList(imageList);
03372     m_ownsImageListNormal = true;
03373 }
03374 
03375 void wxTreeListMainWindow::AssignStateImageList (wxImageList *imageList) {
03376     SetStateImageList(imageList);
03377     m_ownsImageListState = true;
03378 }
03379 
03380 void wxTreeListMainWindow::AssignButtonsImageList (wxImageList *imageList) {
03381     SetButtonsImageList(imageList);
03382     m_ownsImageListButtons = true;
03383 }
03384 
03385 // ----------------------------------------------------------------------------
03386 // helpers
03387 // ----------------------------------------------------------------------------
03388 
03389 void wxTreeListMainWindow::AdjustMyScrollbars() {
03390     if (m_rootItem) {
03391         int xUnit, yUnit;
03392         GetScrollPixelsPerUnit (&xUnit, &yUnit);
03393         if (xUnit == 0) xUnit = GetCharWidth();
03394         if (yUnit == 0) yUnit = m_lineHeight;
03395         int x = 0, y = 0;
03396         m_rootItem->GetSize (x, y, this);
03397         y += yUnit + 2; // one more scrollbar unit + 2 pixels
03398         int x_pos = GetScrollPos (wxHORIZONTAL);
03399         int y_pos = GetScrollPos (wxVERTICAL);
03400         x = m_owner->GetHeaderWindow()->GetWidth() + 2;
03401         if (x < GetClientSize().GetWidth()) x_pos = 0;
03402         SetScrollbars (xUnit, yUnit, x/xUnit, y/yUnit, x_pos, y_pos);
03403     }else{
03404         SetScrollbars (0, 0, 0, 0);
03405     }
03406 }
03407 
03408 int wxTreeListMainWindow::GetLineHeight (wxTreeListItem *item) const {
03409     if (GetWindowStyleFlag() & wxTR_HAS_VARIABLE_ROW_HEIGHT) {
03410         return item->GetHeight();
03411     }else{
03412         return m_lineHeight;
03413     }
03414 }
03415 
03416 void wxTreeListMainWindow::PaintItem (wxTreeListItem *item, wxDC& dc) {
03417 
03418 // read attributes constant for all item cells
03419     wxColour colText = GetItemTextColour(item);
03420     wxColour colBg = GetItemBackgroundColour(item);
03421 #if !wxCHECK_VERSION(2, 5, 0)
03422     wxColour colTextHilight = wxSystemSettings::GetSystemColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
03423 #else
03424     wxColour colTextHilight = wxSystemSettings::GetColour (wxSYS_COLOUR_HIGHLIGHTTEXT);
03425 #endif
03426     int total_w = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetMainWindow()->GetClientSize().GetWidth());
03427     int total_h = GetLineHeight(item);
03428     int off_h = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
03429     int off_w = HasFlag(wxTR_COLUMN_LINES) ? 1 : 0;
03430     wxDCClipper clipper (dc, 0, item->GetY(), total_w, total_h); // only within line
03431     // compute text height based on main col
03432     int text_h = 0;
03433     dc.GetTextExtent( item->GetText(GetMainColumn()).size() > 0
03434             ? item->GetText(GetMainColumn())
03435             : _T("M"),  // dummy text to avoid zero height and no highlight width
03436         NULL, &text_h );
03437 
03438 // determine background and show it
03439 // in wxTR_FULL_ROW_HIGHLIGHT mode, some drawing can be done already now
03440 #if wxCHECK_VERSION(3, 0, 0)
03441     dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03442 #else
03443     dc.SetBrush (wxBrush ( colBg, wxSOLID));
03444 #endif
03445     dc.SetPen (*wxTRANSPARENT_PEN);
03446     if (HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
03447         if (item->IsSelected()) {
03448             if (! m_isDragging && m_hasFocus) {
03449                 dc.SetBrush (*m_hilightBrush);
03450 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03451                 dc.SetPen (*wxBLACK_PEN);
03452 #endif // !__WXMAC__
03453             }else{
03454                 dc.SetBrush (*m_hilightUnfocusedBrush);
03455 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03456                 dc.SetPen (*wxTRANSPARENT_PEN);
03457 #endif // !__WXMAC__
03458             }
03459             dc.SetTextForeground (colTextHilight);
03460         }else {
03461             dc.SetTextForeground (GetItemTextColour(item));
03462             if (item == m_curItem) {
03463                 dc.SetPen (m_hasFocus? *wxBLACK_PEN: *wxTRANSPARENT_PEN);
03464             }
03465         }
03466         dc.DrawRectangle (0, item->GetY() + off_h, total_w, total_h - off_h);
03467     }
03468 
03469 // iterate through all cells
03470     int text_extraH = (total_h > text_h) ? (total_h - text_h)/2 : 0;
03471     int img_extraH = (total_h > m_imgHeight)? (total_h-m_imgHeight)/2: 0;
03472     int x_colstart = 0;
03473     for (int i = 0; i < GetColumnCount(); ++i ) {
03474         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
03475         int col_w = m_owner->GetHeaderWindow()->GetColumnWidth(i);
03476         if (col_w <= 0) continue;  // workaround for probable GTK2 bug [wxCode-Bugs-#3061215]
03477         wxDCClipper clipper (dc, x_colstart, item->GetY(), col_w, total_h); // only within column
03478 
03479         // read variable attributes
03480         dc.SetFont (GetItemFont (item, i));
03481         colText = GetItemTextColour(item, i);
03482         colBg = GetItemBackgroundColour(item, i);
03483 
03484         //
03485         int x = 0;
03486         int image = NO_IMAGE;
03487         int image_w = 0;
03488         if(i == GetMainColumn()) {
03489             x = item->GetX() + MARGIN;
03490             if (HasButtons()) {
03491                 x += (m_btnWidth-m_btnWidth2) + LINEATROOT;
03492             }else{
03493                 x -= m_indent/2;
03494             }
03495             if (m_imageListNormal) image = item->GetCurrentImage();
03496         }else{
03497             x = x_colstart + MARGIN;
03498             image = item->GetImage(i);
03499         }
03500         if (image != NO_IMAGE) image_w = m_imgWidth + MARGIN;
03501 
03502         // honor text alignment
03503         int w = 0, text_w = 0;
03504         wxString text = item->GetText(i);
03505         dc.GetTextExtent (text, &text_w, NULL);
03506         switch ( m_owner->GetHeaderWindow()->GetColumn(i).GetAlignment() ) {
03507         case wxALIGN_LEFT:
03508             // nothing to do, already left aligned
03509             break;
03510         case wxALIGN_RIGHT:
03511             w = col_w - (image_w + text_w + off_w + MARGIN);
03512             x += (w > 0)? w: 0;
03513             break;
03514         case wxALIGN_CENTER:
03515             w = (col_w - (image_w + text_w + off_w + MARGIN))/2;
03516             x += (w > 0)? w: 0;
03517             break;
03518         }
03519         int text_x = x + image_w;
03520         if (i == GetMainColumn()) item->SetTextX (text_x);
03521 
03522         // draw background (in non wxTR_FULL_ROW_HIGHLIGHT mode)
03523         // cell-specific settings are used --excepted for selection:
03524         if ( ! HasFlag (wxTR_FULL_ROW_HIGHLIGHT)) {
03525             // cursor: indicate current cell
03526             bool drawCursor = false;
03527 #ifndef __WXMAC__ // don't draw rect outline if we already have the background color
03528             drawCursor = (item == m_curItem && i == m_curColumn && !m_isDragging && m_hasFocus);
03529 #endif // !__WXMAC__
03530             // selection: main col only, overrides colors + separate draw
03531             if (item->IsSelected() && i == GetMainColumn()) {
03532                 // draw normal background
03533                 dc.SetPen (*wxTRANSPARENT_PEN);
03534 #if wxCHECK_VERSION(3, 0, 0)
03535                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03536 #else
03537                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
03538 #endif
03539                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
03540                 // draw selection & optionally cursor
03541                 dc.SetPen (drawCursor ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
03542                 dc.SetBrush(!m_isDragging && m_hasFocus ? *m_hilightBrush : *m_hilightUnfocusedBrush);
03543                 dc.SetTextForeground (colTextHilight);
03544                 dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
03545             // normal FG / BG from attributes
03546             } else {
03547                 // draw normal background & optionally cursor
03548                 dc.SetPen (drawCursor && i != GetMainColumn() ? *wxBLACK_PEN : *wxTRANSPARENT_PEN);
03549 #if wxCHECK_VERSION(3, 0, 0)
03550                 dc.SetBrush (wxBrush ( colBg, wxBRUSHSTYLE_SOLID));
03551 #else
03552                 dc.SetBrush (wxBrush ( colBg, wxSOLID));
03553 #endif
03554                 dc.SetTextForeground (colText);
03555                 dc.DrawRectangle (x_colstart, item->GetY() + off_h, col_w, total_h - off_h);
03556                 // on main col draw a separate cursor
03557                 if (drawCursor && i == GetMainColumn()) {
03558                     dc.SetPen (*wxBLACK_PEN);
03559                     dc.SetBackgroundMode (wxTRANSPARENT);
03560                     dc.DrawRectangle (text_x, item->GetY() + off_h, text_w, total_h - off_h);
03561                 }
03562             }
03563         }
03564 
03565         // draw vertical column lines
03566         if (HasFlag(wxTR_COLUMN_LINES)) { // vertical lines between columns
03567 #if !wxCHECK_VERSION(2, 5, 0)
03568             wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03569 #else
03570 #if wxCHECK_VERSION(3, 0, 0)
03571             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxPENSTYLE_SOLID);
03572 #else
03573             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03574 #endif
03575 #endif
03576             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
03577             dc.DrawLine (x_colstart+col_w-1, item->GetY(), x_colstart+col_w-1, item->GetY()+total_h);
03578         }
03579 
03580         dc.SetBackgroundMode (wxTRANSPARENT);
03581 
03582         // draw image
03583         if (image != NO_IMAGE && m_imageListNormal && image < m_imageListNormal->GetImageCount()) {
03584             int y = item->GetY() + img_extraH;
03585             m_imageListNormal->Draw (image, dc, x, y, wxIMAGELIST_DRAW_TRANSPARENT );
03586         }
03587 
03588         // draw text
03589         int text_y = item->GetY() + text_extraH;
03590         dc.DrawText (text, (wxCoord)text_x, (wxCoord)text_y);
03591 
03592         x_colstart += col_w;
03593     }
03594 
03595     // restore normal font
03596     dc.SetFont( m_normalFont );
03597 }
03598 
03599 // Now y stands for the top of the item, whereas it used to stand for middle !
03600 void wxTreeListMainWindow::PaintLevel (wxTreeListItem *item, wxDC &dc,
03601                                        int level, int &y, int x_maincol) {
03602 
03603     // Handle hide root (only level 0)
03604     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) {
03605         wxArrayTreeListItems& children = item->GetChildren();
03606         for (size_t n = 0; n < children.Count(); n++) {
03607             PaintLevel (children[n], dc, 1, y, x_maincol);
03608         }
03609         // end after expanding root
03610         return;
03611     }
03612 
03613     // calculate position of vertical lines
03614     int x = x_maincol + MARGIN; // start of column
03615     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
03616     if (HasButtons()) {
03617         x += (m_btnWidth-m_btnWidth2); // half button space
03618     }else{
03619         x += (m_indent-m_indent/2);
03620     }
03621     if (HasFlag(wxTR_HIDE_ROOT)) {
03622         x += m_indent * (level-1); // indent but not level 1
03623     }else{
03624         x += m_indent * level; // indent according to level
03625     }
03626 
03627     // set position of vertical line
03628     item->SetX (x);
03629     item->SetY (y);
03630 
03631     int h = GetLineHeight (item);
03632     int y_top = y;
03633     int y_mid = y_top + (h/2);
03634     y += h;
03635 
03636     int exposed_x = dc.LogicalToDeviceX(0);
03637     int exposed_y = dc.LogicalToDeviceY(y_top);
03638 
03639     if (IsExposed(exposed_x, exposed_y, 10000, h)) { // 10000 = very much
03640 
03641         if (HasFlag(wxTR_ROW_LINES)) { // horizontal lines between rows
03642             //dc.DestroyClippingRegion();
03643             int total_width = std::max(m_owner->GetHeaderWindow()->GetWidth(), m_owner->GetClientSize().GetWidth());
03644             // if the background colour is white, choose a
03645             // contrasting color for the lines
03646 #if !wxCHECK_VERSION(2, 5, 0)
03647             wxPen pen (wxSystemSettings::GetSystemColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03648 #else
03649 #if wxCHECK_VERSION(3, 0, 0)
03650             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxPENSTYLE_SOLID);
03651 #else
03652             wxPen pen (wxSystemSettings::GetColour (wxSYS_COLOUR_3DLIGHT ), 1, wxSOLID);
03653 #endif
03654 #endif
03655             dc.SetPen ((GetBackgroundColour() == *wxWHITE)? pen: *wxWHITE_PEN);
03656             dc.DrawLine (0, y_top, total_width, y_top);
03657             dc.DrawLine (0, y_top+h, total_width, y_top+h);
03658         }
03659 
03660         // draw item
03661         PaintItem (item, dc);
03662 
03663         // restore DC objects
03664         dc.SetBrush(*wxWHITE_BRUSH);
03665         dc.SetPen(m_dottedPen);
03666 
03667         // clip to the column width
03668         int clip_width = m_owner->GetHeaderWindow()->
03669                             GetColumn(m_main_column).GetWidth();
03670         wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
03671 
03672         if (!HasFlag(wxTR_NO_LINES)) { // connection lines
03673 
03674             // draw the horizontal line here
03675             dc.SetPen(m_dottedPen);
03676             int x2 = x - m_indent;
03677             if (x2 < (x_maincol + MARGIN)) x2 = x_maincol + MARGIN;
03678             int x3 = x + (m_btnWidth-m_btnWidth2);
03679             if (HasButtons()) {
03680                 if (item->HasPlus()) {
03681                     dc.DrawLine (x2, y_mid, x - m_btnWidth2, y_mid);
03682                     dc.DrawLine (x3, y_mid, x3 + LINEATROOT, y_mid);
03683                 }else{
03684                     dc.DrawLine (x2, y_mid, x3 + LINEATROOT, y_mid);
03685                 }
03686             }else{
03687                 dc.DrawLine (x2, y_mid, x - m_indent/2, y_mid);
03688             }
03689         }
03690 
03691         if (item->HasPlus() && HasButtons()) { // should the item show a button?
03692 
03693             if (m_imageListButtons) {
03694 
03695                 // draw the image button here
03696                 int image = wxTreeItemIcon_Normal;
03697                 if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
03698                 if (item->IsSelected()) image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
03699                 int xx = x - m_btnWidth2 + MARGIN;
03700                 int yy = y_mid - m_btnHeight2;
03701                 dc.SetClippingRegion(xx, yy, m_btnWidth, m_btnHeight);
03702                 m_imageListButtons->Draw (image, dc, xx, yy, wxIMAGELIST_DRAW_TRANSPARENT);
03703                 dc.DestroyClippingRegion();
03704 
03705             }else if (HasFlag (wxTR_TWIST_BUTTONS)) {
03706 
03707                 // draw the twisty button here
03708                 dc.SetPen(*wxBLACK_PEN);
03709                 dc.SetBrush(*m_hilightBrush);
03710                 wxPoint button[3];
03711                 if (item->IsExpanded()) {
03712                     button[0].x = x - (m_btnWidth2+1);
03713                     button[0].y = y_mid - (m_btnHeight/3);
03714                     button[1].x = x + (m_btnWidth2+1);
03715                     button[1].y = button[0].y;
03716                     button[2].x = x;
03717                     button[2].y = button[0].y + (m_btnHeight2+1);
03718                 }else{
03719                     button[0].x = x - (m_btnWidth/3);
03720                     button[0].y = y_mid - (m_btnHeight2+1);
03721                     button[1].x = button[0].x;
03722                     button[1].y = y_mid + (m_btnHeight2+1);
03723                     button[2].x = button[0].x + (m_btnWidth2+1);
03724                     button[2].y = y_mid;
03725                 }
03726                 dc.DrawPolygon(3, button);
03727 
03728             }else{ // if (HasFlag(wxTR_HAS_BUTTONS))
03729 
03730                 // draw the plus sign here
03731 #if !wxCHECK_VERSION(2, 7, 0)
03732                 dc.SetPen(*wxGREY_PEN);
03733                 dc.SetBrush(*wxWHITE_BRUSH);
03734                 dc.DrawRectangle (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
03735                 dc.SetPen(*wxBLACK_PEN);
03736                 dc.DrawLine (x-(m_btnWidth2-2), y_mid, x+(m_btnWidth2-1), y_mid);
03737                 if (!item->IsExpanded()) { // change "-" to "+"
03738                     dc.DrawLine (x, y_mid-(m_btnHeight2-2), x, y_mid+(m_btnHeight2-1));
03739                 }
03740 #else
03741                 wxRect rect (x-m_btnWidth2, y_mid-m_btnHeight2, m_btnWidth, m_btnHeight);
03742                 int flag = item->IsExpanded()? wxCONTROL_EXPANDED: 0;
03743                 wxRendererNative::GetDefault().DrawTreeItemButton (this, dc, rect, flag);
03744 #endif
03745 
03746             }
03747 
03748         }
03749 
03750     }
03751 
03752     // restore DC objects
03753     dc.SetBrush(*wxWHITE_BRUSH);
03754     dc.SetPen(m_dottedPen);
03755     dc.SetTextForeground(*wxBLACK);
03756 
03757     if (item->IsExpanded())
03758     {
03759         wxArrayTreeListItems& children = item->GetChildren();
03760 
03761         // clip to the column width
03762         int clip_width = m_owner->GetHeaderWindow()->
03763                             GetColumn(m_main_column).GetWidth();
03764 
03765         // process lower levels
03766         int oldY;
03767         if (m_imgWidth > 0) {
03768             oldY = y_mid + m_imgHeight2;
03769         }else{
03770             oldY = y_mid + h/2;
03771         }
03772         int y2;
03773         for (size_t n = 0; n < children.Count(); ++n) {
03774 
03775             y2 = y + h/2;
03776             PaintLevel (children[n], dc, level+1, y, x_maincol);
03777 
03778             // draw vertical line
03779             wxDCClipper clipper(dc, x_maincol, y_top, clip_width, 10000);
03780             if (!HasFlag (wxTR_NO_LINES)) {
03781                 x = item->GetX();
03782                 dc.DrawLine (x, oldY, x, y2);
03783                 oldY = y2;
03784             }
03785         }
03786     }
03787 }
03788 
03789 
03790 // ----------------------------------------------------------------------------
03791 // wxWindows callbacks
03792 // ----------------------------------------------------------------------------
03793 
03794 void wxTreeListMainWindow::OnPaint (wxPaintEvent &WXUNUSED(event)) {
03795 
03796     // init device context, clear background (BEFORE changing DC origin...)
03797     wxAutoBufferedPaintDC dc (this);
03798 #if wxCHECK_VERSION(3, 0, 0)
03799     wxBrush brush(GetBackgroundColour(), wxBRUSHSTYLE_SOLID);
03800 #else
03801     wxBrush brush(GetBackgroundColour(), wxSOLID);
03802 #endif
03803     dc.SetBackground(brush);
03804     dc.Clear();
03805     DoPrepareDC (dc);
03806 
03807     if (!m_rootItem || (GetColumnCount() <= 0)) return;
03808 
03809     // calculate button size
03810     if (m_imageListButtons) {
03811         m_imageListButtons->GetSize (0, m_btnWidth, m_btnHeight);
03812     }else if (HasButtons()) {
03813         m_btnWidth = BTNWIDTH;
03814         m_btnHeight = BTNHEIGHT;
03815     }
03816     m_btnWidth2 = m_btnWidth/2;
03817     m_btnHeight2 = m_btnHeight/2;
03818 
03819     // calculate image size
03820     if (m_imageListNormal) {
03821         m_imageListNormal->GetSize (0, m_imgWidth, m_imgHeight);
03822     }
03823     m_imgWidth2 = m_imgWidth/2;
03824     m_imgHeight2 = m_imgHeight/2;
03825 
03826     // calculate indent size
03827     if (m_imageListButtons) {
03828         m_indent = wxMax (MININDENT, m_btnWidth + MARGIN);
03829     }else if (HasButtons()) {
03830         m_indent = wxMax (MININDENT, m_btnWidth + LINEATROOT);
03831     }
03832 
03833     // set default values
03834     dc.SetFont( m_normalFont );
03835     dc.SetPen( m_dottedPen );
03836 
03837     // calculate column start and paint
03838     int x_maincol = 0;
03839     int i = 0;
03840     for (i = 0; i < (int)GetMainColumn(); ++i) {
03841         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
03842         x_maincol += m_owner->GetHeaderWindow()->GetColumnWidth (i);
03843     }
03844     int y = 0;
03845     PaintLevel (m_rootItem, dc, 0, y, x_maincol);
03846 }
03847 
03848 void wxTreeListMainWindow::OnSetFocus (wxFocusEvent &event) {
03849     m_hasFocus = true;
03850     RefreshSelected();
03851     if (m_curItem) RefreshLine (m_curItem);
03852     event.Skip();
03853 }
03854 
03855 void wxTreeListMainWindow::OnKillFocus( wxFocusEvent &event )
03856 {
03857     m_hasFocus = false;
03858     RefreshSelected();
03859     if (m_curItem) RefreshLine (m_curItem);
03860     event.Skip();
03861 }
03862 
03863 void wxTreeListMainWindow::OnChar (wxKeyEvent &event) {
03864     // send event to user code
03865     wxTreeEvent nevent (wxEVT_COMMAND_TREE_KEY_DOWN, 0 );
03866     nevent.SetInt(m_curColumn);
03867     nevent.SetKeyEvent (event);
03868     if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
03869 
03870     // if no item current, select root
03871     bool curItemSet = false;
03872     if (!m_curItem) {
03873         if (! GetRootItem().IsOk()) return;
03874         SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
03875         if (HasFlag(wxTR_HIDE_ROOT)) {
03876 #if !wxCHECK_VERSION(2, 5, 0)
03877             long cookie = 0;
03878 #else
03879             wxTreeItemIdValue cookie = 0;
03880 #endif
03881             SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
03882         }
03883         SelectItem(m_curItem, (wxTreeItemId*)NULL, true);  // unselect others
03884         curItemSet = true;
03885     }
03886 
03887     // remember item at shift down
03888     if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
03889         if (!m_shiftItem) m_shiftItem = m_curItem;
03890     }else{
03891         m_shiftItem = (wxTreeListItem*)NULL;
03892     }
03893 
03894     if (curItemSet) return;  // if no item was current until now, do nothing more
03895 
03896     // process all cases
03897     wxTreeItemId newItem = (wxTreeItemId*)NULL;
03898     switch (event.GetKeyCode()) {
03899 
03900         // '+': Expand subtree
03901         case '+':
03902         case WXK_ADD: {
03903             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
03904         }break;
03905 
03906         // '-': collapse subtree
03907         case '-':
03908         case WXK_SUBTRACT: {
03909             if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
03910         }break;
03911 
03912         // '*': expand/collapse all subtrees // TODO: Mak it more useful
03913         case '*':
03914         case WXK_MULTIPLY: {
03915             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
03916                 ExpandAll (m_curItem);
03917             }else if (m_curItem->HasPlus()) {
03918                 Collapse (m_curItem); // TODO: CollapseAll
03919             }
03920         }break;
03921 
03922         // ' ': toggle current item
03923         case ' ': {
03924             SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
03925         }break;
03926 
03927         // <RETURN>: activate current item
03928         case WXK_RETURN: {
03929             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
03930 
03931                 // if the user code didn't process the activate event,
03932                 // handle it ourselves by toggling the item when it is
03933                 // double clicked
03934                 if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
03935             }
03936         }break;
03937 
03938         // <BKSP>: go to the parent without collapsing
03939         case WXK_BACK: {
03940             newItem = GetItemParent (m_curItem);
03941             if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03942                 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
03943             }
03944         }break;
03945 
03946         // <HOME>: go to first visible
03947         case WXK_HOME: {
03948             newItem = GetFirstVisible(false, false);
03949         }break;
03950 
03951         // <PAGE-UP>: go to the top of the page, or if we already are then one page back
03952         case WXK_PAGEUP: {
03953         int flags = 0;
03954         int col = 0;
03955         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
03956         // PAGE-UP: first go the the first visible row
03957             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03958             newItem = GetFirstVisible(false, true);
03959         // if we are already there then scroll back one page
03960             if (newItem == m_curItem) {
03961                 abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
03962                 if (abs_p.y < 0) abs_p.y = 0;
03963                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03964             }
03965             // newItem should never be NULL
03966         } break;
03967 
03968         // <UP>: go to the previous sibling or for the last of its children, to the parent
03969         case WXK_UP: {
03970             newItem = GetPrevSibling (m_curItem);
03971             if (newItem) {
03972 #if !wxCHECK_VERSION(2, 5, 0)
03973                 long cookie = 0;
03974 #else
03975                 wxTreeItemIdValue cookie = 0;
03976 #endif
03977                 while (IsExpanded (newItem) && HasChildren (newItem)) {
03978                     newItem = GetLastChild (newItem, cookie);
03979                 }
03980             }else {
03981                 newItem = GetItemParent (m_curItem);
03982                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03983                     newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
03984                 }
03985             }
03986         }break;
03987 
03988         // <LEFT>: if expanded collapse subtree, else go to the parent
03989         case WXK_LEFT: {
03990             if (IsExpanded (m_curItem)) {
03991                 Collapse (m_curItem);
03992             }else{
03993                 newItem = GetItemParent (m_curItem);
03994                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03995                     newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
03996                 }
03997             }
03998         }break;
03999 
04000         // <RIGHT>: if possible expand subtree, else go go to the first child
04001         case WXK_RIGHT: {
04002             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
04003                 Expand (m_curItem);
04004             }else{
04005                 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
04006 #if !wxCHECK_VERSION(2, 5, 0)
04007                     long cookie = 0;
04008 #else
04009                     wxTreeItemIdValue cookie = 0;
04010 #endif
04011                     newItem = GetFirstChild (m_curItem, cookie);
04012                 }
04013             }
04014         }break;
04015 
04016         // <DOWN>: if expanded go to the first child, else to the next sibling, ect
04017         case WXK_DOWN: {
04018             if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
04019 #if !wxCHECK_VERSION(2, 5, 0)
04020                 long cookie = 0;
04021 #else
04022                 wxTreeItemIdValue cookie = 0;
04023 #endif
04024                 newItem = GetFirstChild( m_curItem, cookie );
04025             }
04026             if (!newItem) {
04027                 wxTreeItemId parent = m_curItem;
04028                 do {
04029                     newItem = GetNextSibling (parent);
04030                     parent = GetItemParent (parent);
04031                 } while (!newItem && parent);
04032             }
04033         }break;
04034 
04035         // <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
04036         case WXK_PAGEDOWN: {
04037         int flags = 0;
04038         int col = 0;
04039         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
04040         // PAGE-UP: first go the the first visible row
04041             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
04042             newItem = GetLastVisible(false, true);
04043         // if we are already there then scroll down one page
04044             if (newItem == m_curItem) {
04045                 abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
04046 //                if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
04047                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
04048             }
04049         // if we reached the empty area below the rows, return last item instead
04050             if (! newItem) newItem = GetLastVisible(false, false);
04051         } break;
04052 
04053         // <END>: go to last item of the root
04054         case WXK_END: {
04055             newItem = GetLastVisible (false, false);
04056         }break;
04057 
04058         // any char: go to the next matching string
04059         default:
04060             wxChar key = event.GetUnicodeKey();
04061 #if wxCHECK_VERSION(3,0,0)
04062             if (key == WXK_NONE) key = (wxChar)event.GetKeyCode();
04063 #else
04064             if (key == 0) key = (wxChar)event.GetKeyCode();
04065 #endif
04066             if (key  >= 32) {
04067                 // prepare search parameters
04068                 int mode = wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE;
04069                 if (!m_findTimer->IsRunning()) m_findStr.Clear();
04070                 m_findStr.Append (key);
04071                 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
04072                 wxTreeItemId prev = (wxTreeItemId*)NULL;
04073                 // try if current item or one of its followers matches
04074                 if (m_curItem) {
04075                     prev = (wxTreeItemId*)m_curItem;
04076                     for (int col=0; col<=GetColumnCount() - 1; col++) {
04077                         if (MatchItemText(GetItemText(prev, col), m_findStr, mode)) {
04078                             newItem = prev;
04079                             break;
04080                         }
04081                     }
04082                     if (! newItem) {
04083                         newItem = FindItem (prev, -1, m_findStr, mode);
04084                     };
04085                 }
04086                 // current item or does not match: try to find next
04087                 // still not match: search from beginning (but only if there was a current item i.e.we did not start from root already)
04088                 if (! newItem) {
04089                     prev = (wxTreeItemId*)NULL;
04090                     newItem = FindItem (prev, -1, m_findStr, mode);
04091                 }
04092                 // no match at all: remove just typed char to allow try with another extension
04093                 if (! newItem) m_findStr.RemoveLast();
04094             }
04095             event.Skip();
04096 
04097     }
04098 
04099     // select and show the new item
04100     if (newItem) {
04101         if (!event.ControlDown()) {
04102             bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
04103                                       HasFlag(wxTR_MULTIPLE));
04104             SelectItem (newItem, m_shiftItem, unselect_others);
04105         }
04106         EnsureVisible (newItem);
04107         wxTreeListItem *oldItem = m_curItem;
04108         SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
04109         RefreshLine (oldItem);
04110     }
04111 
04112 }
04113 
04114 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
04115 
04116     int w, h;
04117     GetSize(&w, &h);
04118     flags=0;
04119     column = -1;
04120     if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
04121     if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
04122     if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
04123     if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
04124     if (flags) return wxTreeItemId();
04125 
04126     if (!m_rootItem) {
04127         flags = wxTREE_HITTEST_NOWHERE;
04128         column = -1;
04129         return wxTreeItemId();
04130     }
04131 
04132     wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
04133                                                this, flags, column, 0);
04134     if (!hit) {
04135         flags = wxTREE_HITTEST_NOWHERE;
04136         column = -1;
04137         return wxTreeItemId();
04138     }
04139     return hit;
04140 }
04141 
04142 // get the bounding rectangle of the item (or of its label only)
04143 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
04144                                             bool WXUNUSED(textOnly)) const {
04145     wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
04146 
04147     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
04148 
04149     int xUnit, yUnit;
04150     GetScrollPixelsPerUnit (&xUnit, &yUnit);
04151     int startX, startY;
04152     GetViewStart(& startX, & startY);
04153 
04154     rect.x = item->GetX() - startX * xUnit;
04155     rect.y = item->GetY() - startY * yUnit;
04156     rect.width = item->GetWidth();
04157     rect.height = GetLineHeight (item);
04158 
04159     return true;
04160 }
04161 
04162 /* **** */
04163 
04164 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
04165 
04166 // validate
04167     if (!item.IsOk()) return;
04168     if (!((column >= 0) && (column < GetColumnCount()))) return;
04169 
04170 // cancel any editing
04171     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
04172 
04173 // prepare edit (position)
04174     m_editItem = (wxTreeListItem*) item.m_pItem;
04175 
04176     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
04177     te.SetInt (column);
04178     SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
04179 
04180     // ensure that the position of the item it calculated in any case
04181     if (m_dirty) CalculatePositions();
04182 
04183     wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
04184 
04185     // position & size are rather unpredictable (tsssk, tssssk) so were
04186     //  set by trial & error (on Win 2003 pre-XP style)
04187     int x = 0;
04188     int w = +4;  // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
04189     int y = m_editItem->GetY() + 1;  // this is cell, not text
04190     int h = m_editItem->GetHeight() - 1;  // consequence from above
04191     long style = 0;
04192     if (column == GetMainColumn()) {
04193         x += m_editItem->GetTextX() - 2;  // wrong by 2, don't know why
04194         w += m_editItem->GetWidth();
04195     } else {
04196         for (int i = 0; i < column; ++i) {
04197             if ( header_win->IsColumnShown(i) ) {
04198                 x += header_win->GetColumnWidth (i); // start of column
04199             }
04200                 }
04201         w += header_win->GetColumnWidth (column);  // currently non-main column width not pre-computed
04202     }
04203     switch (header_win->GetColumnAlignment (column)) {
04204         case wxALIGN_LEFT:   {style = wxTE_LEFT;   x -= 1; break;}
04205         case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
04206         case wxALIGN_RIGHT:  {style = wxTE_RIGHT;  x += 0; break;}  // yes, strange but that's the way it is
04207     }
04208     // wxTextCtrl simple border style requires 2 extra pixels before and after
04209     //  (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
04210     y -= 2; x -= 2;
04211     w += 4; h += 4;
04212 
04213     wxClientDC dc (this);
04214     PrepareDC (dc);
04215     x = dc.LogicalToDeviceX (x);
04216     y = dc.LogicalToDeviceY (y);
04217 
04218 // now do edit (change state, show control)
04219     m_editCol = column;  // only used in OnRenameAccept()
04220     m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
04221                                                this, m_editItem->GetText (column),
04222                                                wxPoint (x, y), wxSize (w, h), style);
04223     m_editControl->SelectAll();
04224     m_editControl->SetFocus();
04225 }
04226 
04227 void wxTreeListMainWindow::OnRenameTimer() {
04228     EditLabel (m_curItem, GetCurrentColumn());
04229 }
04230 
04231 void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
04232 
04233     // TODO if the validator fails this causes a crash
04234     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
04235     le.SetLabel( m_editRes );
04236     le.SetEditCanceled(isCancelled);
04237     le.SetInt(m_editCol);
04238     SendEvent(0, m_editItem, &le); if (! isCancelled  && le.IsAllowed())
04239     {
04240         SetItemText (m_editItem, le.GetInt(), le.GetLabel());
04241     }
04242 }
04243 
04244 void wxTreeListMainWindow::EndEdit(bool isCancelled) {
04245     if (m_editControl) { m_editControl->EndEdit(true); }
04246 }
04247 
04248 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
04249 bool mayDrag = true;
04250 bool maySelect = true;  // may change selection
04251 bool mayClick = true;  // may process DOWN clicks to expand, send click events
04252 bool mayDoubleClick = true;  // implies mayClick
04253 bool bSkip = true;
04254 
04255     // send event to user code
04256     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
04257     if (!m_rootItem) return;
04258 
04259 
04260 // ---------- DETERMINE EVENT ----------
04261 /*
04262 wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
04263     event.LeftDown(), event.MiddleDown(), event.RightDown(),
04264     event.LeftUp(), event.MiddleUp(), event.RightUp(),
04265     event.LeftDClick(), event.Dragging());
04266 */
04267     wxPoint p = wxPoint (event.GetX(), event.GetY());
04268     int flags = 0;
04269     wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
04270                                                 this, flags, m_curColumn, 0);
04271     bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
04272     // we were dragging
04273     if (m_isDragging) {
04274         maySelect = mayDoubleClick = false;
04275     }
04276     // we are starting or continuing to drag
04277     if (event.Dragging()) {
04278         maySelect = mayDoubleClick = mayClick = false;
04279     }
04280     // crosshair area is special
04281     if (bCrosshair) {
04282         // left click does not select
04283         if (event.LeftDown()) maySelect = false;
04284         // double click is ignored
04285         mayDoubleClick = false;
04286     }
04287     // double click only if simple click
04288     if (mayDoubleClick) mayDoubleClick = mayClick;
04289     // selection conditions --remember also that selection exludes editing
04290     if (maySelect) maySelect = mayClick;  // yes, select/unselect requires a click
04291     if (maySelect) {
04292 
04293         // multiple selection mode complicates things, sometimes we
04294         //  select on button-up instead of down:
04295         if (HasFlag(wxTR_MULTIPLE)) {
04296 
04297             // CONTROL/SHIFT key used, don't care about anything else, will
04298             //  toggle on key down
04299             if (event.ControlDown() || event.ShiftDown()) {
04300                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04301                 m_lastOnSame = false;  // prevent editing when keys are used
04302 
04303             // already selected item: to allow drag or contextual menu for multiple
04304             //  items, we only select/unselect on click-up --and only on LEFT
04305             // click, right is reserved for contextual menu
04306             } else if ((item != NULL && item->IsSelected())) {
04307                 maySelect = maySelect && event.LeftUp();
04308 
04309             // non-selected items: select on click-down like simple select (so
04310             //  that a right-click contextual menu may be chained)
04311             } else {
04312                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04313             }
04314 
04315         // single-select is simply on left or right click-down
04316         } else {
04317             maySelect = maySelect && (event.LeftDown() || event.RightDown());
04318         }
04319     }
04320 
04321 
04322 // ----------  GENERAL ACTIONS  ----------
04323 
04324     // set focus if window clicked
04325     if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
04326 
04327     // tooltip change ?
04328     if (item != m_toolTipItem) {
04329 
04330         // not over an item, use global tip
04331         if (item == NULL) {
04332             m_toolTipItem = NULL;
04333             wxScrolledWindow::SetToolTip(m_toolTip);
04334 
04335         // over an item
04336         } else {
04337             const wxString *tip = item->GetToolTip();
04338 
04339             // is there an item-specific tip ?
04340             if (tip) {
04341                 m_toolTipItem = item;
04342                 wxScrolledWindow::SetToolTip(*tip);
04343 
04344             // no item tip, but we are in item-specific mode (SetItemToolTip()
04345             //  was called after SetToolTip() )
04346             } else if (m_isItemToolTip) {
04347                 m_toolTipItem = item;
04348                 wxScrolledWindow::SetToolTip(wxString());
04349 
04350             // no item tip, display global tip instead; item change ignored
04351             } else if (m_toolTipItem != NULL) {
04352                 m_toolTipItem = NULL;
04353                 wxScrolledWindow::SetToolTip(m_toolTip);
04354             }
04355         }
04356     }
04357 
04358 
04359 // ----------  HANDLE SIMPLE-CLICKS  (selection change, contextual menu) ----------
04360     if (mayClick) {
04361 
04362         // 2nd left-click on an item might trigger edit
04363         if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
04364 
04365         // left-click on haircross is expand (and no select)
04366         if (bCrosshair && event.LeftDown()) {
04367 
04368             bSkip = false;
04369 
04370             // note that we only toggle the item for a single click, double
04371             // click on the button doesn't do anything
04372             Toggle (item);
04373         }
04374 
04375         if (maySelect) {
04376             bSkip = false;
04377 
04378             // set / remember item at shift down before current item gets changed
04379             if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
04380                 if (!m_shiftItem) m_shiftItem = m_curItem;
04381             }else{
04382                 m_shiftItem = (wxTreeListItem*)NULL;
04383             }
04384 
04385             // how is selection altered
04386             // keep or discard already selected ?
04387             bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
04388                 event.ShiftDown()
04389              || event.ControlDown()
04390             ));
04391 
04392             // check is selection change is not vetoed
04393             if (SelectItem(item, m_shiftItem, unselect_others)) {
04394                 // make the new item the current item
04395                 EnsureVisible (item);
04396                 SetCurrentItem(item);
04397             }
04398         }
04399 
04400         // generate click & menu events
04401         if (event.MiddleDown()) {
04402             // our own event to set point
04403             wxTreeEvent nevent(0, 0);
04404             nevent.SetPoint(p);
04405             nevent.SetInt(m_curColumn);
04406             bSkip = false;
04407             SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item, &nevent);
04408         }
04409         if (event.RightDown()) {
04410             // our own event to set point
04411             wxTreeEvent nevent(0, 0);
04412             nevent.SetPoint(p);
04413             nevent.SetInt(m_curColumn);
04414             bSkip = false;
04415             SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item, &nevent);
04416         }
04417         if (event.RightUp()) {
04418             // our own event to set point
04419             wxTreeEvent nevent(0, 0);
04420             nevent.SetPoint(p);
04421             nevent.SetInt(m_curColumn);
04422             SendEvent(wxEVT_COMMAND_TREE_ITEM_MENU, item, &nevent);
04423         }
04424 
04425         // if 2nd left click finishes on same item, will edit it
04426         if (m_lastOnSame && event.LeftUp()) {
04427             if ((item == m_curItem) && (m_curColumn != -1) &&
04428                 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
04429                 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
04430             ){
04431                 m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
04432                 bSkip = false;
04433             }
04434             m_lastOnSame = false;
04435         }
04436     }
04437 
04438 
04439 // ----------  HANDLE DOUBLE-CLICKS  ----------
04440     if (mayDoubleClick && event.LeftDClick()) {
04441 
04442         bSkip = false;
04443 
04444         // double clicking should not start editing the item label
04445         m_editTimer->Stop();
04446         m_lastOnSame = false;
04447 
04448         // selection reset to that single item which was double-clicked
04449         if (SelectItem(item, (wxTreeItemId*)NULL, true)) {  // unselect others --return false if vetoed
04450 
04451             // selection change not vetoed, send activate event
04452             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
04453 
04454                 // if the user code didn't process the activate event,
04455                 // handle it ourselves by toggling the item when it is
04456                 // double clicked
04457                 if (item && item->HasPlus()) Toggle(item);
04458             }
04459         }
04460     }
04461 
04462 
04463 // ----------  HANDLE DRAGGING  ----------
04464 // NOTE: drag itself makes no change to selection
04465     if (mayDrag) {  // actually this is always true
04466 
04467         // CASE 1: we were dragging => continue, end, abort
04468         if (m_isDragging) {
04469 
04470             // CASE 1.1: click aborts drag:
04471             if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
04472 
04473                 bSkip = false;
04474 
04475                 // stop dragging
04476                 m_isDragStarted = m_isDragging = false;
04477                 if (HasCapture()) ReleaseMouse();
04478                 RefreshSelected();
04479 
04480             // CASE 1.2: still dragging
04481             } else if (event.Dragging()) {
04482 
04483                 ;; // nothing to do
04484 
04485             // CASE 1.3: dragging now ends normally
04486             } else {
04487 
04488                 bSkip = false;
04489 
04490                 // stop dragging
04491                 m_isDragStarted = m_isDragging = false;
04492                 if (HasCapture()) ReleaseMouse();
04493                 RefreshSelected();
04494 
04495                 // send drag end event
04496                 // our own event to set point
04497                 wxTreeEvent nevent(0, 0);
04498                 nevent.SetPoint(p);
04499                 nevent.SetInt(m_curColumn);
04500                 SendEvent(wxEVT_COMMAND_TREE_END_DRAG, item, &nevent);
04501             }
04502 
04503         // CASE 2: not were not dragging => continue, start
04504         } else if (event.Dragging()) {
04505 
04506             // We will really start dragging if we've moved beyond a few pixels
04507             if (m_isDragStarted) {
04508                 const int tolerance = 3;
04509                 int dx = abs(p.x - m_dragStartPos.x);
04510                 int dy = abs(p.y - m_dragStartPos.y);
04511                 if (dx <= tolerance && dy <= tolerance)
04512                     return;
04513             // determine drag start
04514             } else {
04515                 m_dragStartPos = p;
04516                 m_dragCol = GetCurrentColumn();
04517                 m_dragItem = item;
04518                 m_isDragStarted = true;
04519                 return;
04520             }
04521 
04522             bSkip = false;
04523 
04524             // we are now dragging
04525             m_isDragging = true;
04526             RefreshSelected();
04527             CaptureMouse(); // TODO: usefulness unclear
04528 
04529             wxTreeEvent nevent(0, 0);
04530             nevent.SetPoint(p);
04531             nevent.SetInt(m_dragCol);
04532             nevent.Veto();
04533             SendEvent(event.LeftIsDown()
04534                                   ? wxEVT_COMMAND_TREE_BEGIN_DRAG
04535                                   : wxEVT_COMMAND_TREE_BEGIN_RDRAG,
04536                       m_dragItem, &nevent);
04537         }
04538     }
04539 
04540 
04541     if (bSkip) event.Skip();
04542 }
04543 
04544 
04545 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
04546     /* after all changes have been done to the tree control,
04547      * we actually redraw the tree when everything is over */
04548 
04549     if (!m_dirty) return;
04550 
04551     m_dirty = false;
04552 
04553     CalculatePositions();
04554     Refresh();
04555     AdjustMyScrollbars();
04556 }
04557 
04558 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
04559 
04560     // send event to wxTreeListCtrl (for user code)
04561     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
04562 
04563     // TODO
04564 #if defined(__WXGTK__) && !defined(__WXUNIVERSAL__) && !wxCHECK_VERSION(3,0,0)
04565     wxScrolledWindow::OnScroll(event);
04566 #else
04567     HandleOnScroll( event );
04568 #endif
04569 
04570     if(event.GetOrientation() == wxHORIZONTAL) {
04571         m_owner->GetHeaderWindow()->Refresh();
04572         m_owner->GetHeaderWindow()->Update();
04573     }
04574 }
04575 
04576 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
04577     wxCoord text_w = 0;
04578     wxCoord text_h = 0;
04579 
04580     dc.SetFont (GetItemFont (item));
04581     dc.GetTextExtent (item->GetText(m_main_column).size() > 0
04582             ? item->GetText (m_main_column)
04583             : _T(" "),  // blank to avoid zero height and no highlight width
04584         &text_w, &text_h);
04585     // restore normal font
04586     dc.SetFont (m_normalFont);
04587 
04588     int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
04589     if (max_h < 30) { // add 10% space if greater than 30 pixels
04590         max_h += 2; // minimal 2 pixel space
04591     }else{
04592         max_h += max_h / 10; // otherwise 10% space
04593     }
04594 
04595     item->SetHeight (max_h);
04596     if (max_h > m_lineHeight) m_lineHeight = max_h;
04597     item->SetWidth(m_imgWidth + text_w+2);
04598 }
04599 
04600 // -----------------------------------------------------------------------------
04601 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
04602                                            int level, int &y, int x_colstart) {
04603 
04604     // calculate position of vertical lines
04605     int x = x_colstart + MARGIN; // start of column
04606     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
04607     if (HasButtons()) {
04608         x += (m_btnWidth-m_btnWidth2); // half button space
04609     }else{
04610         x += (m_indent-m_indent/2);
04611     }
04612     if (HasFlag(wxTR_HIDE_ROOT)) {
04613         x += m_indent * (level-1); // indent but not level 1
04614     }else{
04615         x += m_indent * level; // indent according to level
04616     }
04617 
04618     // a hidden root is not evaluated, but its children are always
04619     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
04620 
04621     CalculateSize( item, dc );
04622 
04623     // set its position
04624     item->SetX (x);
04625     item->SetY (y);
04626     y += GetLineHeight(item);
04627 
04628     // we don't need to calculate collapsed branches
04629     if ( !item->IsExpanded() ) return;
04630 
04631 Recurse:
04632     wxArrayTreeListItems& children = item->GetChildren();
04633     long n, count = (long)children.Count();
04634     ++level;
04635     for (n = 0; n < count; ++n) {
04636         CalculateLevel( children[n], dc, level, y, x_colstart );  // recurse
04637     }
04638 }
04639 
04640 void wxTreeListMainWindow::CalculatePositions() {
04641     if ( !m_rootItem ) return;
04642 
04643     wxClientDC dc(this);
04644     PrepareDC( dc );
04645 
04646     dc.SetFont( m_normalFont );
04647 
04648     dc.SetPen( m_dottedPen );
04649     //if(GetImageList() == NULL)
04650     // m_lineHeight = (int)(dc.GetCharHeight() + 4);
04651 
04652     int y = 2;
04653     int x_colstart = 0;
04654     for (int i = 0; i < (int)GetMainColumn(); ++i) {
04655         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
04656         x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
04657     }
04658     CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
04659 }
04660 
04661 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
04662     if (m_dirty) return;
04663 
04664     wxClientDC dc(this);
04665     PrepareDC(dc);
04666 
04667     int cw = 0;
04668     int ch = 0;
04669     GetVirtualSize( &cw, &ch );
04670 
04671     wxRect rect;
04672     rect.x = dc.LogicalToDeviceX( 0 );
04673     rect.width = cw;
04674     rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
04675     rect.height = ch;
04676 
04677     Refresh (true, &rect );
04678     AdjustMyScrollbars();
04679 }
04680 
04681 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
04682     if (m_dirty) return;
04683 
04684     wxClientDC dc(this);
04685     PrepareDC( dc );
04686 
04687     int cw = 0;
04688     int ch = 0;
04689     GetVirtualSize( &cw, &ch );
04690 
04691     wxRect rect;
04692     rect.x = dc.LogicalToDeviceX( 0 );
04693     rect.y = dc.LogicalToDeviceY( item->GetY() );
04694     rect.width = cw;
04695     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
04696 
04697     Refresh (true, &rect);
04698 }
04699 
04700 void wxTreeListMainWindow::RefreshSelected() {
04701     // TODO: this is awfully inefficient, we should keep the list of all
04702     //       selected items internally, should be much faster
04703     if (m_rootItem) {
04704         RefreshSelectedUnder (m_rootItem);
04705     }
04706 }
04707 
04708 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
04709     if (item->IsSelected()) {
04710         RefreshLine (item);
04711     }
04712 
04713     const wxArrayTreeListItems& children = item->GetChildren();
04714     long count = (long)children.GetCount();
04715     for (long n = 0; n < count; n++ ) {
04716         RefreshSelectedUnder (children[n]);
04717     }
04718 }
04719 
04720 // ----------------------------------------------------------------------------
04721 // changing colours: we need to refresh the tree control
04722 // ----------------------------------------------------------------------------
04723 
04724 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
04725     if (!wxWindow::SetBackgroundColour(colour)) return false;
04726 
04727     Refresh();
04728     return true;
04729 }
04730 
04731 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
04732     if (!wxWindow::SetForegroundColour(colour)) return false;
04733 
04734     Refresh();
04735     return true;
04736 }
04737 
04738 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
04739     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
04740 
04741     if (this->IsFrozen())
04742     {
04743         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04744         item->SetText(column, text);
04745         m_dirty = true;
04746     }
04747     else
04748     {
04749         wxClientDC dc(this);
04750         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04751         item->SetText(column, text);
04752         CalculateSize(item, dc);
04753         RefreshLine(item);
04754     };
04755 }
04756 
04757 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
04758     wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
04759 
04760     if( IsVirtual() )   return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
04761     else                return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
04762 }
04763 
04764 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
04765    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
04766    return m_owner->OnGetItemText(item, column);
04767 }
04768 
04769 void wxTreeListMainWindow::SetFocus() {
04770     wxWindow::SetFocus();
04771 }
04772 
04773 
04774 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
04775     if (!item) return 0;
04776 
04777     // determine item width
04778     int w = 0, h = 0;
04779     wxFont font = GetItemFont (item);
04780     GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
04781     w += 2*MARGIN;
04782 
04783     // calculate width
04784     int width = w + 2*MARGIN;
04785     if (column == GetMainColumn()) {
04786         width += MARGIN;
04787         if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
04788         if (HasButtons()) width += m_btnWidth + LINEATROOT;
04789         if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
04790 
04791         // count indent level
04792         int level = 0;
04793         wxTreeListItem *parent = item->GetItemParent();
04794         wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
04795         while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
04796             level++;
04797             parent = parent->GetItemParent();
04798         }
04799         if (level) width += level * GetIndent();
04800     }
04801 
04802     return width;
04803 }
04804 
04805 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
04806     int maxWidth, h;
04807     GetClientSize (&maxWidth, &h);
04808     int width = 0;
04809 
04810     // get root if on item
04811     if (!parent.IsOk()) parent = GetRootItem();
04812 
04813     // add root width
04814     if (!HasFlag(wxTR_HIDE_ROOT)) {
04815         int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
04816         if (width < w) width = w;
04817         if (width > maxWidth) return maxWidth;
04818     }
04819 
04820     wxTreeItemIdValue cookie = 0;
04821     wxTreeItemId item = GetFirstChild (parent, cookie);
04822     while (item.IsOk()) {
04823         int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
04824         if (width < w) width = w;
04825         if (width > maxWidth) return maxWidth;
04826 
04827         // check the children of this item
04828         if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
04829             int w = GetBestColumnWidth (column, item);
04830             if (width < w) width = w;
04831             if (width > maxWidth) return maxWidth;
04832         }
04833 
04834         // next sibling
04835         item = GetNextChild (parent, cookie);
04836     }
04837 
04838     return width;
04839 }
04840 
04841 
04842 bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
04843 wxTreeEvent nevent (event_type, 0);
04844 
04845     if (event == NULL) {
04846         event = &nevent;
04847         event->SetInt (m_curColumn); // the mouse colum
04848     } else if (event_type) {
04849         event->SetEventType(event_type);
04850     }
04851 
04852     event->SetEventObject (m_owner);
04853     event->SetId(m_owner->GetId());
04854     if (item) {
04855 #if !wxCHECK_VERSION(2, 5, 0)
04856         event->SetItem ((long)item);
04857 #else
04858         event->SetItem (item);
04859 #endif
04860     }
04861 
04862     return m_owner->GetEventHandler()->ProcessEvent (*event);
04863 }
04864 
04865 
04866 //-----------------------------------------------------------------------------
04867 //  wxTreeListCtrl
04868 //-----------------------------------------------------------------------------
04869 
04870 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
04871 
04872 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
04873     EVT_SIZE(wxTreeListCtrl::OnSize)
04874 END_EVENT_TABLE();
04875 
04876 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
04877                             const wxPoint& pos,
04878                             const wxSize& size,
04879                             long style, const wxValidator &validator,
04880                             const wxString& name)
04881 {
04882     long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE |
04883                                 wxBORDER_RAISED | wxBORDER_STATIC);
04884     main_style |= wxWANTS_CHARS ;
04885     long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
04886 
04887     if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
04888        return false;
04889     }
04890     m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
04891                                            main_style, validator);
04892     m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
04893                                                wxPoint(0, 0), wxDefaultSize,
04894                                                wxTAB_TRAVERSAL);
04895     CalculateAndSetHeaderHeight();
04896     return true;
04897 }
04898 
04899 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
04900 {
04901     if (m_header_win) {
04902 
04903         // we use 'g' to get the descent, too
04904         int h;
04905 #if wxCHECK_VERSION_FULL(2, 7, 0, 1)
04906 #ifdef __WXMSW__
04907         h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
04908 #else
04909         h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
04910 #endif
04911 #else
04912         int w, d;
04913         m_header_win->GetTextExtent(_T("Hg"), &w, &h, &d);
04914         h += d + 2 * HEADER_OFFSET_Y + EXTRA_HEIGHT;
04915 #endif
04916 
04917         // only update if changed
04918         if (h != m_headerHeight) {
04919             m_headerHeight = h;
04920             DoHeaderLayout();
04921         }
04922     }
04923 }
04924 
04925 void wxTreeListCtrl::DoHeaderLayout()
04926 {
04927     int w, h;
04928     GetClientSize(&w, &h);
04929     if (m_header_win) {
04930         m_header_win->SetSize (0, 0, w, m_headerHeight);
04931         m_header_win->Refresh();
04932     }
04933     if (m_main_win) {
04934         m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
04935     }
04936 }
04937 
04938 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
04939 {
04940     DoHeaderLayout();
04941 }
04942 
04943 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
04944 
04945 unsigned int wxTreeListCtrl::GetIndent() const
04946 { return m_main_win->GetIndent(); }
04947 
04948 void wxTreeListCtrl::SetIndent(unsigned int indent)
04949 { m_main_win->SetIndent(indent); }
04950 
04951 unsigned int wxTreeListCtrl::GetLineSpacing() const
04952 { return m_main_win->GetLineSpacing(); }
04953 
04954 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
04955 { m_main_win->SetLineSpacing(spacing); }
04956 
04957 wxImageList* wxTreeListCtrl::GetImageList() const
04958 { return m_main_win->GetImageList(); }
04959 
04960 wxImageList* wxTreeListCtrl::GetStateImageList() const
04961 { return m_main_win->GetStateImageList(); }
04962 
04963 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
04964 { return m_main_win->GetButtonsImageList(); }
04965 
04966 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
04967 { m_main_win->SetImageList(imageList); }
04968 
04969 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
04970 { m_main_win->SetStateImageList(imageList); }
04971 
04972 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
04973 { m_main_win->SetButtonsImageList(imageList); }
04974 
04975 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
04976 { m_main_win->AssignImageList(imageList); }
04977 
04978 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
04979 { m_main_win->AssignStateImageList(imageList); }
04980 
04981 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
04982 { m_main_win->AssignButtonsImageList(imageList); }
04983 
04984 
04985 
04986 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
04987 { return m_main_win->GetItemText (item, column); }
04988 
04989 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
04990 { return m_main_win->GetItemImage(item, which); }
04991 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
04992 { return m_main_win->GetItemImage(item, column); }
04993 
04994 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
04995 { return m_main_win->GetItemData(item); }
04996 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
04997 { return m_main_win->GetItemData(item, column); }
04998 
04999 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
05000 { return m_main_win->GetItemBold(item); }
05001 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
05002 { return m_main_win->GetItemBold(item, column); }
05003 
05004 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
05005 { return m_main_win->GetItemTextColour(item); }
05006 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
05007 { return m_main_win->GetItemTextColour(item, column); }
05008 
05009 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
05010 { return m_main_win->GetItemBackgroundColour(item); }
05011 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
05012 { return m_main_win->GetItemBackgroundColour(item, column); }
05013 
05014 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
05015 { return m_main_win->GetItemFont(item); }
05016 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
05017 { return m_main_win->GetItemFont(item, column); }
05018 
05019 
05020 
05021 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
05022 { m_main_win->SetItemHasChildren(item, has); }
05023 
05024 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
05025 { m_main_win->SetItemText (item, column, text); }
05026 
05027 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
05028 { m_main_win->SetItemImage(item, image, which); }
05029 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
05030 { m_main_win->SetItemImage(item, column, image); }
05031 
05032 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data)
05033 { m_main_win->SetItemData(item, data); }
05034 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
05035 { m_main_win->SetItemData(item, column, data); }
05036 
05037 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold)
05038 { m_main_win->SetItemBold(item, bold); }
05039 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
05040 { m_main_win->SetItemBold(item, column, bold); }
05041 
05042 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour)
05043 { m_main_win->SetItemTextColour(item, colour); }
05044 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
05045 { m_main_win->SetItemTextColour(item, column, colour); }
05046 
05047 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour)
05048 { m_main_win->SetItemBackgroundColour(item, colour); }
05049 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
05050 { m_main_win->SetItemBackgroundColour(item, column, colour); }
05051 
05052 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font)
05053 { m_main_win->SetItemFont(item, font); }
05054 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
05055 { m_main_win->SetItemFont(item, column, font); }
05056 
05057 
05058 
05059 bool wxTreeListCtrl::SetFont(const wxFont& font)
05060 {
05061     if (m_header_win) {
05062         m_header_win->SetFont(font);
05063         CalculateAndSetHeaderHeight();
05064         m_header_win->Refresh();
05065     }
05066     if (m_main_win) {
05067         return m_main_win->SetFont(font);
05068     }else{
05069         return false;
05070     }
05071 }
05072 
05073 void wxTreeListCtrl::SetWindowStyleFlag(long style)
05074 {
05075     if (m_main_win)
05076     {
05077         long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE | wxBORDER_RAISED | wxBORDER_STATIC);
05078         main_style |= wxWANTS_CHARS;
05079         m_main_win->SetWindowStyle(main_style);
05080     };
05081     m_windowStyle = style & ~(wxVSCROLL | wxHSCROLL);
05082     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
05083 }
05084 
05085 long wxTreeListCtrl::GetWindowStyleFlag() const
05086 {
05087     long style = m_windowStyle;
05088     if(m_main_win)
05089         style |= m_main_win->GetWindowStyle();
05090     return style;
05091 }
05092 
05093 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05094 { return m_main_win->IsVisible(item, fullRow, within); }
05095 
05096 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
05097 { return m_main_win->HasChildren(item); }
05098 
05099 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
05100 { return m_main_win->IsExpanded(item); }
05101 
05102 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
05103 { return m_main_win->IsSelected(item); }
05104 
05105 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
05106 { return m_main_win->GetChildrenCount(item, rec); }
05107 
05108 wxTreeItemId wxTreeListCtrl::GetRootItem() const
05109 { return m_main_win->GetRootItem(); }
05110 
05111 wxTreeItemId wxTreeListCtrl::GetSelection() const
05112 { return m_main_win->GetSelection(); }
05113 
05114 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
05115 { return m_main_win->GetSelections(arr); }
05116 
05117 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
05118 { return m_main_win->GetItemParent(item); }
05119 
05120 #if !wxCHECK_VERSION(2, 5, 0)
05121 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
05122                                             long& cookie) const
05123 #else
05124 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
05125                                             wxTreeItemIdValue& cookie) const
05126 #endif
05127 { return m_main_win->GetFirstChild(item, cookie); }
05128 
05129 #if !wxCHECK_VERSION(2, 5, 0)
05130 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
05131                                            long& cookie) const
05132 #else
05133 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
05134                                            wxTreeItemIdValue& cookie) const
05135 #endif
05136 { return m_main_win->GetNextChild(item, cookie); }
05137 
05138 #if !wxCHECK_VERSION(2, 5, 0)
05139 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
05140                                            long& cookie) const
05141 #else
05142 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
05143                                            wxTreeItemIdValue& cookie) const
05144 #endif
05145 { return m_main_win->GetPrevChild(item, cookie); }
05146 
05147 #if !wxCHECK_VERSION(2, 5, 0)
05148 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
05149                                            long& cookie) const
05150 #else
05151 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
05152                                            wxTreeItemIdValue& cookie) const
05153 #endif
05154 { return m_main_win->GetLastChild(item, cookie); }
05155 
05156 
05157 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
05158 { return m_main_win->GetNextSibling(item); }
05159 
05160 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
05161 { return m_main_win->GetPrevSibling(item); }
05162 
05163 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
05164 { return m_main_win->GetNext(item, true); }
05165 
05166 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
05167 { return m_main_win->GetPrev(item, true); }
05168 
05169 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
05170 { return m_main_win->GetFirstExpandedItem(); }
05171 
05172 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
05173 { return m_main_win->GetNextExpanded(item); }
05174 
05175 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
05176 { return m_main_win->GetPrevExpanded(item); }
05177 
05178 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
05179 { return GetFirstVisible(fullRow); }
05180 wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
05181 { return m_main_win->GetFirstVisible(fullRow, within); }
05182 
05183 wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
05184 { return m_main_win->GetLastVisible(fullRow, within); }
05185 
05186 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05187 { return m_main_win->GetNextVisible(item, fullRow, within); }
05188 
05189 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
05190 { return m_main_win->GetPrevVisible(item, fullRow, within); }
05191 
05192 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
05193                                       int selectedImage, wxTreeItemData* data)
05194 { return m_main_win->AddRoot (text, image, selectedImage, data); }
05195 
05196 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
05197                                          const wxString& text, int image,
05198                                          int selectedImage,
05199                                          wxTreeItemData* data)
05200 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
05201 
05202 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
05203                                         const wxTreeItemId& previous,
05204                                         const wxString& text, int image,
05205                                         int selectedImage,
05206                                         wxTreeItemData* data)
05207 {
05208     return m_main_win->InsertItem(parent, previous, text, image,
05209                                   selectedImage, data);
05210 }
05211 
05212 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
05213                                         size_t index,
05214                                         const wxString& text, int image,
05215                                         int selectedImage,
05216                                         wxTreeItemData* data)
05217 {
05218     return m_main_win->InsertItem(parent, index, text, image,
05219                                   selectedImage, data);
05220 }
05221 
05222 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
05223                                         const wxString& text, int image,
05224                                         int selectedImage,
05225                                         wxTreeItemData* data)
05226 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
05227 
05228 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
05229 { m_main_win->Delete(item); }
05230 
05231 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
05232 { m_main_win->DeleteChildren(item); }
05233 
05234 void wxTreeListCtrl::DeleteRoot()
05235 { m_main_win->DeleteRoot(); }
05236 
05237 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
05238 { m_main_win->Expand(item); }
05239 
05240 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
05241 { m_main_win->ExpandAll(item); }
05242 
05243 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
05244 { m_main_win->Collapse(item); }
05245 
05246 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
05247 { m_main_win->CollapseAndReset(item); }
05248 
05249 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
05250 { m_main_win->Toggle(item); }
05251 
05252 void wxTreeListCtrl::Unselect()
05253 { m_main_win->Unselect(); }
05254 
05255 void wxTreeListCtrl::UnselectAll()
05256 { m_main_win->UnselectAll(); }
05257 
05258 bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
05259                                 bool unselect_others)
05260 { return m_main_win->SelectItem (item, last, unselect_others); }
05261 
05262 void wxTreeListCtrl::SelectAll()
05263 { m_main_win->SelectAll(); }
05264 
05265 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
05266 { m_main_win->EnsureVisible(item); }
05267 
05268 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
05269 { m_main_win->ScrollTo(item); }
05270 
05271 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
05272 {
05273     wxPoint p = pos;
05274     return m_main_win->HitTest (p, flags, column);
05275 }
05276 
05277 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
05278                                      bool textOnly) const
05279 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
05280 
05281 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
05282     { m_main_win->EditLabel (item, column); }
05283 void wxTreeListCtrl::EndEdit(bool isCancelled)
05284     { m_main_win->EndEdit(isCancelled); }
05285 
05286 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
05287 {
05288     // do the comparison here and not in m_main_win in order to allow
05289     // override in child class
05290     return wxStrcmp(GetItemText(item1), GetItemText(item2));
05291 }
05292 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
05293 {
05294     // do the comparison here and not in m_main_win in order to allow
05295     // override in child class
05296     return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
05297 }
05298 
05299 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
05300 { m_main_win->SortChildren(item, column, reverseOrder); }
05301 
05302 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
05303 { return m_main_win->FindItem (item, column, str, mode); }
05304 
05305 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
05306 { m_main_win->SetDragItem (item); }
05307 
05308 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
05309 {
05310     if (!m_main_win) return false;
05311     return m_main_win->SetBackgroundColour(colour);
05312 }
05313 
05314 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
05315 {
05316     if (!m_main_win) return false;
05317     return m_main_win->SetForegroundColour(colour);
05318 }
05319 
05320 int wxTreeListCtrl::GetColumnCount() const
05321 { return m_main_win->GetColumnCount(); }
05322 
05323 void wxTreeListCtrl::SetColumnWidth(int column, int width)
05324 {
05325     m_header_win->SetColumnWidth (column, width);
05326     m_header_win->Refresh();
05327 }
05328 
05329 int wxTreeListCtrl::GetColumnWidth(int column) const
05330 { return m_header_win->GetColumnWidth(column); }
05331 
05332 void wxTreeListCtrl::SetMainColumn(int column)
05333 { m_main_win->SetMainColumn(column); }
05334 
05335 int wxTreeListCtrl::GetMainColumn() const
05336 { return m_main_win->GetMainColumn(); }
05337 
05338 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
05339 {
05340     m_header_win->SetColumnText (column, text);
05341     m_header_win->Refresh();
05342 }
05343 
05344 wxString wxTreeListCtrl::GetColumnText(int column) const
05345 { return m_header_win->GetColumnText(column); }
05346 
05347 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
05348 {
05349     m_header_win->AddColumn (colInfo);
05350     DoHeaderLayout();
05351 }
05352 
05353 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
05354 {
05355     m_header_win->InsertColumn (before, colInfo);
05356     m_header_win->Refresh();
05357 }
05358 
05359 void wxTreeListCtrl::RemoveColumn(int column)
05360 {
05361     m_header_win->RemoveColumn (column);
05362     m_header_win->Refresh();
05363 }
05364 
05365 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
05366 {
05367     m_header_win->SetColumn (column, colInfo);
05368     m_header_win->Refresh();
05369 }
05370 
05371 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
05372 { return m_header_win->GetColumn(column); }
05373 
05374 wxTreeListColumnInfo wxTreeListCtrl::GetColumn(int column)
05375 { return m_header_win->GetColumn(column); }
05376 
05377 void wxTreeListCtrl::SetColumnImage(int column, int image)
05378 {
05379     m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
05380     m_header_win->Refresh();
05381 }
05382 
05383 int wxTreeListCtrl::GetColumnImage(int column) const
05384 {
05385     return m_header_win->GetColumn(column).GetImage();
05386 }
05387 
05388 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
05389 {
05390     m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
05391 }
05392 
05393 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
05394 {
05395     wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
05396     m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
05397     m_header_win->Refresh();
05398 }
05399 
05400 bool wxTreeListCtrl::IsColumnEditable(int column) const
05401 {
05402     return m_header_win->GetColumn(column).IsEditable();
05403 }
05404 
05405 bool wxTreeListCtrl::IsColumnShown(int column) const
05406 {
05407     return m_header_win->GetColumn(column).IsShown();
05408 }
05409 
05410 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
05411 {
05412     m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
05413     m_header_win->Refresh();
05414 }
05415 
05416 int wxTreeListCtrl::GetColumnAlignment(int column) const
05417 {
05418     return m_header_win->GetColumn(column).GetAlignment();
05419 }
05420 
05421 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
05422 {
05423     m_main_win->Refresh (erase, rect);
05424     m_header_win->Refresh (erase, rect);
05425 }
05426 
05427 void wxTreeListCtrl::SetFocus()
05428 { m_main_win->SetFocus(); }
05429 
05430 wxSize wxTreeListCtrl::DoGetBestSize() const
05431 {
05432     wxSize bestSizeHeader = m_header_win->GetBestSize();
05433     wxSize bestSizeMain = m_main_win->GetBestSize();
05434     return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
05435 }
05436 
05437 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
05438 {
05439     return wxEmptyString;
05440 }
05441 
05442 void wxTreeListCtrl::SetToolTip(const wxString& tip) {
05443     m_header_win->SetToolTip(tip);
05444     m_main_win->SetToolTip(tip);
05445 }
05446 void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
05447     m_header_win->SetToolTip(tip);
05448     m_main_win->SetToolTip(tip);
05449 }
05450 
05451 void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
05452     m_main_win->SetItemToolTip(item, tip);
05453 }
05454 
05455 void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
05456     m_main_win->SetCurrentItem(itemId);
05457 }
05458 
05459 void wxTreeListCtrl::SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item) {
05460     m_main_win->SetItemParent(parent, item);
05461 }
05462 
05463 //-----------------------------------------------------------------------------
05464 // wxTreeListCtrlXmlHandler - XRC support for wxTreeListCtrl
05465 //-----------------------------------------------------------------------------
05466 
05467 #if wxUSE_XRC
05468 
05469 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrlXmlHandler, wxXmlResourceHandler)
05470 
05471 wxTreeListCtrlXmlHandler::wxTreeListCtrlXmlHandler() : wxXmlResourceHandler() {
05472 
05473 #define wxTR_NO_BUTTONS              0x0000     // for convenience
05474 #define wxTR_HAS_BUTTONS             0x0001     // draw collapsed/expanded btns
05475 #define wxTR_NO_LINES                0x0004     // don't draw lines at all
05476 #define wxTR_LINES_AT_ROOT           0x0008     // connect top-level nodes
05477 #define wxTR_TWIST_BUTTONS           0x0010     // still used by wxTreeListCtrl
05478 
05479 #define wxTR_SINGLE                  0x0000     // for convenience
05480 #define wxTR_MULTIPLE                0x0020     // can select multiple items
05481 #define wxTR_EXTENDED                0x0040     // TODO: allow extended selection
05482 #define wxTR_HAS_VARIABLE_ROW_HEIGHT 0x0080     // what it says
05483 
05484 #define wxTR_EDIT_LABELS             0x0200     // can edit item labels
05485 #define wxTR_ROW_LINES               0x0400     // put border around items
05486 #define wxTR_HIDE_ROOT               0x0800     // don't display root node
05487 
05488 #define wxTR_FULL_ROW_HIGHLIGHT      0x2000     // highlight full horz space
05489 
05490 #ifdef __WXGTK20__
05491 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_NO_LINES)
05492 #else
05493 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT)
05494 #endif
05495 
05496 // wxTreeCtrl styles, taken from treebase.h
05497         XRC_ADD_STYLE(wxTR_NO_BUTTONS);
05498         XRC_ADD_STYLE(wxTR_HAS_BUTTONS);
05499         XRC_ADD_STYLE(wxTR_NO_LINES);
05500         XRC_ADD_STYLE(wxTR_LINES_AT_ROOT);
05501         XRC_ADD_STYLE(wxTR_TWIST_BUTTONS);
05502 
05503         XRC_ADD_STYLE(wxTR_SINGLE);
05504         XRC_ADD_STYLE(wxTR_MULTIPLE);
05505 #if WXWIN_COMPATIBILITY_2_8
05506     // according to wxWidgets release notes, wxTR_EXTENDED is deprecated
05507     XRC_ADD_STYLE(wxTR_EXTENDED);
05508 #endif // WXWIN_COMPATIBILITY_2_8
05509     XRC_ADD_STYLE(wxTR_HAS_VARIABLE_ROW_HEIGHT);
05510 
05511     XRC_ADD_STYLE(wxTR_EDIT_LABELS);
05512     XRC_ADD_STYLE(wxTR_ROW_LINES);
05513     XRC_ADD_STYLE(wxTR_HIDE_ROOT);
05514 
05515     XRC_ADD_STYLE(wxTR_FULL_ROW_HIGHLIGHT);
05516 
05517     XRC_ADD_STYLE(wxTR_DEFAULT_STYLE);
05518 
05519 // wxTreeListCtrl-specific styles
05520     XRC_ADD_STYLE(wxTR_COLUMN_LINES);
05521     XRC_ADD_STYLE(wxTR_VIRTUAL);
05522 
05523 // standard wxWidgets styles
05524         AddWindowStyles();
05525 }
05526 
05527 wxObject *wxTreeListCtrlXmlHandler::DoCreateResource() {
05528         XRC_MAKE_INSTANCE(tlc, wxTreeListCtrl);
05529         tlc->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName());
05530     SetupWindow(tlc);
05531         return tlc;
05532 }
05533 
05534 bool wxTreeListCtrlXmlHandler::CanHandle(wxXmlNode * node) {
05535         return IsOfClass(node, wxT("TreeListCtrl"));
05536 }
05537 
05538 #endif  // wxUSE_XRC
05539 
05540 #if wxCHECK_VERSION(2,9,0)
05541 } // namespace wxcode
05542 #endif

Generated on 26 May 2016 for Hugintrunk by  doxygen 1.4.7