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

Generated on 29 Apr 2017 for Hugintrunk by  doxygen 1.4.7