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

Generated on 30 Jun 2016 for Hugintrunk by  doxygen 1.4.7