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     // store modifiers in extra long for Mac
03612     nevent.SetExtraLong(event.GetModifiers());
03613     if (SendEvent(0, NULL, &nevent)) return; // char event handled in user code
03614 
03615     // if no item current, select root
03616     bool curItemSet = false;
03617     if (!m_curItem) {
03618         if (! GetRootItem().IsOk()) return;
03619         SetCurrentItem((wxTreeListItem*)GetRootItem().m_pItem);
03620         if (HasFlag(wxTR_HIDE_ROOT)) {
03621             wxTreeItemIdValue cookie = 0;
03622             SetCurrentItem((wxTreeListItem*)GetFirstChild (m_curItem, cookie).m_pItem);
03623         }
03624         SelectItem(m_curItem, (wxTreeItemId*)NULL, true);  // unselect others
03625         curItemSet = true;
03626     }
03627 
03628     // remember item at shift down
03629     if (HasFlag(wxTR_MULTIPLE) && event.ShiftDown()) {
03630         if (!m_shiftItem) m_shiftItem = m_curItem;
03631     }else{
03632         m_shiftItem = (wxTreeListItem*)NULL;
03633     }
03634 
03635     if (curItemSet) return;  // if no item was current until now, do nothing more
03636 
03637     // process all cases
03638     wxTreeItemId newItem = (wxTreeItemId*)NULL;
03639     switch (event.GetKeyCode()) {
03640 
03641         // '+': Expand subtree
03642         case '+':
03643         case WXK_ADD: {
03644             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) Expand (m_curItem);
03645         }break;
03646 
03647         // '-': collapse subtree
03648         case '-':
03649         case WXK_SUBTRACT: {
03650             if (m_curItem->HasPlus() && IsExpanded (m_curItem)) Collapse (m_curItem);
03651         }break;
03652 
03653         // '*': expand/collapse all subtrees // TODO: Mak it more useful
03654         case '*':
03655         case WXK_MULTIPLY: {
03656             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
03657                 ExpandAll (m_curItem);
03658             }else if (m_curItem->HasPlus()) {
03659                 Collapse (m_curItem); // TODO: CollapseAll
03660             }
03661         }break;
03662 
03663         // ' ': toggle current item
03664         case ' ': {
03665             SelectItem (m_curItem, (wxTreeListItem*)NULL, false);
03666         }break;
03667 
03668         // <RETURN>: activate current item
03669         case WXK_RETURN: {
03670             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, m_curItem)) {
03671 
03672                 // if the user code didn't process the activate event,
03673                 // handle it ourselves by toggling the item when it is
03674                 // double clicked
03675                 if (m_curItem && m_curItem->HasPlus()) Toggle(m_curItem);
03676             }
03677         }break;
03678 
03679         // <BKSP>: go to the parent without collapsing
03680         case WXK_BACK: {
03681             newItem = GetItemParent (m_curItem);
03682             if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03683                 newItem = GetPrevSibling (m_curItem); // get sibling instead of root
03684             }
03685         }break;
03686 
03687         // <HOME>: go to first visible
03688         case WXK_HOME: {
03689             newItem = GetFirstVisible(false, false);
03690         }break;
03691 
03692         // <PAGE-UP>: go to the top of the page, or if we already are then one page back
03693         case WXK_PAGEUP: {
03694         int flags = 0;
03695         int col = 0;
03696         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,1));
03697         // PAGE-UP: first go the the first visible row
03698             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03699             newItem = GetFirstVisible(false, true);
03700         // if we are already there then scroll back one page
03701             if (newItem == m_curItem) {
03702                 abs_p.y -= GetClientSize().GetHeight() - m_curItem->GetHeight();
03703                 if (abs_p.y < 0) abs_p.y = 0;
03704                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03705             }
03706             // newItem should never be NULL
03707         } break;
03708 
03709         // <UP>: go to the previous sibling or for the last of its children, to the parent
03710         case WXK_UP: {
03711             newItem = GetPrevSibling (m_curItem);
03712             if (newItem) {
03713                 wxTreeItemIdValue cookie = 0;
03714                 while (IsExpanded (newItem) && HasChildren (newItem)) {
03715                     newItem = GetLastChild (newItem, cookie);
03716                 }
03717             }else {
03718                 newItem = GetItemParent (m_curItem);
03719                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03720                     newItem = (wxTreeItemId*)NULL; // don't go to root if it is hidden
03721                 }
03722             }
03723         }break;
03724 
03725         // <LEFT>: if expanded collapse subtree, else go to the parent
03726         case WXK_LEFT: {
03727             if (IsExpanded (m_curItem)) {
03728                 Collapse (m_curItem);
03729             }else{
03730                 newItem = GetItemParent (m_curItem);
03731                 if ((newItem == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) {
03732                     newItem = GetPrevSibling (m_curItem); // go to sibling if it is hidden
03733                 }
03734             }
03735         }break;
03736 
03737         // <RIGHT>: if possible expand subtree, else go go to the first child
03738         case WXK_RIGHT: {
03739             if (m_curItem->HasPlus() && !IsExpanded (m_curItem)) {
03740                 Expand (m_curItem);
03741             }else{
03742                 if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
03743                     wxTreeItemIdValue cookie = 0;
03744                     newItem = GetFirstChild (m_curItem, cookie);
03745                 }
03746             }
03747         }break;
03748 
03749         // <DOWN>: if expanded go to the first child, else to the next sibling, ect
03750         case WXK_DOWN: {
03751             if (IsExpanded (m_curItem) && HasChildren (m_curItem)) {
03752                 wxTreeItemIdValue cookie = 0;
03753                 newItem = GetFirstChild( m_curItem, cookie );
03754             }
03755             if (!newItem) {
03756                 wxTreeItemId parent = m_curItem;
03757                 do {
03758                     newItem = GetNextSibling (parent);
03759                     parent = GetItemParent (parent);
03760                 } while (!newItem && parent);
03761             }
03762         }break;
03763 
03764         // <PAGE-DOWN>: go to the bottom of the page, or if we already are then one page further
03765         case WXK_PAGEDOWN: {
03766         int flags = 0;
03767         int col = 0;
03768         wxPoint abs_p = CalcUnscrolledPosition (wxPoint(1,GetClientSize().GetHeight() - m_curItem->GetHeight()));
03769         // PAGE-UP: first go the the first visible row
03770             newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03771             newItem = GetLastVisible(false, true);
03772         // if we are already there then scroll down one page
03773             if (newItem == m_curItem) {
03774                 abs_p.y += GetClientSize().GetHeight() - m_curItem->GetHeight();
03775 //                if (abs_p.y >= GetVirtualSize().GetHeight()) abs_p.y = GetVirtualSize().GetHeight() - 1;
03776                 newItem = m_rootItem->HitTest(abs_p, this, flags, col, 0);
03777             }
03778         // if we reached the empty area below the rows, return last item instead
03779             if (! newItem) newItem = GetLastVisible(false, false);
03780         } break;
03781 
03782         // <END>: go to last item of the root
03783         case WXK_END: {
03784             newItem = GetLastVisible (false, false);
03785         }break;
03786 
03787         // any char: go to the next matching string
03788         default:
03789             wxChar key = event.GetUnicodeKey();
03790             if (key == WXK_NONE) key = (wxChar)event.GetKeyCode();
03791             if (key  >= 32) {
03792                 // prepare search parameters
03793                 int mode = wxTL_MODE_NAV_EXPANDED | wxTL_MODE_FIND_PARTIAL | wxTL_MODE_FIND_NOCASE;
03794                 if (!m_findTimer->IsRunning()) m_findStr.Clear();
03795                 m_findStr.Append (key);
03796                 m_findTimer->Start (FIND_TIMER_TICKS, wxTIMER_ONE_SHOT);
03797                 wxTreeItemId prev = (wxTreeItemId*)NULL;
03798                 // try if current item or one of its followers matches
03799                 if (m_curItem) {
03800                     prev = (wxTreeItemId*)m_curItem;
03801                     for (int col=0; col<=GetColumnCount() - 1; col++) {
03802                         if (MatchItemText(GetItemText(prev, col), m_findStr, mode)) {
03803                             newItem = prev;
03804                             break;
03805                         }
03806                     }
03807                     if (! newItem) {
03808                         newItem = FindItem (prev, -1, m_findStr, mode);
03809                     };
03810                 }
03811                 // current item or does not match: try to find next
03812                 // still not match: search from beginning (but only if there was a current item i.e.we did not start from root already)
03813                 if (! newItem) {
03814                     prev = (wxTreeItemId*)NULL;
03815                     newItem = FindItem (prev, -1, m_findStr, mode);
03816                 }
03817                 // no match at all: remove just typed char to allow try with another extension
03818                 if (! newItem) m_findStr.RemoveLast();
03819             }
03820             event.Skip();
03821 
03822     }
03823 
03824     // select and show the new item
03825     if (newItem) {
03826         if (!event.ControlDown()) {
03827             bool unselect_others = !((event.ShiftDown() || event.ControlDown()) &&
03828                                       HasFlag(wxTR_MULTIPLE));
03829             SelectItem (newItem, m_shiftItem, unselect_others);
03830         }
03831         EnsureVisible (newItem);
03832         wxTreeListItem *oldItem = m_curItem;
03833         SetCurrentItem((wxTreeListItem*)newItem.m_pItem); // make the new item the current item
03834         RefreshLine (oldItem);
03835     }
03836 
03837 }
03838 
03839 wxTreeItemId wxTreeListMainWindow::HitTest (const wxPoint& point, int& flags, int& column) {
03840 
03841     int w, h;
03842     GetSize(&w, &h);
03843     flags=0;
03844     column = -1;
03845     if (point.x<0) flags |= wxTREE_HITTEST_TOLEFT;
03846     if (point.x>w) flags |= wxTREE_HITTEST_TORIGHT;
03847     if (point.y<0) flags |= wxTREE_HITTEST_ABOVE;
03848     if (point.y>h) flags |= wxTREE_HITTEST_BELOW;
03849     if (flags) return wxTreeItemId();
03850 
03851     if (!m_rootItem) {
03852         flags = wxTREE_HITTEST_NOWHERE;
03853         column = -1;
03854         return wxTreeItemId();
03855     }
03856 
03857     wxTreeListItem *hit = m_rootItem->HitTest (CalcUnscrolledPosition(point),
03858                                                this, flags, column, 0);
03859     if (!hit) {
03860         flags = wxTREE_HITTEST_NOWHERE;
03861         column = -1;
03862         return wxTreeItemId();
03863     }
03864     return hit;
03865 }
03866 
03867 // get the bounding rectangle of the item (or of its label only)
03868 bool wxTreeListMainWindow::GetBoundingRect (const wxTreeItemId& itemId, wxRect& rect,
03869                                             bool WXUNUSED(textOnly)) const {
03870     wxCHECK_MSG (itemId.IsOk(), false, _T("invalid item in wxTreeListMainWindow::GetBoundingRect") );
03871 
03872     wxTreeListItem *item = (wxTreeListItem*) itemId.m_pItem;
03873 
03874     int xUnit, yUnit;
03875     GetScrollPixelsPerUnit (&xUnit, &yUnit);
03876     int startX, startY;
03877     GetViewStart(& startX, & startY);
03878 
03879     rect.x = item->GetX() - startX * xUnit;
03880     rect.y = item->GetY() - startY * yUnit;
03881     rect.width = item->GetWidth();
03882     rect.height = GetLineHeight (item);
03883 
03884     return true;
03885 }
03886 
03887 /* **** */
03888 
03889 void wxTreeListMainWindow::EditLabel (const wxTreeItemId& item, int column) {
03890 
03891 // validate
03892     if (!item.IsOk()) return;
03893     if (!((column >= 0) && (column < GetColumnCount()))) return;
03894 
03895 // cancel any editing
03896     if (m_editControl) { m_editControl->EndEdit(true); }  // cancelled
03897 
03898 // prepare edit (position)
03899     m_editItem = (wxTreeListItem*) item.m_pItem;
03900 
03901     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, 0 );
03902     te.SetInt (column);
03903     SendEvent(0, m_editItem, &te); if (!te.IsAllowed()) return;
03904 
03905     // ensure that the position of the item it calculated in any case
03906     if (m_dirty) CalculatePositions();
03907 
03908     wxTreeListHeaderWindow* header_win = m_owner->GetHeaderWindow();
03909 
03910     // position & size are rather unpredictable (tsssk, tssssk) so were
03911     //  set by trial & error (on Win 2003 pre-XP style)
03912     int x = 0;
03913     int w = +4;  // +4 is necessary, don't know why (simple border erronously counted somewhere ?)
03914     int y = m_editItem->GetY() + 1;  // this is cell, not text
03915     int h = m_editItem->GetHeight() - 1;  // consequence from above
03916     long style = 0;
03917     if (column == GetMainColumn()) {
03918         x += m_editItem->GetTextX(column) - 2;  // wrong by 2, don't know why
03919         w += m_editItem->GetWidth();
03920     } else {
03921         for (int i = 0; i < column; ++i) {
03922             if ( header_win->IsColumnShown(i) ) {
03923                 x += header_win->GetColumnWidth (i); // start of column
03924             }
03925                 }
03926         w += header_win->GetColumnWidth (column);  // currently non-main column width not pre-computed
03927     }
03928     switch (header_win->GetColumnAlignment (column)) {
03929         case wxALIGN_LEFT:   {style = wxTE_LEFT;   x -= 1; break;}
03930         case wxALIGN_CENTER: {style = wxTE_CENTER; x -= 1; break;}
03931         case wxALIGN_RIGHT:  {style = wxTE_RIGHT;  x += 0; break;}  // yes, strange but that's the way it is
03932     }
03933     // wxTextCtrl simple border style requires 2 extra pixels before and after
03934     //  (measured by changing to style wxNO_BORDER in wxEditTextCtrl::wxEditTextCtrl() )
03935     y -= 2; x -= 2;
03936     w += 4; h += 4;
03937 
03938     wxClientDC dc (this);
03939     PrepareDC (dc);
03940     x = dc.LogicalToDeviceX (x);
03941     y = dc.LogicalToDeviceY (y);
03942 
03943 // now do edit (change state, show control)
03944     m_editCol = column;  // only used in OnRenameAccept()
03945     m_editControl = new wxEditTextCtrl (this, -1, &m_editAccept, &m_editRes,
03946                                                this, m_editItem->GetText (column),
03947                                                wxPoint (x, y), wxSize (w, h), style);
03948     m_editControl->SelectAll();
03949     m_editControl->SetFocus();
03950 }
03951 
03952 void wxTreeListMainWindow::OnRenameTimer() {
03953     EditLabel (m_curItem, GetCurrentColumn());
03954 }
03955 
03956 void wxTreeListMainWindow::OnRenameAccept(bool isCancelled) {
03957 
03958     // TODO if the validator fails this causes a crash
03959     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, 0 );
03960     le.SetLabel( m_editRes );
03961     le.SetEditCanceled(isCancelled);
03962     le.SetInt(m_editCol);
03963     SendEvent(0, m_editItem, &le); if (! isCancelled  && le.IsAllowed())
03964     {
03965         SetItemText (m_editItem, le.GetInt(), le.GetLabel());
03966     }
03967 }
03968 
03969 void wxTreeListMainWindow::EndEdit(bool isCancelled) {
03970     if (m_editControl) { m_editControl->EndEdit(true); }
03971 }
03972 
03973 void wxTreeListMainWindow::OnMouse (wxMouseEvent &event) {
03974 bool mayDrag = true;
03975 bool maySelect = true;  // may change selection
03976 bool mayClick = true;  // may process DOWN clicks to expand, send click events
03977 bool mayDoubleClick = true;  // implies mayClick
03978 bool bSkip = true;
03979 
03980     // send event to user code
03981     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
03982     if (!m_rootItem) return;
03983 
03984 
03985 // ---------- DETERMINE EVENT ----------
03986 /*
03987 wxLogMessage("OnMouse: LMR down=<%d, %d, %d> up=<%d, %d, %d> LDblClick=<%d> dragging=<%d>",
03988     event.LeftDown(), event.MiddleDown(), event.RightDown(),
03989     event.LeftUp(), event.MiddleUp(), event.RightUp(),
03990     event.LeftDClick(), event.Dragging());
03991 */
03992     wxPoint p = wxPoint (event.GetX(), event.GetY());
03993     int flags = 0;
03994     wxTreeListItem *item = m_rootItem->HitTest (CalcUnscrolledPosition (p),
03995                                                 this, flags, m_curColumn, 0);
03996     bool bCrosshair = (item && item->HasPlus() && (flags & wxTREE_HITTEST_ONITEMBUTTON));
03997     // we were dragging
03998     if (m_isDragging) {
03999         maySelect = mayDoubleClick = false;
04000     }
04001     // we are starting or continuing to drag
04002     if (event.Dragging()) {
04003         maySelect = mayDoubleClick = mayClick = false;
04004     }
04005     // crosshair area is special
04006     if (bCrosshair) {
04007         // left click does not select
04008         if (event.LeftDown()) maySelect = false;
04009         // double click is ignored
04010         mayDoubleClick = false;
04011     }
04012     // double click only if simple click
04013     if (mayDoubleClick) mayDoubleClick = mayClick;
04014     // selection conditions --remember also that selection exludes editing
04015     if (maySelect) maySelect = mayClick;  // yes, select/unselect requires a click
04016     if (maySelect) {
04017 
04018         // multiple selection mode complicates things, sometimes we
04019         //  select on button-up instead of down:
04020         if (HasFlag(wxTR_MULTIPLE)) {
04021 
04022             // CONTROL/SHIFT key used, don't care about anything else, will
04023             //  toggle on key down
04024             if (event.ControlDown() || event.ShiftDown()) {
04025                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04026                 m_lastOnSame = false;  // prevent editing when keys are used
04027 
04028             // already selected item: to allow drag or contextual menu for multiple
04029             //  items, we only select/unselect on click-up --and only on LEFT
04030             // click, right is reserved for contextual menu
04031             } else if ((item != NULL && item->IsSelected())) {
04032                 maySelect = maySelect && event.LeftUp();
04033 
04034             // non-selected items: select on click-down like simple select (so
04035             //  that a right-click contextual menu may be chained)
04036             } else {
04037                 maySelect = maySelect && (event.LeftDown() || event.RightDown());
04038             }
04039 
04040         // single-select is simply on left or right click-down
04041         } else {
04042             maySelect = maySelect && (event.LeftDown() || event.RightDown());
04043         }
04044     }
04045 
04046 
04047 // ----------  GENERAL ACTIONS  ----------
04048 
04049     // set focus if window clicked
04050     if (event.LeftDown() || event.MiddleDown() || event.RightDown()) SetFocus();
04051 
04052     // tooltip change ?
04053     if (item != m_toolTipItem) {
04054 
04055         // not over an item, use global tip
04056         if (item == NULL) {
04057             m_toolTipItem = NULL;
04058             wxScrolledWindow::SetToolTip(m_toolTip);
04059 
04060         // over an item
04061         } else {
04062             const wxString *tip = item->GetToolTip();
04063 
04064             // is there an item-specific tip ?
04065             if (tip) {
04066                 m_toolTipItem = item;
04067                 wxScrolledWindow::SetToolTip(*tip);
04068 
04069             // no item tip, but we are in item-specific mode (SetItemToolTip()
04070             //  was called after SetToolTip() )
04071             } else if (m_isItemToolTip) {
04072                 m_toolTipItem = item;
04073                 wxScrolledWindow::SetToolTip(wxString());
04074 
04075             // no item tip, display global tip instead; item change ignored
04076             } else if (m_toolTipItem != NULL) {
04077                 m_toolTipItem = NULL;
04078                 wxScrolledWindow::SetToolTip(m_toolTip);
04079             }
04080         }
04081     }
04082 
04083 
04084 // ----------  HANDLE SIMPLE-CLICKS  (selection change, contextual menu) ----------
04085     if (mayClick) {
04086 
04087         // 2nd left-click on an item might trigger edit
04088         if (event.LeftDown()) m_lastOnSame = (item == m_curItem);
04089 
04090         // left-click on haircross is expand (and no select)
04091         if (bCrosshair && event.LeftDown()) {
04092 
04093             bSkip = false;
04094 
04095             // note that we only toggle the item for a single click, double
04096             // click on the button doesn't do anything
04097             Toggle (item);
04098         }
04099 
04100         if (maySelect) {
04101             bSkip = false;
04102 
04103             // set / remember item at shift down before current item gets changed
04104             if (event.LeftDown() && HasFlag(wxTR_MULTIPLE) && event.ShiftDown())  {
04105                 if (!m_shiftItem) m_shiftItem = m_curItem;
04106             }else{
04107                 m_shiftItem = (wxTreeListItem*)NULL;
04108             }
04109 
04110             // how is selection altered
04111             // keep or discard already selected ?
04112             bool unselect_others = ! (HasFlag(wxTR_MULTIPLE) && (
04113                 event.ShiftDown()
04114              || event.ControlDown()
04115             ));
04116 
04117             // check is selection change is not vetoed
04118             if (SelectItem(item, m_shiftItem, unselect_others)) {
04119                 // make the new item the current item
04120                 EnsureVisible (item);
04121                 SetCurrentItem(item);
04122             }
04123         }
04124 
04125         // generate click & menu events
04126         if (event.MiddleDown()) {
04127             // our own event to set point
04128             wxTreeEvent nevent(0, 0);
04129             nevent.SetPoint(p);
04130             nevent.SetInt(m_curColumn);
04131             bSkip = false;
04132             SendEvent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK, item, &nevent);
04133         }
04134         if (event.RightDown()) {
04135             // our own event to set point
04136             wxTreeEvent nevent(0, 0);
04137             nevent.SetPoint(p);
04138             nevent.SetInt(m_curColumn);
04139             bSkip = false;
04140             SendEvent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, item, &nevent);
04141         }
04142         if (event.RightUp()) {
04143             // our own event to set point
04144             wxTreeEvent nevent(0, 0);
04145             nevent.SetPoint(p);
04146             nevent.SetInt(m_curColumn);
04147             SendEvent(wxEVT_COMMAND_TREE_ITEM_MENU, item, &nevent);
04148         }
04149 
04150         // if 2nd left click finishes on same item, will edit it
04151         if (m_lastOnSame && event.LeftUp()) {
04152             if ((item == m_curItem) && (m_curColumn != -1) &&
04153                 (m_owner->GetHeaderWindow()->IsColumnEditable (m_curColumn)) &&
04154                 (flags & (wxTREE_HITTEST_ONITEMLABEL | wxTREE_HITTEST_ONITEMCOLUMN))
04155             ){
04156                 m_editTimer->Start (RENAME_TIMER_TICKS, wxTIMER_ONE_SHOT);
04157                 bSkip = false;
04158             }
04159             m_lastOnSame = false;
04160         }
04161     }
04162 
04163 
04164 // ----------  HANDLE DOUBLE-CLICKS  ----------
04165     if (mayDoubleClick && event.LeftDClick()) {
04166 
04167         bSkip = false;
04168 
04169         // double clicking should not start editing the item label
04170         m_editTimer->Stop();
04171         m_lastOnSame = false;
04172 
04173         // selection reset to that single item which was double-clicked
04174         if (SelectItem(item, (wxTreeItemId*)NULL, true)) {  // unselect others --return false if vetoed
04175 
04176             // selection change not vetoed, send activate event
04177             if (! SendEvent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, item)) {
04178 
04179                 // if the user code didn't process the activate event,
04180                 // handle it ourselves by toggling the item when it is
04181                 // double clicked
04182                 if (item && item->HasPlus()) Toggle(item);
04183             }
04184         }
04185     }
04186 
04187 
04188 // ----------  HANDLE DRAGGING  ----------
04189 // NOTE: drag itself makes no change to selection
04190     if (mayDrag) {  // actually this is always true
04191 
04192         // CASE 1: we were dragging => continue, end, abort
04193         if (m_isDragging) {
04194 
04195             // CASE 1.1: click aborts drag:
04196             if (event.LeftDown() || event.MiddleDown() || event.RightDown()) {
04197 
04198                 bSkip = false;
04199 
04200                 // stop dragging
04201                 m_isDragStarted = m_isDragging = false;
04202                 if (HasCapture()) ReleaseMouse();
04203                 RefreshSelected();
04204 
04205             // CASE 1.2: still dragging
04206             } else if (event.Dragging()) {
04207 
04208                 ;; // nothing to do
04209 
04210             // CASE 1.3: dragging now ends normally
04211             } else {
04212 
04213                 bSkip = false;
04214 
04215                 // stop dragging
04216                 m_isDragStarted = m_isDragging = false;
04217                 if (HasCapture()) ReleaseMouse();
04218                 RefreshSelected();
04219 
04220                 // send drag end event
04221                 // our own event to set point
04222                 wxTreeEvent nevent(0, 0);
04223                 nevent.SetPoint(p);
04224                 nevent.SetInt(m_curColumn);
04225                 SendEvent(wxEVT_COMMAND_TREE_END_DRAG, item, &nevent);
04226             }
04227 
04228         // CASE 2: not were not dragging => continue, start
04229         } else if (event.Dragging()) {
04230 
04231             // We will really start dragging if we've moved beyond a few pixels
04232             if (m_isDragStarted) {
04233                 const int tolerance = 3;
04234                 int dx = abs(p.x - m_dragStartPos.x);
04235                 int dy = abs(p.y - m_dragStartPos.y);
04236                 if (dx <= tolerance && dy <= tolerance)
04237                     return;
04238             // determine drag start
04239             } else {
04240                 m_dragStartPos = p;
04241                 m_dragCol = GetCurrentColumn();
04242                 m_dragItem = item;
04243                 m_isDragStarted = true;
04244                 return;
04245             }
04246 
04247             bSkip = false;
04248 
04249             // we are now dragging
04250             m_isDragging = true;
04251             RefreshSelected();
04252             CaptureMouse(); // TODO: usefulness unclear
04253 
04254             wxTreeEvent nevent(0, 0);
04255             nevent.SetPoint(p);
04256             nevent.SetInt(m_dragCol);
04257             nevent.Veto();
04258             SendEvent(event.LeftIsDown()
04259                                   ? wxEVT_COMMAND_TREE_BEGIN_DRAG
04260                                   : wxEVT_COMMAND_TREE_BEGIN_RDRAG,
04261                       m_dragItem, &nevent);
04262         }
04263     }
04264 
04265 
04266     if (bSkip) event.Skip();
04267 }
04268 
04269 
04270 void wxTreeListMainWindow::OnIdle (wxIdleEvent &WXUNUSED(event)) {
04271     /* after all changes have been done to the tree control,
04272      * we actually redraw the tree when everything is over */
04273 
04274     if (!m_dirty) return;
04275 
04276     m_dirty = false;
04277 
04278     CalculatePositions();
04279     Refresh();
04280     AdjustMyScrollbars();
04281 }
04282 
04283 void wxTreeListMainWindow::OnScroll (wxScrollWinEvent& event) {
04284 
04285     // send event to wxTreeListCtrl (for user code)
04286     if (m_owner->GetEventHandler()->ProcessEvent(event)) return; // handled (and not skipped) in user code
04287 
04288     // TODO
04289     HandleOnScroll( event );
04290 
04291     if(event.GetOrientation() == wxHORIZONTAL) {
04292         m_owner->GetHeaderWindow()->Refresh();
04293         m_owner->GetHeaderWindow()->Update();
04294     }
04295 }
04296 
04297 void wxTreeListMainWindow::CalculateSize (wxTreeListItem *item, wxDC &dc) {
04298     wxCoord text_w = 0;
04299     wxCoord text_h = 0;
04300 
04301     dc.SetFont (GetItemFont (item));
04302     dc.GetTextExtent (item->GetText(m_main_column).size() > 0
04303             ? item->GetText (m_main_column)
04304             : _T(" "),  // blank to avoid zero height and no highlight width
04305         &text_w, &text_h);
04306     // restore normal font
04307     dc.SetFont (m_normalFont);
04308 
04309     int max_h = (m_imgHeight > text_h) ? m_imgHeight : text_h;
04310     if (max_h < 30) { // add 10% space if greater than 30 pixels
04311         max_h += 2; // minimal 2 pixel space
04312     }else{
04313         max_h += max_h / 10; // otherwise 10% space
04314     }
04315 
04316     item->SetHeight (max_h);
04317     if (max_h > m_lineHeight) m_lineHeight = max_h;
04318     item->SetWidth(m_imgWidth + text_w+2);
04319 }
04320 
04321 // -----------------------------------------------------------------------------
04322 void wxTreeListMainWindow::CalculateLevel (wxTreeListItem *item, wxDC &dc,
04323                                            int level, int &y, int x_colstart) {
04324 
04325     // calculate position of vertical lines
04326     int x = x_colstart + MARGIN; // start of column
04327     if (HasFlag(wxTR_LINES_AT_ROOT)) x += LINEATROOT; // space for lines at root
04328     if (HasButtons()) {
04329         x += (m_btnWidth-m_btnWidth2); // half button space
04330     }else{
04331         x += (m_indent-m_indent/2);
04332     }
04333     if (HasFlag(wxTR_HIDE_ROOT)) {
04334         x += m_indent * (level-1); // indent but not level 1
04335     }else{
04336         x += m_indent * level; // indent according to level
04337     }
04338 
04339     // a hidden root is not evaluated, but its children are always
04340     if (HasFlag(wxTR_HIDE_ROOT) && (level == 0)) goto Recurse;
04341 
04342     CalculateSize( item, dc );
04343 
04344     // set its position
04345     item->SetX (x);
04346     item->SetY (y);
04347     y += GetLineHeight(item);
04348 
04349     // we don't need to calculate collapsed branches
04350     if ( !item->IsExpanded() ) return;
04351 
04352 Recurse:
04353     wxArrayTreeListItems& children = item->GetChildren();
04354     long n, count = (long)children.Count();
04355     ++level;
04356     for (n = 0; n < count; ++n) {
04357         CalculateLevel( children[n], dc, level, y, x_colstart );  // recurse
04358     }
04359 }
04360 
04361 void wxTreeListMainWindow::CalculatePositions() {
04362     if ( !m_rootItem ) return;
04363 
04364     wxClientDC dc(this);
04365     PrepareDC( dc );
04366 
04367     dc.SetFont( m_normalFont );
04368 
04369     dc.SetPen( m_dottedPen );
04370     //if(GetImageList() == NULL)
04371     // m_lineHeight = (int)(dc.GetCharHeight() + 4);
04372 
04373     int y = 2;
04374     int x_colstart = 0;
04375     for (int i = 0; i < (int)GetMainColumn(); ++i) {
04376         if (!m_owner->GetHeaderWindow()->IsColumnShown(i)) continue;
04377         x_colstart += m_owner->GetHeaderWindow()->GetColumnWidth(i);
04378     }
04379     CalculateLevel( m_rootItem, dc, 0, y, x_colstart ); // start recursion
04380 }
04381 
04382 void wxTreeListMainWindow::RefreshSubtree (wxTreeListItem *item) {
04383     if (m_dirty) return;
04384 
04385     wxClientDC dc(this);
04386     PrepareDC(dc);
04387 
04388     int cw = 0;
04389     int ch = 0;
04390     GetVirtualSize( &cw, &ch );
04391 
04392     wxRect rect;
04393     rect.x = dc.LogicalToDeviceX( 0 );
04394     rect.width = cw;
04395     rect.y = dc.LogicalToDeviceY( item->GetY() - 2 );
04396     rect.height = ch;
04397 
04398     Refresh (true, &rect );
04399     AdjustMyScrollbars();
04400 }
04401 
04402 void wxTreeListMainWindow::RefreshLine (wxTreeListItem *item) {
04403     if (m_dirty) return;
04404 
04405     wxClientDC dc(this);
04406     PrepareDC( dc );
04407 
04408     int cw = 0;
04409     int ch = 0;
04410     GetVirtualSize( &cw, &ch );
04411 
04412     wxRect rect;
04413     rect.x = dc.LogicalToDeviceX( 0 );
04414     rect.y = dc.LogicalToDeviceY( item->GetY() );
04415     rect.width = cw;
04416     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
04417 
04418     Refresh (true, &rect);
04419 }
04420 
04421 void wxTreeListMainWindow::RefreshSelected() {
04422     // TODO: this is awfully inefficient, we should keep the list of all
04423     //       selected items internally, should be much faster
04424     if (m_rootItem) {
04425         RefreshSelectedUnder (m_rootItem);
04426     }
04427 }
04428 
04429 void wxTreeListMainWindow::RefreshSelectedUnder (wxTreeListItem *item) {
04430     if (item->IsSelected()) {
04431         RefreshLine (item);
04432     }
04433 
04434     const wxArrayTreeListItems& children = item->GetChildren();
04435     long count = (long)children.GetCount();
04436     for (long n = 0; n < count; n++ ) {
04437         RefreshSelectedUnder (children[n]);
04438     }
04439 }
04440 
04441 // ----------------------------------------------------------------------------
04442 // changing colours: we need to refresh the tree control
04443 // ----------------------------------------------------------------------------
04444 
04445 bool wxTreeListMainWindow::SetBackgroundColour (const wxColour& colour) {
04446     if (!wxWindow::SetBackgroundColour(colour)) return false;
04447 
04448     Refresh();
04449     return true;
04450 }
04451 
04452 bool wxTreeListMainWindow::SetForegroundColour (const wxColour& colour) {
04453     if (!wxWindow::SetForegroundColour(colour)) return false;
04454 
04455     Refresh();
04456     return true;
04457 }
04458 
04459 void wxTreeListMainWindow::SetItemText (const wxTreeItemId& itemId, int column, const wxString& text) {
04460     wxCHECK_RET (itemId.IsOk(), _T("invalid tree item"));
04461 
04462     if (this->IsFrozen())
04463     {
04464         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04465         item->SetText(column, text);
04466         m_dirty = true;
04467     }
04468     else
04469     {
04470         wxClientDC dc(this);
04471         wxTreeListItem *item = (wxTreeListItem*)itemId.m_pItem;
04472         item->SetText(column, text);
04473         CalculateSize(item, dc);
04474         RefreshLine(item);
04475     };
04476 }
04477 
04478 wxString wxTreeListMainWindow::GetItemText (const wxTreeItemId& itemId, int column) const {
04479     wxCHECK_MSG (itemId.IsOk(), _T(""), _T("invalid tree item") );
04480 
04481     if( IsVirtual() )   return m_owner->OnGetItemText(((wxTreeListItem*) itemId.m_pItem)->GetData(),column);
04482     else                return ((wxTreeListItem*) itemId.m_pItem)->GetText (column);
04483 }
04484 
04485 wxString wxTreeListMainWindow::GetItemText (wxTreeItemData* item, int column) const {
04486    wxASSERT_MSG( IsVirtual(), _T("can be used only with virtual control") );
04487    return m_owner->OnGetItemText(item, column);
04488 }
04489 
04490 void wxTreeListMainWindow::SetFocus() {
04491     wxWindow::SetFocus();
04492 }
04493 
04494 
04495 int wxTreeListMainWindow::GetItemWidth (int column, wxTreeListItem *item) {
04496     if (!item) return 0;
04497 
04498     // determine item width
04499     int w = 0, h = 0;
04500     wxFont font = GetItemFont (item);
04501     GetTextExtent (item->GetText (column), &w, &h, NULL, NULL, font.Ok()? &font: NULL);
04502     w += 2*MARGIN;
04503 
04504     // calculate width
04505     int width = w + 2*MARGIN;
04506     if (column == GetMainColumn()) {
04507         width += MARGIN;
04508         if (HasFlag(wxTR_LINES_AT_ROOT)) width += LINEATROOT;
04509         if (HasButtons()) width += m_btnWidth + LINEATROOT;
04510         if (item->GetCurrentImage() != NO_IMAGE) width += m_imgWidth;
04511 
04512         // count indent level
04513         int level = 0;
04514         wxTreeListItem *parent = item->GetItemParent();
04515         wxTreeListItem *root = (wxTreeListItem*)GetRootItem().m_pItem;
04516         while (parent && (!HasFlag(wxTR_HIDE_ROOT) || (parent != root))) {
04517             level++;
04518             parent = parent->GetItemParent();
04519         }
04520         if (level) width += level * GetIndent();
04521     }
04522 
04523     return width;
04524 }
04525 
04526 int wxTreeListMainWindow::GetBestColumnWidth (int column, wxTreeItemId parent) {
04527     int maxWidth, h;
04528     GetClientSize (&maxWidth, &h);
04529     int width = 0;
04530 
04531     // get root if on item
04532     if (!parent.IsOk()) parent = GetRootItem();
04533 
04534     // add root width
04535     if (!HasFlag(wxTR_HIDE_ROOT)) {
04536         int w = GetItemWidth (column, (wxTreeListItem*)parent.m_pItem);
04537         if (width < w) width = w;
04538         if (width > maxWidth) return maxWidth;
04539     }
04540 
04541     wxTreeItemIdValue cookie = 0;
04542     wxTreeItemId item = GetFirstChild (parent, cookie);
04543     while (item.IsOk()) {
04544         int w = GetItemWidth (column, (wxTreeListItem*)item.m_pItem);
04545         if (width < w) width = w;
04546         if (width > maxWidth) return maxWidth;
04547 
04548         // check the children of this item
04549         if (((wxTreeListItem*)item.m_pItem)->IsExpanded()) {
04550             int w = GetBestColumnWidth (column, item);
04551             if (width < w) width = w;
04552             if (width > maxWidth) return maxWidth;
04553         }
04554 
04555         // next sibling
04556         item = GetNextChild (parent, cookie);
04557     }
04558 
04559     return width;
04560 }
04561 
04562 
04563 bool wxTreeListMainWindow::SendEvent(wxEventType event_type, wxTreeListItem *item, wxTreeEvent *event) {
04564 wxTreeEvent nevent (event_type, 0);
04565 
04566     if (event == NULL) {
04567         event = &nevent;
04568         event->SetInt (m_curColumn); // the mouse colum
04569     } else if (event_type) {
04570         event->SetEventType(event_type);
04571     }
04572 
04573     event->SetEventObject (m_owner);
04574     event->SetId(m_owner->GetId());
04575     if (item) {
04576         event->SetItem (item);
04577     }
04578 
04579     return m_owner->GetEventHandler()->ProcessEvent (*event);
04580 }
04581 
04582 
04583 //-----------------------------------------------------------------------------
04584 //  wxTreeListCtrl
04585 //-----------------------------------------------------------------------------
04586 
04587 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrl, wxControl);
04588 
04589 BEGIN_EVENT_TABLE(wxTreeListCtrl, wxControl)
04590     EVT_SIZE(wxTreeListCtrl::OnSize)
04591 END_EVENT_TABLE();
04592 
04593 bool wxTreeListCtrl::Create(wxWindow *parent, wxWindowID id,
04594                             const wxPoint& pos,
04595                             const wxSize& size,
04596                             long style, const wxValidator &validator,
04597                             const wxString& name)
04598 {
04599     long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE |
04600                                 wxBORDER_RAISED | wxBORDER_STATIC);
04601     main_style |= wxWANTS_CHARS ;
04602     long ctrl_style = style & ~(wxVSCROLL|wxHSCROLL);
04603 
04604     if (!wxControl::Create(parent, id, pos, size, ctrl_style, validator, name)) {
04605        return false;
04606     }
04607     m_main_win = new wxTreeListMainWindow (this, -1, wxPoint(0, 0), size,
04608                                            main_style, validator);
04609     m_header_win = new wxTreeListHeaderWindow (this, -1, m_main_win,
04610                                                wxPoint(0, 0), wxDefaultSize,
04611                                                wxTAB_TRAVERSAL);
04612     CalculateAndSetHeaderHeight();
04613     return true;
04614 }
04615 
04616 void wxTreeListCtrl::CalculateAndSetHeaderHeight()
04617 {
04618     if (m_header_win) {
04619 
04620         // we use 'g' to get the descent, too
04621         int h;
04622 #ifdef __WXMSW__
04623         h = (int)(wxRendererNative::Get().GetHeaderButtonHeight(m_header_win) * 0.8) + 2;
04624 #else
04625         h = wxRendererNative::Get().GetHeaderButtonHeight(m_header_win);
04626 #endif
04627 
04628         // only update if changed
04629         if (h != m_headerHeight) {
04630             m_headerHeight = h;
04631             DoHeaderLayout();
04632         }
04633     }
04634 }
04635 
04636 void wxTreeListCtrl::DoHeaderLayout()
04637 {
04638     int w, h;
04639     GetClientSize(&w, &h);
04640     if (m_header_win) {
04641         m_header_win->SetSize (0, 0, w, m_headerHeight);
04642         m_header_win->Refresh();
04643     }
04644     if (m_main_win) {
04645         m_main_win->SetSize (0, m_headerHeight, w, h - m_headerHeight);
04646     }
04647 }
04648 
04649 void wxTreeListCtrl::OnSize(wxSizeEvent& WXUNUSED(event))
04650 {
04651     DoHeaderLayout();
04652 }
04653 
04654 size_t wxTreeListCtrl::GetCount() const { return m_main_win->GetCount(); }
04655 
04656 unsigned int wxTreeListCtrl::GetIndent() const
04657 { return m_main_win->GetIndent(); }
04658 
04659 void wxTreeListCtrl::SetIndent(unsigned int indent)
04660 { m_main_win->SetIndent(indent); }
04661 
04662 unsigned int wxTreeListCtrl::GetLineSpacing() const
04663 { return m_main_win->GetLineSpacing(); }
04664 
04665 void wxTreeListCtrl::SetLineSpacing(unsigned int spacing)
04666 { m_main_win->SetLineSpacing(spacing); }
04667 
04668 wxImageList* wxTreeListCtrl::GetImageList() const
04669 { return m_main_win->GetImageList(); }
04670 
04671 wxImageList* wxTreeListCtrl::GetStateImageList() const
04672 { return m_main_win->GetStateImageList(); }
04673 
04674 wxImageList* wxTreeListCtrl::GetButtonsImageList() const
04675 { return m_main_win->GetButtonsImageList(); }
04676 
04677 void wxTreeListCtrl::SetImageList(wxImageList* imageList)
04678 { m_main_win->SetImageList(imageList); }
04679 
04680 void wxTreeListCtrl::SetStateImageList(wxImageList* imageList)
04681 { m_main_win->SetStateImageList(imageList); }
04682 
04683 void wxTreeListCtrl::SetButtonsImageList(wxImageList* imageList)
04684 { m_main_win->SetButtonsImageList(imageList); }
04685 
04686 void wxTreeListCtrl::AssignImageList(wxImageList* imageList)
04687 { m_main_win->AssignImageList(imageList); }
04688 
04689 void wxTreeListCtrl::AssignStateImageList(wxImageList* imageList)
04690 { m_main_win->AssignStateImageList(imageList); }
04691 
04692 void wxTreeListCtrl::AssignButtonsImageList(wxImageList* imageList)
04693 { m_main_win->AssignButtonsImageList(imageList); }
04694 
04695 
04696 
04697 wxString wxTreeListCtrl::GetItemText(const wxTreeItemId& item, int column) const
04698 { return m_main_win->GetItemText (item, column); }
04699 
04700 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, wxTreeItemIcon which) const
04701 { return m_main_win->GetItemImage(item, which); }
04702 int wxTreeListCtrl::GetItemImage(const wxTreeItemId& item, int column) const
04703 { return m_main_win->GetItemImage(item, column); }
04704 
04705 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item) const
04706 { return m_main_win->GetItemData(item); }
04707 wxTreeItemData* wxTreeListCtrl::GetItemData(const wxTreeItemId& item, int column) const
04708 { return m_main_win->GetItemData(item, column); }
04709 
04710 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item) const
04711 { return m_main_win->GetItemBold(item); }
04712 bool wxTreeListCtrl::GetItemBold(const wxTreeItemId& item, int column) const
04713 { return m_main_win->GetItemBold(item, column); }
04714 
04715 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item) const
04716 { return m_main_win->GetItemTextColour(item); }
04717 wxColour wxTreeListCtrl::GetItemTextColour(const wxTreeItemId& item, int column) const
04718 { return m_main_win->GetItemTextColour(item, column); }
04719 
04720 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
04721 { return m_main_win->GetItemBackgroundColour(item); }
04722 wxColour wxTreeListCtrl::GetItemBackgroundColour(const wxTreeItemId& item, int column) const
04723 { return m_main_win->GetItemBackgroundColour(item, column); }
04724 
04725 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item) const
04726 { return m_main_win->GetItemFont(item); }
04727 wxFont wxTreeListCtrl::GetItemFont(const wxTreeItemId& item, int column) const
04728 { return m_main_win->GetItemFont(item, column); }
04729 
04730 
04731 
04732 void wxTreeListCtrl::SetItemHasChildren(const wxTreeItemId& item, bool has)
04733 { m_main_win->SetItemHasChildren(item, has); }
04734 
04735 void wxTreeListCtrl::SetItemText(const wxTreeItemId& item, int column, const wxString& text)
04736 { m_main_win->SetItemText (item, column, text); }
04737 
04738 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int image, wxTreeItemIcon which)
04739 { m_main_win->SetItemImage(item, image, which); }
04740 void wxTreeListCtrl::SetItemImage(const wxTreeItemId& item, int column, int image)
04741 { m_main_win->SetItemImage(item, column, image); }
04742 
04743 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item,             wxTreeItemData* data)
04744 { m_main_win->SetItemData(item, data); }
04745 void wxTreeListCtrl::SetItemData(const wxTreeItemId& item, int column, wxTreeItemData* data)
04746 { m_main_win->SetItemData(item, column, data); }
04747 
04748 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item,             bool bold)
04749 { m_main_win->SetItemBold(item, bold); }
04750 void wxTreeListCtrl::SetItemBold(const wxTreeItemId& item, int column, bool bold)
04751 { m_main_win->SetItemBold(item, column, bold); }
04752 
04753 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item,              const wxColour& colour)
04754 { m_main_win->SetItemTextColour(item, colour); }
04755 void wxTreeListCtrl::SetItemTextColour(const wxTreeItemId& item, int column, const wxColour& colour)
04756 { m_main_win->SetItemTextColour(item, column, colour); }
04757 
04758 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item,             const wxColour& colour)
04759 { m_main_win->SetItemBackgroundColour(item, colour); }
04760 void wxTreeListCtrl::SetItemBackgroundColour(const wxTreeItemId& item, int column, const wxColour& colour)
04761 { m_main_win->SetItemBackgroundColour(item, column, colour); }
04762 
04763 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item,             const wxFont& font)
04764 { m_main_win->SetItemFont(item, font); }
04765 void wxTreeListCtrl::SetItemFont(const wxTreeItemId& item, int column, const wxFont& font)
04766 { m_main_win->SetItemFont(item, column, font); }
04767 
04768 
04769 
04770 bool wxTreeListCtrl::SetFont(const wxFont& font)
04771 {
04772     if (m_header_win) {
04773         m_header_win->SetFont(font);
04774         CalculateAndSetHeaderHeight();
04775         m_header_win->Refresh();
04776     }
04777     if (m_main_win) {
04778         return m_main_win->SetFont(font);
04779     }else{
04780         return false;
04781     }
04782 }
04783 
04784 void wxTreeListCtrl::SetWindowStyleFlag(long style)
04785 {
04786     if (m_main_win)
04787     {
04788         long main_style = style & ~(wxBORDER_SIMPLE | wxBORDER_SUNKEN | wxBORDER_DOUBLE | wxBORDER_RAISED | wxBORDER_STATIC);
04789         main_style |= wxWANTS_CHARS;
04790         m_main_win->SetWindowStyle(main_style);
04791     };
04792     m_windowStyle = style & ~(wxVSCROLL | wxHSCROLL);
04793     // TODO: provide something like wxTL_NO_HEADERS to hide m_header_win
04794 }
04795 
04796 long wxTreeListCtrl::GetWindowStyleFlag() const
04797 {
04798     long style = m_windowStyle;
04799     if(m_main_win)
04800         style |= m_main_win->GetWindowStyle();
04801     return style;
04802 }
04803 
04804 bool wxTreeListCtrl::IsVisible(const wxTreeItemId& item, bool fullRow, bool within) const
04805 { return m_main_win->IsVisible(item, fullRow, within); }
04806 
04807 bool wxTreeListCtrl::HasChildren(const wxTreeItemId& item) const
04808 { return m_main_win->HasChildren(item); }
04809 
04810 bool wxTreeListCtrl::IsExpanded(const wxTreeItemId& item) const
04811 { return m_main_win->IsExpanded(item); }
04812 
04813 bool wxTreeListCtrl::IsSelected(const wxTreeItemId& item) const
04814 { return m_main_win->IsSelected(item); }
04815 
04816 size_t wxTreeListCtrl::GetChildrenCount(const wxTreeItemId& item, bool rec)
04817 { return m_main_win->GetChildrenCount(item, rec); }
04818 
04819 wxTreeItemId wxTreeListCtrl::GetRootItem() const
04820 { return m_main_win->GetRootItem(); }
04821 
04822 wxTreeItemId wxTreeListCtrl::GetSelection() const
04823 { return m_main_win->GetSelection(); }
04824 
04825 size_t wxTreeListCtrl::GetSelections(wxArrayTreeItemIds& arr) const
04826 { return m_main_win->GetSelections(arr); }
04827 
04828 wxTreeItemId wxTreeListCtrl::GetItemParent(const wxTreeItemId& item) const
04829 { return m_main_win->GetItemParent(item); }
04830 
04831 wxTreeItemId wxTreeListCtrl::GetFirstChild (const wxTreeItemId& item,
04832                                             wxTreeItemIdValue& cookie) const
04833 { return m_main_win->GetFirstChild(item, cookie); }
04834 
04835 wxTreeItemId wxTreeListCtrl::GetNextChild (const wxTreeItemId& item,
04836                                            wxTreeItemIdValue& cookie) const
04837 { return m_main_win->GetNextChild(item, cookie); }
04838 
04839 wxTreeItemId wxTreeListCtrl::GetPrevChild (const wxTreeItemId& item,
04840                                            wxTreeItemIdValue& cookie) const
04841 { return m_main_win->GetPrevChild(item, cookie); }
04842 
04843 wxTreeItemId wxTreeListCtrl::GetLastChild (const wxTreeItemId& item,
04844                                            wxTreeItemIdValue& cookie) const
04845 { return m_main_win->GetLastChild(item, cookie); }
04846 
04847 
04848 wxTreeItemId wxTreeListCtrl::GetNextSibling(const wxTreeItemId& item) const
04849 { return m_main_win->GetNextSibling(item); }
04850 
04851 wxTreeItemId wxTreeListCtrl::GetPrevSibling(const wxTreeItemId& item) const
04852 { return m_main_win->GetPrevSibling(item); }
04853 
04854 wxTreeItemId wxTreeListCtrl::GetNext(const wxTreeItemId& item) const
04855 { return m_main_win->GetNext(item, true); }
04856 
04857 wxTreeItemId wxTreeListCtrl::GetPrev(const wxTreeItemId& item) const
04858 { return m_main_win->GetPrev(item, true); }
04859 
04860 wxTreeItemId wxTreeListCtrl::GetFirstExpandedItem() const
04861 { return m_main_win->GetFirstExpandedItem(); }
04862 
04863 wxTreeItemId wxTreeListCtrl::GetNextExpanded(const wxTreeItemId& item) const
04864 { return m_main_win->GetNextExpanded(item); }
04865 
04866 wxTreeItemId wxTreeListCtrl::GetPrevExpanded(const wxTreeItemId& item) const
04867 { return m_main_win->GetPrevExpanded(item); }
04868 
04869 wxTreeItemId wxTreeListCtrl::GetFirstVisibleItem(bool fullRow) const
04870 { return GetFirstVisible(fullRow); }
04871 wxTreeItemId wxTreeListCtrl::GetFirstVisible(bool fullRow, bool within) const
04872 { return m_main_win->GetFirstVisible(fullRow, within); }
04873 
04874 wxTreeItemId wxTreeListCtrl::GetLastVisible(bool fullRow, bool within) const
04875 { return m_main_win->GetLastVisible(fullRow, within); }
04876 
04877 wxTreeItemId wxTreeListCtrl::GetNextVisible(const wxTreeItemId& item, bool fullRow, bool within) const
04878 { return m_main_win->GetNextVisible(item, fullRow, within); }
04879 
04880 wxTreeItemId wxTreeListCtrl::GetPrevVisible(const wxTreeItemId& item, bool fullRow, bool within) const
04881 { return m_main_win->GetPrevVisible(item, fullRow, within); }
04882 
04883 wxTreeItemId wxTreeListCtrl::AddRoot (const wxString& text, int image,
04884                                       int selectedImage, wxTreeItemData* data)
04885 { return m_main_win->AddRoot (text, image, selectedImage, data); }
04886 
04887 wxTreeItemId wxTreeListCtrl::PrependItem(const wxTreeItemId& parent,
04888                                          const wxString& text, int image,
04889                                          int selectedImage,
04890                                          wxTreeItemData* data)
04891 { return m_main_win->PrependItem(parent, text, image, selectedImage, data); }
04892 
04893 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
04894                                         const wxTreeItemId& previous,
04895                                         const wxString& text, int image,
04896                                         int selectedImage,
04897                                         wxTreeItemData* data)
04898 {
04899     return m_main_win->InsertItem(parent, previous, text, image,
04900                                   selectedImage, data);
04901 }
04902 
04903 wxTreeItemId wxTreeListCtrl::InsertItem(const wxTreeItemId& parent,
04904                                         size_t index,
04905                                         const wxString& text, int image,
04906                                         int selectedImage,
04907                                         wxTreeItemData* data)
04908 {
04909     return m_main_win->InsertItem(parent, index, text, image,
04910                                   selectedImage, data);
04911 }
04912 
04913 wxTreeItemId wxTreeListCtrl::AppendItem(const wxTreeItemId& parent,
04914                                         const wxString& text, int image,
04915                                         int selectedImage,
04916                                         wxTreeItemData* data)
04917 { return m_main_win->AppendItem(parent, text, image, selectedImage, data); }
04918 
04919 void wxTreeListCtrl::Delete(const wxTreeItemId& item)
04920 { m_main_win->Delete(item); }
04921 
04922 void wxTreeListCtrl::DeleteChildren(const wxTreeItemId& item)
04923 { m_main_win->DeleteChildren(item); }
04924 
04925 void wxTreeListCtrl::DeleteRoot()
04926 { m_main_win->DeleteRoot(); }
04927 
04928 void wxTreeListCtrl::Expand(const wxTreeItemId& item)
04929 { m_main_win->Expand(item); }
04930 
04931 void wxTreeListCtrl::ExpandAll(const wxTreeItemId& item)
04932 { m_main_win->ExpandAll(item); }
04933 
04934 void wxTreeListCtrl::Collapse(const wxTreeItemId& item)
04935 { m_main_win->Collapse(item); }
04936 
04937 void wxTreeListCtrl::CollapseAndReset(const wxTreeItemId& item)
04938 { m_main_win->CollapseAndReset(item); }
04939 
04940 void wxTreeListCtrl::Toggle(const wxTreeItemId& item)
04941 { m_main_win->Toggle(item); }
04942 
04943 void wxTreeListCtrl::Unselect()
04944 { m_main_win->Unselect(); }
04945 
04946 void wxTreeListCtrl::UnselectAll()
04947 { m_main_win->UnselectAll(); }
04948 
04949 bool wxTreeListCtrl::SelectItem(const wxTreeItemId& item, const wxTreeItemId& last,
04950                                 bool unselect_others)
04951 { return m_main_win->SelectItem (item, last, unselect_others); }
04952 
04953 void wxTreeListCtrl::SelectAll()
04954 { m_main_win->SelectAll(); }
04955 
04956 void wxTreeListCtrl::EnsureVisible(const wxTreeItemId& item)
04957 { m_main_win->EnsureVisible(item); }
04958 
04959 void wxTreeListCtrl::ScrollTo(const wxTreeItemId& item)
04960 { m_main_win->ScrollTo(item); }
04961 
04962 wxTreeItemId wxTreeListCtrl::HitTest(const wxPoint& pos, int& flags, int& column)
04963 {
04964     wxPoint p = pos;
04965     return m_main_win->HitTest (p, flags, column);
04966 }
04967 
04968 bool wxTreeListCtrl::GetBoundingRect(const wxTreeItemId& item, wxRect& rect,
04969                                      bool textOnly) const
04970 { return m_main_win->GetBoundingRect(item, rect, textOnly); }
04971 
04972 void wxTreeListCtrl::EditLabel (const wxTreeItemId& item, int column)
04973     { m_main_win->EditLabel (item, column); }
04974 void wxTreeListCtrl::EndEdit(bool isCancelled)
04975     { m_main_win->EndEdit(isCancelled); }
04976 
04977 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2)
04978 {
04979     // do the comparison here and not in m_main_win in order to allow
04980     // override in child class
04981     return wxStrcmp(GetItemText(item1), GetItemText(item2));
04982 }
04983 int wxTreeListCtrl::OnCompareItems(const wxTreeItemId& item1, const wxTreeItemId& item2, int column)
04984 {
04985     // do the comparison here and not in m_main_win in order to allow
04986     // override in child class
04987     return wxStrcmp(GetItemText(item1, column), GetItemText(item2, column));
04988 }
04989 
04990 void wxTreeListCtrl::SortChildren(const wxTreeItemId& item, int column, bool reverseOrder)
04991 { m_main_win->SortChildren(item, column, reverseOrder); }
04992 
04993 wxTreeItemId wxTreeListCtrl::FindItem (const wxTreeItemId& item, int column, const wxString& str, int mode)
04994 { return m_main_win->FindItem (item, column, str, mode); }
04995 
04996 void wxTreeListCtrl::SetDragItem (const wxTreeItemId& item)
04997 { m_main_win->SetDragItem (item); }
04998 
04999 bool wxTreeListCtrl::SetBackgroundColour(const wxColour& colour)
05000 {
05001     if (!m_main_win) return false;
05002     return m_main_win->SetBackgroundColour(colour);
05003 }
05004 
05005 bool wxTreeListCtrl::SetForegroundColour(const wxColour& colour)
05006 {
05007     if (!m_main_win) return false;
05008     return m_main_win->SetForegroundColour(colour);
05009 }
05010 
05011 int wxTreeListCtrl::GetColumnCount() const
05012 { return m_main_win->GetColumnCount(); }
05013 
05014 void wxTreeListCtrl::SetColumnWidth(int column, int width)
05015 {
05016     m_header_win->SetColumnWidth (column, width);
05017     m_header_win->Refresh();
05018 }
05019 
05020 int wxTreeListCtrl::GetColumnWidth(int column) const
05021 { return m_header_win->GetColumnWidth(column); }
05022 
05023 void wxTreeListCtrl::SetMainColumn(int column)
05024 { m_main_win->SetMainColumn(column); }
05025 
05026 int wxTreeListCtrl::GetMainColumn() const
05027 { return m_main_win->GetMainColumn(); }
05028 
05029 void wxTreeListCtrl::SetColumnText(int column, const wxString& text)
05030 {
05031     m_header_win->SetColumnText (column, text);
05032     m_header_win->Refresh();
05033 }
05034 
05035 wxString wxTreeListCtrl::GetColumnText(int column) const
05036 { return m_header_win->GetColumnText(column); }
05037 
05038 void wxTreeListCtrl::AddColumn(const wxTreeListColumnInfo& colInfo)
05039 {
05040     m_header_win->AddColumn (colInfo);
05041     DoHeaderLayout();
05042 }
05043 
05044 void wxTreeListCtrl::InsertColumn(int before, const wxTreeListColumnInfo& colInfo)
05045 {
05046     m_header_win->InsertColumn (before, colInfo);
05047     m_header_win->Refresh();
05048 }
05049 
05050 void wxTreeListCtrl::RemoveColumn(int column)
05051 {
05052     m_header_win->RemoveColumn (column);
05053     m_header_win->Refresh();
05054 }
05055 
05056 void wxTreeListCtrl::SetColumn(int column, const wxTreeListColumnInfo& colInfo)
05057 {
05058     m_header_win->SetColumn (column, colInfo);
05059     m_header_win->Refresh();
05060 }
05061 
05062 const wxTreeListColumnInfo& wxTreeListCtrl::GetColumn(int column) const
05063 { return m_header_win->GetColumn(column); }
05064 
05065 wxTreeListColumnInfo wxTreeListCtrl::GetColumn(int column)
05066 { return m_header_win->GetColumn(column); }
05067 
05068 void wxTreeListCtrl::SetColumnImage(int column, int image)
05069 {
05070     m_header_win->SetColumn (column, GetColumn(column).SetImage(image));
05071     m_header_win->Refresh();
05072 }
05073 
05074 int wxTreeListCtrl::GetColumnImage(int column) const
05075 {
05076     return m_header_win->GetColumn(column).GetImage();
05077 }
05078 
05079 void wxTreeListCtrl::SetColumnEditable(int column, bool shown)
05080 {
05081     m_header_win->SetColumn (column, GetColumn(column).SetEditable(shown));
05082 }
05083 
05084 void wxTreeListCtrl::SetColumnShown(int column, bool shown)
05085 {
05086     wxASSERT_MSG (column != GetMainColumn(), _T("The main column may not be hidden") );
05087     m_header_win->SetColumn (column, GetColumn(column).SetShown(GetMainColumn()==column? true: shown));
05088     m_header_win->Refresh();
05089 }
05090 
05091 bool wxTreeListCtrl::IsColumnEditable(int column) const
05092 {
05093     return m_header_win->GetColumn(column).IsEditable();
05094 }
05095 
05096 bool wxTreeListCtrl::IsColumnShown(int column) const
05097 {
05098     return m_header_win->GetColumn(column).IsShown();
05099 }
05100 
05101 void wxTreeListCtrl::SetColumnAlignment (int column, int flag)
05102 {
05103     m_header_win->SetColumn(column, GetColumn(column).SetAlignment(flag));
05104     m_header_win->Refresh();
05105 }
05106 
05107 int wxTreeListCtrl::GetColumnAlignment(int column) const
05108 {
05109     return m_header_win->GetColumn(column).GetAlignment();
05110 }
05111 
05112 void wxTreeListCtrl::Refresh(bool erase, const wxRect* rect)
05113 {
05114     m_main_win->Refresh (erase, rect);
05115     m_header_win->Refresh (erase, rect);
05116 }
05117 
05118 void wxTreeListCtrl::SetFocus()
05119 { m_main_win->SetFocus(); }
05120 
05121 wxSize wxTreeListCtrl::DoGetBestSize() const
05122 {
05123     wxSize bestSizeHeader = m_header_win->GetBestSize();
05124     wxSize bestSizeMain = m_main_win->GetBestSize();
05125     return wxSize (bestSizeHeader.x > bestSizeMain.x ? bestSizeHeader.x : bestSizeMain.x, bestSizeHeader.y + bestSizeMain.y);
05126 }
05127 
05128 wxString wxTreeListCtrl::OnGetItemText( wxTreeItemData* WXUNUSED(item), long WXUNUSED(column)) const
05129 {
05130     return wxEmptyString;
05131 }
05132 
05133 void wxTreeListCtrl::SetToolTip(const wxString& tip) {
05134     m_header_win->SetToolTip(tip);
05135     m_main_win->SetToolTip(tip);
05136 }
05137 void wxTreeListCtrl::SetToolTip(wxToolTip *tip) {
05138     m_header_win->SetToolTip(tip);
05139     m_main_win->SetToolTip(tip);
05140 }
05141 
05142 void wxTreeListCtrl::SetItemToolTip(const wxTreeItemId& item, const wxString &tip) {
05143     m_main_win->SetItemToolTip(item, tip);
05144 }
05145 
05146 void wxTreeListCtrl::SetCurrentItem(const wxTreeItemId& itemId) {
05147     m_main_win->SetCurrentItem(itemId);
05148 }
05149 
05150 void wxTreeListCtrl::SetItemParent(const wxTreeItemId& parent, const wxTreeItemId& item) {
05151     m_main_win->SetItemParent(parent, item);
05152 }
05153 
05154 //-----------------------------------------------------------------------------
05155 // wxTreeListCtrlXmlHandler - XRC support for wxTreeListCtrl
05156 //-----------------------------------------------------------------------------
05157 
05158 #if wxUSE_XRC
05159 
05160 IMPLEMENT_DYNAMIC_CLASS(wxTreeListCtrlXmlHandler, wxXmlResourceHandler)
05161 
05162 wxTreeListCtrlXmlHandler::wxTreeListCtrlXmlHandler() : wxXmlResourceHandler() {
05163 
05164 #define wxTR_NO_BUTTONS              0x0000     // for convenience
05165 #define wxTR_HAS_BUTTONS             0x0001     // draw collapsed/expanded btns
05166 #define wxTR_NO_LINES                0x0004     // don't draw lines at all
05167 #define wxTR_LINES_AT_ROOT           0x0008     // connect top-level nodes
05168 #define wxTR_TWIST_BUTTONS           0x0010     // still used by wxTreeListCtrl
05169 
05170 #define wxTR_SINGLE                  0x0000     // for convenience
05171 #define wxTR_MULTIPLE                0x0020     // can select multiple items
05172 #define wxTR_EXTENDED                0x0040     // TODO: allow extended selection
05173 #define wxTR_HAS_VARIABLE_ROW_HEIGHT 0x0080     // what it says
05174 
05175 #define wxTR_EDIT_LABELS             0x0200     // can edit item labels
05176 #define wxTR_ROW_LINES               0x0400     // put border around items
05177 #define wxTR_HIDE_ROOT               0x0800     // don't display root node
05178 
05179 #define wxTR_FULL_ROW_HIGHLIGHT      0x2000     // highlight full horz space
05180 
05181 #ifdef __WXGTK20__
05182 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_NO_LINES)
05183 #else
05184 #define wxTR_DEFAULT_STYLE           (wxTR_HAS_BUTTONS | wxTR_LINES_AT_ROOT)
05185 #endif
05186 
05187 // wxTreeCtrl styles, taken from treebase.h
05188         XRC_ADD_STYLE(wxTR_NO_BUTTONS);
05189         XRC_ADD_STYLE(wxTR_HAS_BUTTONS);
05190         XRC_ADD_STYLE(wxTR_NO_LINES);
05191         XRC_ADD_STYLE(wxTR_LINES_AT_ROOT);
05192         XRC_ADD_STYLE(wxTR_TWIST_BUTTONS);
05193 
05194         XRC_ADD_STYLE(wxTR_SINGLE);
05195         XRC_ADD_STYLE(wxTR_MULTIPLE);
05196 #if WXWIN_COMPATIBILITY_2_8
05197     // according to wxWidgets release notes, wxTR_EXTENDED is deprecated
05198     XRC_ADD_STYLE(wxTR_EXTENDED);
05199 #endif // WXWIN_COMPATIBILITY_2_8
05200     XRC_ADD_STYLE(wxTR_HAS_VARIABLE_ROW_HEIGHT);
05201 
05202     XRC_ADD_STYLE(wxTR_EDIT_LABELS);
05203     XRC_ADD_STYLE(wxTR_ROW_LINES);
05204     XRC_ADD_STYLE(wxTR_HIDE_ROOT);
05205 
05206     XRC_ADD_STYLE(wxTR_FULL_ROW_HIGHLIGHT);
05207 
05208     XRC_ADD_STYLE(wxTR_DEFAULT_STYLE);
05209 
05210 // wxTreeListCtrl-specific styles
05211     XRC_ADD_STYLE(wxTR_COLUMN_LINES);
05212     XRC_ADD_STYLE(wxTR_VIRTUAL);
05213 
05214 // standard wxWidgets styles
05215         AddWindowStyles();
05216 }
05217 
05218 wxObject *wxTreeListCtrlXmlHandler::DoCreateResource() {
05219         XRC_MAKE_INSTANCE(tlc, wxTreeListCtrl);
05220         tlc->Create(m_parentAsWindow, GetID(), GetPosition(), GetSize(), GetStyle(), wxDefaultValidator, GetName());
05221     SetupWindow(tlc);
05222         return tlc;
05223 }
05224 
05225 bool wxTreeListCtrlXmlHandler::CanHandle(wxXmlNode * node) {
05226         return IsOfClass(node, wxT("TreeListCtrl"));
05227 }
05228 
05229 #endif  // wxUSE_XRC
05230 
05231 } // namespace wxcode

Generated on 18 Oct 2017 for Hugintrunk by  doxygen 1.4.7