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

Generated on Tue Sep 30 01:25:35 2014 for Hugintrunk by  doxygen 1.3.9.1