]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
digital mars updated
[wxWidgets.git] / src / generic / treectlg.cpp
index f2b3ca9dde89d3af36e5720f41b46d284d60b949..f0be2d87232f673442e02b2739abd069a3031cb6 100644 (file)
@@ -5,7 +5,7 @@
 // Created:     01/02/97
 // Modified:    22/10/98 - almost total rewrite, simpler interface (VZ)
 // Id:          $Id$
-// Copyright:   (c) 1998 Robert Roebling, Julian Smart and Markus Holzem
+// Copyright:   (c) 1998 Robert Roebling and Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 
 #include "wx/settings.h"
 #include "wx/dcclient.h"
 
+#ifdef __WXMAC__
+    #include "wx/mac/private.h"
+#endif
+
 // -----------------------------------------------------------------------------
 // array types
 // -----------------------------------------------------------------------------
@@ -45,7 +49,6 @@
 class WXDLLEXPORT wxGenericTreeItem;
 
 WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
-//WX_DEFINE_OBJARRAY(wxArrayTreeItemIds);
 
 // ----------------------------------------------------------------------------
 // constants
@@ -53,7 +56,55 @@ WX_DEFINE_EXPORTED_ARRAY(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 static const int NO_IMAGE = -1;
 
-#define PIXELS_PER_UNIT 10
+static const int PIXELS_PER_UNIT = 10;
+
+// ----------------------------------------------------------------------------
+// Aqua arrows
+// ----------------------------------------------------------------------------
+
+/* XPM */
+static const char *aqua_arrow_right[] = {
+/* columns rows colors chars-per-pixel */
+"13 11 4 1",
+"  c None",
+"b c #C0C0C0",
+"c c #707070",
+"d c #A0A0A0",
+/* pixels */
+"    b        ",
+"    ddb      ",
+"    cccdb    ",
+"    cccccd   ",
+"    ccccccdb ",
+"    ccccccccd",
+"    ccccccdb ",
+"    cccccb   ",
+"    cccdb    ",
+"    ddb      ",
+"    b        "
+};
+
+/* XPM */
+static const char *aqua_arrow_down[] = {
+/* columns rows colors chars-per-pixel */
+"13 11 4 1",
+"  c None",
+"b c #C0C0C0",
+"c c #707070",
+"d c #A0A0A0",
+/* pixels */
+"             ",
+"             ",
+" bdcccccccdb ",
+"  dcccccccd  ",
+"  bcccccccb  ",
+"   dcccccd   ",
+"   bcccccb   ",
+"    bcccd    ",
+"     dcd     ",
+"     bcb     ",
+"      d      "
+};
 
 // -----------------------------------------------------------------------------
 // private classes
@@ -63,41 +114,60 @@ static const int NO_IMAGE = -1;
 class WXDLLEXPORT wxTreeRenameTimer: public wxTimer
 {
 public:
+    // start editing the current item after half a second (if the mouse hasn't
+    // been clicked/moved)
+    enum { DELAY = 500 };
+
     wxTreeRenameTimer( wxGenericTreeCtrl *owner );
 
-    void Notify();
+    virtual void Notify();
 
 private:
-    wxGenericTreeCtrl   *m_owner;
+    wxGenericTreeCtrl *m_owner;
+
+    DECLARE_NO_COPY_CLASS(wxTreeRenameTimer)
 };
 
 // control used for in-place edit
 class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
 {
 public:
-    wxTreeTextCtrl( wxWindow *parent,
-                    const wxWindowID id,
-                    bool *accept,
-                    wxString *res,
-                    wxGenericTreeCtrl *owner,
-                    const wxString &value = wxEmptyString,
-                    const wxPoint &pos = wxDefaultPosition,
-                    const wxSize &size = wxDefaultSize,
-                    int style = wxSIMPLE_BORDER,
-                    const wxValidator& validator = wxDefaultValidator,
-                    const wxString &name = wxTextCtrlNameStr );
+    wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
 
+protected:
     void OnChar( wxKeyEvent &event );
     void OnKeyUp( wxKeyEvent &event );
     void OnKillFocus( wxFocusEvent &event );
 
+    bool AcceptChanges();
+    void Finish();
+
 private:
-    bool               *m_accept;
-    wxString           *m_res;
     wxGenericTreeCtrl  *m_owner;
+    wxGenericTreeItem  *m_itemEdited;
     wxString            m_startValue;
+    bool                m_finished;
 
     DECLARE_EVENT_TABLE()
+    DECLARE_NO_COPY_CLASS(wxTreeTextCtrl)
+};
+
+// timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
+// for a sufficiently long time
+class WXDLLEXPORT wxTreeFindTimer : public wxTimer
+{
+public:
+    // reset the current prefix after half a second of inactivity
+    enum { DELAY = 500 };
+
+    wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
+
+    virtual void Notify() { m_owner->m_findPrefix.clear(); }
+
+private:
+    wxGenericTreeCtrl *m_owner;
+
+    DECLARE_NO_COPY_CLASS(wxTreeFindTimer)
 };
 
 // a tree item
@@ -108,7 +178,6 @@ public:
     wxGenericTreeItem() { m_data = NULL; }
     wxGenericTreeItem( wxGenericTreeItem *parent,
                        const wxString& text,
-                       wxDC& dc,
                        int image,
                        int selImage,
                        wxTreeItemData *data );
@@ -227,7 +296,7 @@ private:
     short               m_images[wxTreeItemIcon_Max];
 
     wxCoord             m_x;            // (virtual) offset from top
-    short               m_y;            // (virtual) offset from left
+    wxCoord             m_y;            // (virtual) offset from left
     short               m_width;        // width of this item
     unsigned char       m_height;       // height of this item
 
@@ -238,6 +307,8 @@ private:
                                           // children but has a [+] button
     int                 m_isBold      :1; // render the label in bold font
     int                 m_ownsAttr    :1; // delete attribute when done
+
+    DECLARE_NO_COPY_CLASS(wxGenericTreeItem)
 };
 
 // =============================================================================
@@ -262,6 +333,23 @@ static void EventFlagsToSelType(long style,
     unselect_others = !(extended_select || (ctrlDown && is_multiple));
 }
 
+// check if the given item is under another one
+static bool IsDescendantOf(wxGenericTreeItem *parent, wxGenericTreeItem *item)
+{
+    while ( item )
+    {
+        if ( item == parent )
+        {
+            // item is a descendant of parent
+            return TRUE;
+        }
+
+        item = item->GetParent();
+    }
+
+    return FALSE;
+}
+
 // -----------------------------------------------------------------------------
 // wxTreeRenameTimer (internal)
 // -----------------------------------------------------------------------------
@@ -286,94 +374,135 @@ BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus)
 END_EVENT_TABLE()
 
-wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
-                                const wxWindowID id,
-                                bool *accept,
-                                wxString *res,
-                                wxGenericTreeCtrl *owner,
-                                const wxString &value,
-                                const wxPoint &pos,
-                                const wxSize &size,
-                                int style,
-                                const wxValidator& validator,
-                                const wxString &name )
-    : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
-{
-    m_res = res;
-    m_accept = accept;
+wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
+                               wxGenericTreeItem *item)
+              : m_itemEdited(item), m_startValue(item->GetText())
+{
     m_owner = owner;
-    (*m_accept) = FALSE;
-    (*m_res) = wxEmptyString;
-    m_startValue = value;
-}
+    m_finished = FALSE;
 
-void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
-{
-    // TODO focus doesn't return to the wxTextCtrl when this closes...
-    if (event.m_keyCode == WXK_RETURN)
+    int w = m_itemEdited->GetWidth(),
+        h = m_itemEdited->GetHeight();
+
+    int x, y;
+    m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y);
+
+    int image_h = 0,
+        image_w = 0;
+
+    int image = item->GetCurrentImage();
+    if ( image != NO_IMAGE )
     {
-        (*m_accept) = TRUE;
-        (*m_res) = GetValue();
+        if ( m_owner->m_imageListNormal )
+        {
+            m_owner->m_imageListNormal->GetSize( image, image_w, image_h );
+            image_w += 4;
+        }
+        else
+        {
+            wxFAIL_MSG(_T("you must create an image list to use images!"));
+        }
+    }
 
-        if ((*m_accept) && ((*m_res) != m_startValue))
-            m_owner->OnRenameAccept();
+    // FIXME: what are all these hardcoded 4, 8 and 11s really?
+    x += image_w;
+    w -= image_w + 4;
 
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
+    (void)Create(m_owner, wxID_ANY, m_startValue,
+                 wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
+}
 
-        return;
+bool wxTreeTextCtrl::AcceptChanges()
+{
+    const wxString value = GetValue();
+
+    if ( value == m_startValue )
+    {
+        // nothing changed, always accept
+        return TRUE;
     }
-    if (event.m_keyCode == WXK_ESCAPE)
+
+    if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
     {
-        (*m_accept) = FALSE;
-        (*m_res) = "";
+        // vetoed by the user
+        return FALSE;
+    }
 
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
+    // accepted, do rename the item
+    m_owner->SetItemText(m_itemEdited, value);
 
-        return;
-    }
-    event.Skip();
+    return TRUE;
 }
 
-void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
+void wxTreeTextCtrl::Finish()
 {
-    // auto-grow the textctrl:
-    wxSize parentSize = m_owner->GetSize();
-    wxPoint myPos = GetPosition();
-    wxSize mySize = GetSize();
-    int sx, sy;
-    GetTextExtent(GetValue() + _T("MM"), &sx, &sy);
-    if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
-    if (mySize.x > sx) sx = mySize.x;
-    SetSize(sx, -1);
+    if ( !m_finished )
+    {
+        m_owner->ResetTextControl();
 
-    event.Skip();
+        wxPendingDelete.Append(this);
+
+        m_finished = TRUE;
+
+        m_owner->SetFocus(); // This doesn't work. TODO.
+    }
 }
 
-void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &WXUNUSED(event) )
+void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
 {
-    if (!wxPendingDelete.Member(this))
-        wxPendingDelete.Append(this);
+    switch ( event.m_keyCode )
+    {
+        case WXK_RETURN:
+            if ( !AcceptChanges() )
+            {
+                // vetoed by the user, don't disappear
+                break;
+            }
+            //else: fall through
+
+        case WXK_ESCAPE:
+            Finish();
+            m_owner->OnRenameCancelled(m_itemEdited);
+            break;
 
-    if ((*m_accept) && ((*m_res) != m_startValue))
-        m_owner->OnRenameAccept();
+        default:
+            event.Skip();
+    }
 }
 
-#if 0
-// -----------------------------------------------------------------------------
-// wxTreeEvent
-// -----------------------------------------------------------------------------
+void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
+{
+    if ( !m_finished )
+    {
+        // auto-grow the textctrl:
+        wxSize parentSize = m_owner->GetSize();
+        wxPoint myPos = GetPosition();
+        wxSize mySize = GetSize();
+        int sx, sy;
+        GetTextExtent(GetValue() + _T("M"), &sx, &sy);
+        if (myPos.x + sx > parentSize.x)
+            sx = parentSize.x - myPos.x;
+        if (mySize.x > sx)
+            sx = mySize.x;
+        SetSize(sx, -1);
+    }
 
-IMPLEMENT_DYNAMIC_CLASS(wxTreeEvent, wxNotifyEvent)
+    event.Skip();
+}
 
-wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
-           : wxNotifyEvent( commandType, id )
+void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
 {
-    m_code = 0;
-    m_itemOld = (wxGenericTreeItem *)NULL;
+    if ( m_finished )
+    {
+        event.Skip();
+        return;
+    }
+
+    if ( AcceptChanges() )
+    {
+        Finish();
+    }
 }
-#endif
 
 // -----------------------------------------------------------------------------
 // wxGenericTreeItem
@@ -381,7 +510,6 @@ wxTreeEvent::wxTreeEvent( wxEventType commandType, int id )
 
 wxGenericTreeItem::wxGenericTreeItem(wxGenericTreeItem *parent,
                                      const wxString& text,
-                                     wxDC& WXUNUSED(dc),
                                      int image, int selImage,
                                      wxTreeItemData *data)
                  : m_text(text)
@@ -606,7 +734,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl)
 
 void wxGenericTreeCtrl::Init()
 {
-    m_current = m_key_current = m_anchor = (wxGenericTreeItem *) NULL;
+    m_current = m_key_current = m_anchor = m_select_me = (wxGenericTreeItem *) NULL;
     m_hasFocus = FALSE;
     m_dirty = FALSE;
 
@@ -616,7 +744,7 @@ void wxGenericTreeCtrl::Init()
 
     m_hilightBrush = new wxBrush
                          (
-                            wxSystemSettings::GetSystemColour
+                            wxSystemSettings::GetColour
                             (
                                 wxSYS_COLOUR_HIGHLIGHT
                             ),
@@ -625,7 +753,7 @@ void wxGenericTreeCtrl::Init()
 
     m_hilightUnfocusedBrush = new wxBrush
                               (
-                                 wxSystemSettings::GetSystemColour
+                                 wxSystemSettings::GetColour
                                  (
                                      wxSYS_COLOUR_BTNSHADOW
                                  ),
@@ -640,16 +768,21 @@ void wxGenericTreeCtrl::Init()
     m_dragCount = 0;
     m_isDragging = FALSE;
     m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL;
+    m_textCtrl = NULL;
+
+    m_renameTimer = NULL;
+    m_findTimer = NULL;
 
-    m_renameTimer = new wxTreeRenameTimer( this );
     m_lastOnSame = FALSE;
 
-    m_normalFont = wxSystemSettings::GetSystemFont( wxSYS_DEFAULT_GUI_FONT );
-    m_boldFont = wxFont( m_normalFont.GetPointSize(),
-                         m_normalFont.GetFamily(),
-                         m_normalFont.GetStyle(),
-                         wxBOLD,
-                         m_normalFont.GetUnderlined());
+    m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
+    m_boldFont = wxFont(m_normalFont.GetPointSize(),
+                        m_normalFont.GetFamily(),
+                        m_normalFont.GetStyle(),
+                        wxBOLD,
+                        m_normalFont.GetUnderlined(),
+                        m_normalFont.GetFaceName(),
+                        m_normalFont.GetEncoding());
 }
 
 bool wxGenericTreeCtrl::Create(wxWindow *parent,
@@ -660,12 +793,37 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
                                const wxValidator &validator,
                                const wxString& name )
 {
+#ifdef __WXMAC__
+    int major,minor;
+    wxGetOsVersion( &major, &minor );
+
+    if (style & wxTR_HAS_BUTTONS) style |= wxTR_MAC_BUTTONS;
+    if (style & wxTR_HAS_BUTTONS) style &= ~wxTR_HAS_BUTTONS;
+    style &= ~wxTR_LINES_AT_ROOT;
+    style |= wxTR_NO_LINES;
+    if (major < 10)
+        style |= wxTR_ROW_LINES;
+    if (major >= 10)
+        style |= wxTR_AQUA_BUTTONS;
+#endif
+
+    if (style & wxTR_AQUA_BUTTONS)
+    {
+        m_arrowRight = new wxBitmap( aqua_arrow_right );
+        m_arrowDown = new wxBitmap( aqua_arrow_down );
+    }
+    else
+    {
+        m_arrowRight = NULL;
+        m_arrowDown = NULL;
+    }
+
     wxScrolledWindow::Create( parent, id, pos, size,
                               style|wxHSCROLL|wxVSCROLL, name );
 
-        // If the tree display has no buttons, but does have
-        // connecting lines, we can use a narrower layout.
-        // It may not be a good idea to force this...
+    // If the tree display has no buttons, but does have
+    // connecting lines, we can use a narrower layout.
+    // It may not be a good idea to force this...
     if (!HasButtons() && !HasFlag(wxTR_NO_LINES))
     {
         m_indent= 10;
@@ -676,10 +834,11 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     SetValidator( validator );
 #endif
 
-    SetBackgroundColour( wxSystemSettings::GetSystemColour( wxSYS_COLOUR_LISTBOX ) );
+    SetForegroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT) );
+    SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOX) );
 
 //  m_dottedPen = wxPen( "grey", 0, wxDOT );  too slow under XFree86
-    m_dottedPen = wxPen( "grey", 0, 0 );
+    m_dottedPen = wxPen( wxT("grey"), 0, 0 );
 
     return TRUE;
 }
@@ -689,12 +848,20 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl()
     delete m_hilightBrush;
     delete m_hilightUnfocusedBrush;
 
+    delete m_arrowRight;
+    delete m_arrowDown;
+
     DeleteAllItems();
 
     delete m_renameTimer;
-    if (m_ownsImageListNormal) delete m_imageListNormal;
-    if (m_ownsImageListState) delete m_imageListState;
-    if (m_ownsImageListButtons) delete m_imageListButtons;
+    delete m_findTimer;
+
+    if (m_ownsImageListNormal)
+        delete m_imageListNormal;
+    if (m_ownsImageListState)
+        delete m_imageListState;
+    if (m_ownsImageListButtons)
+        delete m_imageListButtons;
 }
 
 // -----------------------------------------------------------------------------
@@ -708,13 +875,13 @@ size_t wxGenericTreeCtrl::GetCount() const
 
 void wxGenericTreeCtrl::SetIndent(unsigned int indent)
 {
-    m_indent = indent;
+    m_indent = (unsigned short) indent;
     m_dirty = TRUE;
 }
 
 void wxGenericTreeCtrl::SetSpacing(unsigned int spacing)
 {
-    m_spacing = spacing;
+    m_spacing = (unsigned short) spacing;
     m_dirty = TRUE;
 }
 
@@ -727,9 +894,17 @@ size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recurs
 
 void wxGenericTreeCtrl::SetWindowStyle(const long styles)
 {
-        // right now, just sets the styles.  Eventually, we may
-        // want to update the inherited styles, but right now
-        // none of the parents has updatable styles
+    if (!HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT))
+    {
+        // if we will hide the root, make sure children are visible
+        m_anchor->SetHasPlus();
+        m_anchor->Expand();
+        CalculatePositions();
+    }
+
+    // right now, just sets the styles.  Eventually, we may
+    // want to update the inherited styles, but right now
+    // none of the parents has updatable styles
     m_windowStyle = styles;
     m_dirty = TRUE;
 }
@@ -760,6 +935,30 @@ wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const
     return ((wxGenericTreeItem*) item.m_pItem)->GetData();
 }
 
+wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const
+{
+    wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->Attr().GetTextColour();
+}
+
+wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const
+{
+    wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->Attr().GetBackgroundColour();
+}
+
+wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const
+{
+    wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") );
+
+    wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem;
+    return pItem->Attr().GetFont();
+}
+
 void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text)
 {
     wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
@@ -848,11 +1047,13 @@ bool wxGenericTreeCtrl::SetFont( const wxFont &font )
     wxScrolledWindow::SetFont(font);
 
     m_normalFont = font ;
-    m_boldFont = wxFont( m_normalFont.GetPointSize(),
-                            m_normalFont.GetFamily(),
-                            m_normalFont.GetStyle(),
-                            wxBOLD,
-                            m_normalFont.GetUnderlined());
+    m_boldFont = wxFont(m_normalFont.GetPointSize(),
+                        m_normalFont.GetFamily(),
+                        m_normalFont.GetStyle(),
+                        wxBOLD,
+                        m_normalFont.GetUnderlined(),
+                        m_normalFont.GetFaceName(),
+                        m_normalFont.GetEncoding());
 
     return TRUE;
 }
@@ -898,7 +1099,12 @@ bool wxGenericTreeCtrl::ItemHasChildren(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), FALSE, wxT("invalid tree item") );
 
-    return !((wxGenericTreeItem*) item.m_pItem)->GetChildren().IsEmpty();
+    // consider that the item does have children if it has the "+" button: it
+    // might not have them (if it had never been expanded yet) but then it
+    // could have them as well and it's better to err on this side rather than
+    // disabling some operations which are restricted to the items with
+    // children for an item which does have them
+    return ((wxGenericTreeItem*) item.m_pItem)->HasPlus();
 }
 
 bool wxGenericTreeCtrl::IsExpanded(const wxTreeItemId& item) const
@@ -926,7 +1132,7 @@ bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const
 // navigation
 // -----------------------------------------------------------------------------
 
-wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const
+wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 
@@ -1026,21 +1232,12 @@ wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const
          do
          {
               toFind = GetNextSibling(p);
-              p = GetParent(p);
+              p = GetItemParent(p);
          } while (p.IsOk() && !toFind.IsOk());
          return toFind;
     }
 }
 
-wxTreeItemId wxGenericTreeCtrl::GetPrev(const wxTreeItemId& item) const
-{
-    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
-
-    wxFAIL_MSG(wxT("not implemented"));
-
-    return wxTreeItemId();
-}
-
 wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 {
     wxTreeItemId id = GetRootItem();
@@ -1082,6 +1279,58 @@ wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
     return wxTreeItemId();
 }
 
+// called by wxTextTreeCtrl when it marks itself for deletion
+void wxGenericTreeCtrl::ResetTextControl()
+{
+  m_textCtrl = NULL;
+}
+
+// find the first item starting with the given prefix after the given item
+wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
+                                         const wxString& prefixOrig) const
+{
+    // match is case insensitive as this is more convenient to the user: having
+    // to press Shift-letter to go to the item starting with a capital letter
+    // would be too bothersome
+    wxString prefix = prefixOrig.Lower();
+
+    // determine the starting point: we shouldn't take the current item (this
+    // allows to switch between two items starting with the same letter just by
+    // pressing it) but we shouldn't jump to the next one if the user is
+    // continuing to type as otherwise he might easily skip the item he wanted
+    wxTreeItemId id = idParent;
+    if ( prefix.length() == 1 )
+    {
+        id = GetNext(id);
+    }
+
+    // look for the item starting with the given prefix after it
+    while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) )
+    {
+        id = GetNext(id);
+    }
+
+    // if we haven't found anything...
+    if ( !id.IsOk() )
+    {
+        // ... wrap to the beginning
+        id = GetRootItem();
+        if ( HasFlag(wxTR_HIDE_ROOT) )
+        {
+            // can't select virtual root
+            id = GetNext(id);
+        }
+
+        // and try all the items (stop when we get to the one we started from)
+        while ( id != idParent && !GetItemText(id).Lower().StartsWith(prefix) )
+        {
+            id = GetNext(id);
+        }
+    }
+
+    return id;
+}
+
 // -----------------------------------------------------------------------------
 // operations
 // -----------------------------------------------------------------------------
@@ -1101,9 +1350,8 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
 
     m_dirty = TRUE;     // do this first so stuff below doesn't cause flicker
 
-    wxClientDC dc(this);
     wxGenericTreeItem *item =
-        new wxGenericTreeItem( parent, text, dc, image, selImage, data );
+        new wxGenericTreeItem( parent, text, image, selImage, data );
 
     if ( data != NULL )
     {
@@ -1123,19 +1371,20 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
 
     m_dirty = TRUE;     // do this first so stuff below doesn't cause flicker
 
-    wxClientDC dc(this);
-    m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text, dc,
+    m_anchor = new wxGenericTreeItem((wxGenericTreeItem *)NULL, text,
                                    image, selImage, data);
+    if ( data != NULL )
+    {
+        data->m_pItem = (long) m_anchor;
+    }
+
     if (HasFlag(wxTR_HIDE_ROOT))
     {
         // if root is hidden, make sure we can navigate
         // into children
         m_anchor->SetHasPlus();
-        Expand(m_anchor);
-    }
-    if ( data != NULL )
-    {
-        data->m_pItem = (long) m_anchor;
+        m_anchor->Expand();
+        CalculatePositions();
     }
 
     if (!HasFlag(wxTR_MULTIPLE))
@@ -1168,9 +1417,13 @@ wxTreeItemId wxGenericTreeCtrl::InsertItem(const wxTreeItemId& parentId,
         return AddRoot(text, image, selImage, data);
     }
 
-    int index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem);
-    wxASSERT_MSG( index != wxNOT_FOUND,
-                  wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") );
+    int index = -1;
+    if (idPrevious.IsOk())
+    {
+        index = parent->GetChildren().Index((wxGenericTreeItem*) idPrevious.m_pItem);
+        wxASSERT_MSG( index != wxNOT_FOUND,
+                      wxT("previous item in wxGenericTreeCtrl::InsertItem() is not a sibling") );
+    }
 
     return DoInsertItem(parentId, (size_t)++index, text, image, selImage, data);
 }
@@ -1229,33 +1482,49 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
-    // don't stay with invalid m_key_current or we will crash in
-    // the next call to OnChar()
-    bool changeKeyCurrent = FALSE;
-    wxGenericTreeItem *itemKey = m_key_current;
-    while ( itemKey )
+    wxGenericTreeItem *parent = item->GetParent();
+
+    // don't keep stale pointers around!
+    if ( IsDescendantOf(item, m_key_current) )
     {
-        if ( itemKey == item )
-        {
-            // m_key_current is a descendant of the item being deleted
-            changeKeyCurrent = TRUE;
-            break;
-        }
-        itemKey = itemKey->GetParent();
+        // Don't silently change the selection:
+        // do it properly in idle time, so event
+        // handlers get called.
+        
+        // m_key_current = parent;
+        m_key_current = NULL;
     }
 
-    wxGenericTreeItem *parent = item->GetParent();
+    // m_select_me records whether we need to select
+    // a different item, in idle time.
+    if ( m_select_me && IsDescendantOf(item, m_select_me) )
+    {
+        m_select_me = parent;
+    }
+
+    if ( IsDescendantOf(item, m_current) )
+    {
+        // Don't silently change the selection:
+        // do it properly in idle time, so event
+        // handlers get called.
+        
+        // m_current = parent;
+        m_current = NULL;
+        m_select_me = parent;
+    }
+
+    // remove the item from the tree
     if ( parent )
     {
         parent->GetChildren().Remove( item );  // remove by value
     }
-
-    if ( changeKeyCurrent )
+    else // deleting the root
     {
-        // may be NULL or not
-        m_key_current = parent;
+        // nothing will be left in the tree
+        m_anchor = NULL;
     }
 
+    // and delete all of its children and the item itself now
     item->DeleteChildren(this);
     SendDeleteEvent(item);
     delete item;
@@ -1265,12 +1534,7 @@ void wxGenericTreeCtrl::DeleteAllItems()
 {
     if ( m_anchor )
     {
-        m_dirty = TRUE;
-
-        m_anchor->DeleteChildren(this);
-        delete m_anchor;
-
-        m_anchor = NULL;
+        Delete(m_anchor);
     }
 }
 
@@ -1279,6 +1543,8 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
     wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
+    wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
+                 _T("can't expand hidden root") );
 
     if ( !item->HasPlus() )
         return;
@@ -1307,22 +1573,28 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 
 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
 {
-    Expand(item);
-    if ( IsExpanded(item) )
+    if ( !HasFlag(wxTR_HIDE_ROOT) || item != GetRootItem())
     {
-        long cookie;
-        wxTreeItemId child = GetFirstChild(item, cookie);
-        while ( child.IsOk() )
-        {
-            ExpandAll(child);
+        Expand(item);
+        if ( !IsExpanded(item) )
+            return;
+    }
 
-            child = GetNextChild(item, cookie);
-        }
+    long cookie;
+    wxTreeItemId child = GetFirstChild(item, cookie);
+    while ( child.IsOk() )
+    {
+        ExpandAll(child);
+
+        child = GetNextChild(item, cookie);
     }
 }
 
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 {
+    wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
+                 _T("can't collapse hidden root") );
+
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
     if ( !item->IsExpanded() )
@@ -1378,6 +1650,9 @@ void wxGenericTreeCtrl::Unselect()
     {
         m_current->SetHilight( FALSE );
         RefreshLine( m_current );
+
+        m_current = NULL;
+        m_select_me = NULL;
     }
 }
 
@@ -1402,7 +1677,13 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::UnselectAll()
 {
-    UnselectAllChildren((wxGenericTreeItem*) GetRootItem().m_pItem);
+    wxTreeItemId rootItem = GetRootItem();
+
+    // the tree might not have the root item at all
+    if ( rootItem )
+    {
+        UnselectAllChildren((wxGenericTreeItem*) rootItem.m_pItem);
+    }
 }
 
 // Recursive function !
@@ -1457,6 +1738,7 @@ void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeI
 {
     // item2 is not necessary after item1
     wxGenericTreeItem *first=NULL, *last=NULL;
+    m_select_me = NULL;
 
     // choice first' and 'last' between item1 and item2
     if (item1->GetY()<item2->GetY())
@@ -1479,11 +1761,13 @@ void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeI
 }
 
 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
-                            bool unselect_others,
-                            bool extended_select)
+                                   bool unselect_others,
+                                   bool extended_select)
 {
     wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") );
 
+    m_select_me = NULL;
+    
     bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE);
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
@@ -1515,13 +1799,13 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
     if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
         return;
 
-    wxTreeItemId parent = GetParent( itemId );
+    wxTreeItemId parent = GetItemParent( itemId );
     while (parent.IsOk())
     {
         if (!IsExpanded(parent))
             Expand( parent );
 
-        parent = GetParent( parent );
+        parent = GetItemParent( parent );
     }
 
     EnsureVisible( itemId );
@@ -1562,7 +1846,7 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId,
 }
 
 void wxGenericTreeCtrl::FillArray(wxGenericTreeItem *item,
-                           wxArrayTreeItemIds &array) const
+                                  wxArrayTreeItemIds &array) const
 {
     if ( item->IsSelected() )
         array.Add(wxTreeItemId(item));
@@ -1597,10 +1881,22 @@ void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 
     // first expand all parent branches
     wxGenericTreeItem *parent = gitem->GetParent();
-    while ( parent )
+
+    if ( HasFlag(wxTR_HIDE_ROOT) )
     {
-        Expand(parent);
-        parent = parent->GetParent();
+        while ( parent != m_anchor )
+        {
+            Expand(parent);
+            parent = parent->GetParent();
+        }
+    }
+    else
+    {
+        while ( parent )
+        {
+            Expand(parent);
+            parent = parent->GetParent();
+        }
     }
 
     //if (parent) CalculatePositions();
@@ -1756,7 +2052,10 @@ void wxGenericTreeCtrl::SetImageList(wxImageList *imageList)
     m_imageListNormal = imageList;
     m_ownsImageListNormal = FALSE;
     m_dirty = TRUE;
-    CalculateLineHeight();
+    // Don't do any drawing if we're setting the list to NULL,
+    // since we may be in the process of deleting the tree control.
+    if (imageList)
+        CalculateLineHeight();
 }
 
 void wxGenericTreeCtrl::SetStateImageList(wxImageList *imageList)
@@ -1855,7 +2154,20 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     if ( item->IsSelected() )
     {
+// under mac selections are only a rectangle in case they don't have the focus
+#ifdef __WXMAC__
+        if ( !m_hasFocus )
+        {
+            dc.SetBrush( *wxTRANSPARENT_BRUSH ) ;
+            dc.SetPen( wxPen( wxSystemSettings::GetColour( wxSYS_COLOUR_HIGHLIGHT ) , 1 , wxSOLID ) ) ;
+        }
+        else
+        {
+            dc.SetBrush( *m_hilightBrush ) ;
+        }
+#else
         dc.SetBrush(*(m_hasFocus ? m_hilightBrush : m_hilightUnfocusedBrush));
+#endif
     }
     else
     {
@@ -1869,18 +2181,29 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     int offset = HasFlag(wxTR_ROW_LINES) ? 1 : 0;
 
-    if ( item->IsSelected() && image != NO_IMAGE )
+    if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) )
     {
-        // If it's selected, and there's an image, then we should
-        // take care to leave the area under the image painted in the
-        // background colour.
-        dc.DrawRectangle( item->GetX() + image_w - 2, item->GetY()+offset,
-                          item->GetWidth() - image_w + 2, total_h-offset );
+        int x, y, w, h;
+
+        DoGetPosition(&x, &y);
+        DoGetSize(&w, &h);
+        dc.DrawRectangle(x, item->GetY()+offset, w, total_h-offset);
     }
     else
     {
-        dc.DrawRectangle( item->GetX()-2, item->GetY()+offset,
-                          item->GetWidth()+2, total_h-offset );
+        if ( item->IsSelected() && image != NO_IMAGE )
+        {
+            // If it's selected, and there's an image, then we should
+            // take care to leave the area under the image painted in the
+            // background colour.
+            dc.DrawRectangle( item->GetX() + image_w - 2, item->GetY()+offset,
+                              item->GetWidth() - image_w + 2, total_h-offset );
+        }
+        else
+        {
+            dc.DrawRectangle( item->GetX()-2, item->GetY()+offset,
+                              item->GetWidth()+2, total_h-offset );
+        }
     }
 
     if ( image != NO_IMAGE )
@@ -1913,10 +2236,26 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
     }
     else if (level == 0)
     {
+        // always expand hidden root
+        int origY = y;
         wxArrayGenericTreeItems& children = item->GetChildren();
-        size_t n, count = children.Count();
-        for (n = 0; n < count; ++n)
-            PaintLevel(children[n], dc, 1, y);
+        int count = children.Count();
+        if (count > 0)
+        {
+            int n = 0, oldY;
+            do {
+                oldY = y;
+                PaintLevel(children[n], dc, 1, y);
+            } while (++n < count);
+
+            if (!HasFlag(wxTR_NO_LINES) && HasFlag(wxTR_LINES_AT_ROOT) && count > 0)
+            {
+                // draw line down to last child
+                origY += GetLineHeight(children[0])>>1;
+                oldY += GetLineHeight(children[n-1])>>1;
+                dc.DrawLine(3, origY, 3, oldY);
+            }
+        }
         return;
     }
 
@@ -1933,22 +2272,68 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
 
     if (IsExposed(exposed_x, exposed_y, 10000, h))  // 10000 = very much
     {
+        wxPen *pen =
+#ifndef __WXMAC__
+            // don't draw rect outline if we already have the
+            // background color under Mac
+            (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN :
+#endif // !__WXMAC__
+            wxTRANSPARENT_PEN;
+
+        wxColour colText;
+        if ( item->IsSelected() )
+        {
+            colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+        }
+        else
+        {
+            wxTreeItemAttr *attr = item->GetAttributes();
+            if (attr && attr->HasTextColour())
+                colText = attr->GetTextColour();
+            else
+                colText = GetForegroundColour();
+        }
+
+        // prepare to draw
+        dc.SetTextForeground(colText);
+        dc.SetPen(*pen);
+
+        // draw
+        PaintItem(item, dc);
+
+        if (HasFlag(wxTR_ROW_LINES))
+        {
+            // if the background colour is white, choose a
+            // contrasting color for the lines
+            dc.SetPen(*((GetBackgroundColour() == *wxWHITE)
+                         ? wxMEDIUM_GREY_PEN : wxWHITE_PEN));
+            dc.DrawLine(0, y_top, 10000, y_top);
+            dc.DrawLine(0, y, 10000, y);
+        }
+
+        // restore DC objects
+        dc.SetBrush(*wxWHITE_BRUSH);
+        dc.SetPen(m_dottedPen);
+        dc.SetTextForeground(*wxBLACK);
+
         if (item->HasPlus() && HasButtons())  // should the item show a button?
         {
             if (!HasFlag(wxTR_NO_LINES))
             {
-                if (x > (signed)m_indent || HasFlag(wxTR_LINES_AT_ROOT))
+                if (x > (signed)m_indent)
                     dc.DrawLine(x - m_indent, y_mid, x - 5, y_mid);
+                else if (HasFlag(wxTR_LINES_AT_ROOT))
+                    dc.DrawLine(3, y_mid, x - 5, y_mid);
                 dc.DrawLine(x + 5, y_mid, x + m_spacing, y_mid);
             }
 
             if (m_imageListButtons != NULL)
             {
                 // draw the image button here
-                int image_h = 0, image_w = 0, image = wxCLOSED_BUTTON;
-                if (item->IsExpanded()) image = wxOPEN_BUTTON;
+                int image_h = 0, image_w = 0, image = wxTreeItemIcon_Normal;
+                if (item->IsExpanded()) image = wxTreeItemIcon_Expanded;
                 if (item->IsSelected())
-                    image += wxOPEN_BUTTON_SELECTED - wxOPEN_BUTTON;
+                    image += wxTreeItemIcon_Selected - wxTreeItemIcon_Normal;
                 m_imageListButtons->GetSize(image, image_w, image_h);
                 int xx = x - (image_w>>1);
                 int yy = y_mid - (image_h>>1);
@@ -1960,32 +2345,57 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
             else if (HasFlag(wxTR_TWIST_BUTTONS))
             {
                 // draw the twisty button here
-                dc.SetPen(*wxBLACK_PEN);
-                dc.SetBrush(*m_hilightBrush);
-
-                wxPoint button[3];
 
-                if (item->IsExpanded())
+                if (HasFlag(wxTR_AQUA_BUTTONS))
                 {
-                    button[0].x = x-5;
-                    button[0].y = y_mid-2;
-                    button[1].x = x+5;
-                    button[1].y = y_mid-2;
-                    button[2].x = x;
-                    button[2].y = y_mid+3;
+                    // This causes update problems, so disabling for now.
+#if 0 // def __WXMAC__
+                    wxMacPortSetter helper(&dc) ;
+                    wxMacWindowClipper clipper(this) ;
+                    wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ;
+
+                    int loc_x = x - 5 ;
+                    int loc_y = y_mid - 6 ;
+                    MacWindowToRootWindow( & loc_x , & loc_y ) ;
+                    Rect bounds = { loc_y , loc_x , loc_y + 18 , loc_x + 12 } ;
+                    ThemeButtonDrawInfo info = { kThemeStateActive , item->IsExpanded() ? kThemeDisclosureDown : kThemeDisclosureRight ,
+                        kThemeAdornmentNone }; 
+                    DrawThemeButton( &bounds, kThemeDisclosureButton , 
+                        &info , NULL , NULL , NULL , NULL ) ;
+#else
+                    if (item->IsExpanded())
+                        dc.DrawBitmap( *m_arrowDown, x-5, y_mid-6, TRUE );
+                    else
+                        dc.DrawBitmap( *m_arrowRight, x-5, y_mid-6, TRUE );
+#endif
                 }
                 else
                 {
-                    button[0].y = y_mid-5;
-                    button[0].x = x-2;
-                    button[1].y = y_mid+5;
-                    button[1].x = x-2;
-                    button[2].y = y_mid;
-                    button[2].x = x+3;
-                }
-                dc.DrawPolygon(3, button);
+                    dc.SetBrush(*m_hilightBrush);
+                    dc.SetPen(*wxBLACK_PEN);
+                    wxPoint button[3];
 
-                dc.SetPen(m_dottedPen);
+                    if (item->IsExpanded())
+                    {
+                        button[0].x = x-5;
+                        button[0].y = y_mid-2;
+                        button[1].x = x+5;
+                        button[1].y = y_mid-2;
+                        button[2].x = x;
+                        button[2].y = y_mid+3;
+                    }
+                    else
+                    {
+                        button[0].y = y_mid-5;
+                        button[0].x = x-2;
+                        button[1].y = y_mid+5;
+                        button[1].x = x-2;
+                        button[2].y = y_mid;
+                        button[2].x = x+3;
+                    }
+                    dc.DrawPolygon(3, button);
+                    dc.SetPen(m_dottedPen);
+                }
             }
             else // if (HasFlag(wxTR_HAS_BUTTONS))
             {
@@ -2004,51 +2414,12 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         {
             // draw the horizontal line here
             int x_start = x;
-            if (x > (signed)m_indent || HasFlag(wxTR_LINES_AT_ROOT))
+            if (x > (signed)m_indent)
                 x_start -= m_indent;
+            else if (HasFlag(wxTR_LINES_AT_ROOT))
+                x_start = 3;
             dc.DrawLine(x_start, y_mid, x + m_spacing, y_mid);
         }
-
-        wxPen *pen =
-#ifndef __WXMAC__
-            // don't draw rect outline if we already have the
-            // background color under Mac
-            (item->IsSelected() && m_hasFocus) ? wxBLACK_PEN :
-#endif // !__WXMAC__
-            wxTRANSPARENT_PEN;
-
-        wxColour colText;
-        if (item->IsSelected() && m_hasFocus)
-        {
-            colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
-        }
-        else
-        {
-            wxTreeItemAttr *attr = item->GetAttributes();
-            if (attr && attr->HasTextColour())
-                colText = attr->GetTextColour();
-            else
-                colText = wxSystemSettings::GetSystemColour(wxSYS_COLOUR_WINDOWTEXT);
-        }
-
-        // prepare to draw
-        dc.SetTextForeground(colText);
-        dc.SetPen(*pen);
-
-        // draw
-        PaintItem(item, dc);
-
-        if (HasFlag(wxTR_ROW_LINES))
-        {
-            dc.SetPen(*wxWHITE_PEN);
-            dc.DrawLine(0, y_top, 10000, y_top);
-            dc.DrawLine(0, y, 10000, y);
-        }
-
-        // restore DC objects
-        dc.SetBrush(*wxWHITE_BRUSH);
-        dc.SetPen(m_dottedPen);
-        dc.SetTextForeground(*wxBLACK);
     }
 
     if (item->IsExpanded())
@@ -2064,12 +2435,28 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
                 PaintLevel(children[n], dc, level, y);
             } while (++n < count);
 
-            if (!HasFlag(wxTR_NO_LINES))
+            if (!HasFlag(wxTR_NO_LINES) && count > 0)
             {
                 // draw line down to last child
-                oldY += GetLineHeight(children[n-1])/2;
+                oldY += GetLineHeight(children[n-1])>>1;
                 if (HasButtons()) y_mid += 5;
-                dc.DrawLine(x, y_mid, x, oldY);
+
+                // Only draw the portion of the line that is visible, in case it is huge
+                wxCoord        xOrigin=0, yOrigin=0, width, height;
+                dc.GetDeviceOrigin(&xOrigin, &yOrigin);
+                yOrigin = abs(yOrigin);
+                GetClientSize(&width, &height);
+
+                // Move end points to the begining/end of the view?
+                if (y_mid < yOrigin)
+                    y_mid = yOrigin;
+                if (oldY > yOrigin + height)
+                    oldY = yOrigin + height;
+
+                // after the adjustments if y_mid is larger than oldY then the line
+                // isn't visible at all so don't draw anything
+                if (y_mid < oldY)
+                    dc.DrawLine(x, y_mid, x, oldY);
             }
         }
     }
@@ -2181,9 +2568,13 @@ void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
 void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 {
     wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
-    te.m_code = (int)event.KeyCode();
+    te.m_evtKey = event;
     te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
+    if ( GetEventHandler()->ProcessEvent( te ) )
+    {
+        // intercepted by the user code
+        return;
+    }
 
     if ( (m_current == 0) || (m_key_current == 0) )
     {
@@ -2208,7 +2599,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     // right : open if parent and go next
     // home  : go to root
     // end   : go to last item without opening parents
-    switch (event.KeyCode())
+    // alnum : start or continue searching for the item with this prefix
+    int keyCode = event.GetKeyCode();
+    switch ( keyCode )
     {
         case '+':
         case WXK_ADD:
@@ -2238,13 +2631,20 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
         case ' ':
         case WXK_RETURN:
+            if ( !event.HasModifiers() )
             {
                 wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
                 event.m_item = (long) m_current;
-                event.m_code = 0;
                 event.SetEventObject( this );
                 GetEventHandler()->ProcessEvent( event );
             }
+
+            // in any case, also generate the normal key event for this key,
+            // even if we generated the ACTIVATED event above: this is what
+            // wxMSW does and it makes sense because you might not want to
+            // process ACTIVATED event at all and handle Space and Return
+            // directly (and differently) which would be impossible otherwise
+            event.Skip();
             break;
 
             // up goes to the previous sibling or to the last
@@ -2254,7 +2654,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 wxTreeItemId prev = GetPrevSibling( m_key_current );
                 if (!prev)
                 {
-                    prev = GetParent( m_key_current );
+                    prev = GetItemParent( m_key_current );
                     if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
                     {
                         break;  // don't go to root if it is hidden
@@ -2269,7 +2669,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                             // otherwise we return to where we came from
                             SelectItem( prev, unselect_others, extended_select );
                             m_key_current= (wxGenericTreeItem*) prev.m_pItem;
-                            EnsureVisible( prev );
                             break;
                         }
                     }
@@ -2287,7 +2686,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                     SelectItem( prev, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) prev.m_pItem;
-                    EnsureVisible( prev );
                 }
             }
             break;
@@ -2295,7 +2693,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             // left arrow goes to the parent
         case WXK_LEFT:
             {
-                wxTreeItemId prev = GetParent( m_current );
+                wxTreeItemId prev = GetItemParent( m_current );
                 if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT))
                 {
                     // don't go to root if it is hidden
@@ -2303,7 +2701,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 }
                 if (prev)
                 {
-                    EnsureVisible( prev );
                     SelectItem( prev, unselect_others, extended_select );
                 }
             }
@@ -2323,7 +2720,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
                     SelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
-                    EnsureVisible( child );
                 }
                 else
                 {
@@ -2333,7 +2729,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                         wxTreeItemId current = m_key_current;
                         while (current && !next)
                         {
-                            current = GetParent( current );
+                            current = GetItemParent( current );
                             if (current) next = GetNextSibling( current );
                         }
                     }
@@ -2341,7 +2737,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     {
                         SelectItem( next, unselect_others, extended_select );
                         m_key_current=(wxGenericTreeItem*) next.m_pItem;
-                        EnsureVisible( next );
                     }
                 }
             }
@@ -2367,7 +2762,6 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
                 if ( last.IsOk() )
                 {
-                    EnsureVisible( last );
                     SelectItem( last, unselect_others, extended_select );
                 }
             }
@@ -2377,20 +2771,56 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
         case WXK_HOME:
             {
                 wxTreeItemId prev = GetRootItem();
-                if (!prev) break;
-                if (HasFlag(wxTR_HIDE_ROOT))
+                if (!prev)
+                    break;
+
+                if ( HasFlag(wxTR_HIDE_ROOT) )
                 {
                     long dummy;
                     prev = GetFirstChild(prev, dummy);
-                    if (!prev) break;
+                    if (!prev)
+                        break;
                 }
-                EnsureVisible( prev );
+
                 SelectItem( prev, unselect_others, extended_select );
             }
             break;
 
         default:
-            event.Skip();
+            // do not use wxIsalnum() here
+            if ( !event.HasModifiers() &&
+                 ((keyCode >= '0' && keyCode <= '9') ||
+                  (keyCode >= 'a' && keyCode <= 'z') ||
+                  (keyCode >= 'A' && keyCode <= 'Z' )))
+            {
+                // find the next item starting with the given prefix
+                char ch = (char)keyCode;
+
+                wxTreeItemId id = FindItem(m_current, m_findPrefix + (wxChar)ch);
+                if ( !id.IsOk() )
+                {
+                    // no such item
+                    break;
+                }
+
+                SelectItem(id);
+
+                m_findPrefix += ch;
+
+                // also start the timer to reset the current prefix if the user
+                // doesn't press any more alnum keys soon -- we wouldn't want
+                // to use this prefix for a new item search
+                if ( !m_findTimer )
+                {
+                    m_findTimer = new wxTreeFindTimer(this);
+                }
+
+                m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
+            }
+            else
+            {
+                event.Skip();
+            }
     }
 }
 
@@ -2414,14 +2844,8 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
         return wxTreeItemId();
     }
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( point.x );
-    wxCoord y = dc.DeviceToLogicalY( point.y );
-    wxGenericTreeItem *hit =  m_anchor->HitTest(wxPoint(x, y),
-                                                this,
-                                                flags,
-                                                0 );
+    wxGenericTreeItem *hit =  m_anchor->HitTest(CalcUnscrolledPosition(point),
+                                                this, flags, 0);
     if (hit == NULL)
     {
         flags = wxTREE_HITTEST_NOWHERE;
@@ -2432,8 +2856,8 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
 
 // get the bounding rectangle of the item (or of its label only)
 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
-                         wxRect& rect,
-                         bool WXUNUSED(textOnly)) const
+                                        wxRect& rect,
+                                        bool WXUNUSED(textOnly)) const
 {
     wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
 
@@ -2451,83 +2875,70 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
     return TRUE;
 }
 
-/* **** */
-
 void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
 {
-    if (!item.IsOk()) return;
+    wxCHECK_RET( item.IsOk(), _T("can't edit an invalid item") );
 
-    m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
+    wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
-    te.m_item = (long) m_currentEdit;
+    te.m_item = (long) itemEdit;
     te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
-
-    if (!te.IsAllowed()) return;
+    if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
+    {
+        // vetoed by user
+        return;
+    }
 
     // We have to call this here because the label in
     // question might just have been added and no screen
     // update taken place.
-    if (m_dirty) wxYieldIfNeeded();
-
-    wxString s = m_currentEdit->GetText();
-    int x = m_currentEdit->GetX();
-    int y = m_currentEdit->GetY();
-    int w = m_currentEdit->GetWidth();
-    int h = m_currentEdit->GetHeight();
+    if ( m_dirty )
+        wxYieldIfNeeded();
 
-    int image_h = 0;
-    int image_w = 0;
+    m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
 
-    int image = m_currentEdit->GetCurrentImage();
-    if ( image != NO_IMAGE )
-    {
-        if ( m_imageListNormal )
-        {
-            m_imageListNormal->GetSize( image, image_w, image_h );
-            image_w += 4;
-        }
-        else
-        {
-            wxFAIL_MSG(_T("you must create an image list to use images!"));
-        }
-    }
-    x += image_w;
-    w -= image_w + 4; // I don't know why +4 is needed
-
-    wxClientDC dc(this);
-    PrepareDC( dc );
-    x = dc.LogicalToDeviceX( x );
-    y = dc.LogicalToDeviceY( y );
+    m_textCtrl->SetFocus();
+}
 
-    wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1,
-                                              &m_renameAccept,
-                                              &m_renameRes,
-                                              this,
-                                              s,
-                                              wxPoint(x-4,y-4),
-                                              wxSize(w+11,h+8));
-    text->SetFocus();
+// returns a pointer to the text edit control if the item is being
+// edited, NULL otherwise (it's assumed that no more than one item may
+// be edited simultaneously)
+wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const
+{
+    return m_textCtrl;
 }
 
-void wxGenericTreeCtrl::OnRenameTimer()
+bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
+                                       const wxString& value)
 {
-    Edit( m_current );
+    wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
+    le.m_item = (long) item;
+    le.SetEventObject( this );
+    le.m_label = value;
+    le.m_editCancelled = FALSE;
+
+    return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
 }
 
-void wxGenericTreeCtrl::OnRenameAccept()
+void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
 {
-    // TODO if the validator fails this causes a crash
+    // let owner know that the edit was cancelled
     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = (long) m_currentEdit;
+    le.m_item = (long) item;
     le.SetEventObject( this );
-    le.m_label = m_renameRes;
+    le.m_label = wxEmptyString;
+    le.m_editCancelled = FALSE;
+
     GetEventHandler()->ProcessEvent( le );
+}
+
 
-    if (!le.IsAllowed()) return;
 
-    SetItemText( m_currentEdit, m_renameRes );
+
+void wxGenericTreeCtrl::OnRenameTimer()
+{
+    Edit( m_current );
 }
 
 void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
@@ -2549,21 +2960,15 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         return;
     }
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-    wxCoord x = dc.DeviceToLogicalX( event.GetX() );
-    wxCoord y = dc.DeviceToLogicalY( event.GetY() );
+    wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
 
     int flags = 0;
-    wxGenericTreeItem *item = m_anchor->HitTest( wxPoint(x,y),
-                                                 this,
-                                                 flags,
-                                                 0 );
+    wxGenericTreeItem *item = m_anchor->HitTest(pt, this, flags, 0);
 
     if ( event.Dragging() && !m_isDragging )
     {
         if (m_dragCount == 0)
-            m_dragStart = wxPoint(x,y);
+            m_dragStart = pt;
 
         m_dragCount++;
 
@@ -2640,7 +3045,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         wxTreeEvent event(wxEVT_COMMAND_TREE_END_DRAG, GetId());
 
         event.m_item = (long) item;
-        event.m_pointDrag = wxPoint(x, y);
+        event.m_pointDrag = pt;
         event.SetEventObject(this);
 
         (void)GetEventHandler()->ProcessEvent(event);
@@ -2666,10 +3071,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         {
             wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
             nevent.m_item = (long) item;
-            nevent.m_code = 0;
-            CalcScrolledPosition(x, y,
-                                 &nevent.m_pointDrag.x,
-                                 &nevent.m_pointDrag.y);
+            nevent.m_pointDrag = CalcScrolledPosition(pt);
             nevent.SetEventObject(this);
             GetEventHandler()->ProcessEvent(nevent);
         }
@@ -2681,10 +3083,17 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                      (flags & wxTREE_HITTEST_ONITEMLABEL) &&
                      HasFlag(wxTR_EDIT_LABELS) )
                 {
-                    if ( m_renameTimer->IsRunning() )
-                        m_renameTimer->Stop();
+                    if ( m_renameTimer )
+                    {
+                        if ( m_renameTimer->IsRunning() )
+                            m_renameTimer->Stop();
+                    }
+                    else
+                    {
+                        m_renameTimer = new wxTreeRenameTimer( this );
+                    }
 
-                    m_renameTimer->Start( 100, TRUE );
+                    m_renameTimer->Start( wxTreeRenameTimer::DELAY, TRUE );
                 }
 
                 m_lastOnSame = FALSE;
@@ -2724,26 +3133,25 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             if ( event.LeftDClick() )
             {
                 // double clicking should not start editing the item label
-                m_renameTimer->Stop();
+                if ( m_renameTimer )
+                    m_renameTimer->Stop();
+
                 m_lastOnSame = FALSE;
 
-                if (item->HasPlus())
+                // send activate event first
+                wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
+                nevent.m_item = (long) item;
+                nevent.m_pointDrag = CalcScrolledPosition(pt);
+                nevent.SetEventObject( this );
+                if ( !GetEventHandler()->ProcessEvent( nevent ) )
                 {
-                    // for a "directory" node, toggle expansion
-                    Toggle(item);
-                }
-                else
-                {
-                    // for a "file" node, activate it
-                    wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED,
-                                        GetId() );
-                    nevent.m_item = (long) item;
-                    nevent.m_code = 0;
-                    CalcScrolledPosition(x, y,
-                                         &nevent.m_pointDrag.x,
-                                         &nevent.m_pointDrag.y);
-                    nevent.SetEventObject( this );
-                    GetEventHandler()->ProcessEvent( nevent );
+                    // if the user code didn't process the activate event,
+                    // handle it ourselves by toggling the item when it is
+                    // double clicked
+                    if ( item->HasPlus() )
+                    {
+                        Toggle(item);
+                    }
                 }
             }
         }
@@ -2752,6 +3160,18 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
 void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) )
 {
+    // Check if we need to select the root item
+    // because nothing else has been selected.
+    // Delaying it means that we can invoke event handlers
+    // as required, when a first item is selected.
+    if (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk())
+    {
+        if (m_select_me)
+            SelectItem(m_select_me);
+        else if (GetRootItem().IsOk())
+            SelectItem(GetRootItem());
+    }
+
     /* after all changes have been done to the tree control,
      * we actually redraw the tree when everything is over */
 
@@ -2769,7 +3189,10 @@ void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
     wxCoord text_w = 0;
     wxCoord text_h = 0;
 
-    if (item->IsBold())
+    wxTreeItemAttr *attr = item->GetAttributes();
+    if ( attr && attr->HasFont() )
+        dc.SetFont(attr->GetFont());
+    else if ( item->IsBold() )
         dc.SetFont(m_boldFont);
 
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
@@ -2863,20 +3286,14 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
     if (m_dirty) return;
 
-    wxClientDC dc(this);
-    PrepareDC(dc);
-
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
+    wxSize client = GetClientSize();
 
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.width = cw;
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.height = ch;
+    CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
+    rect.width = client.x;
+    rect.height = client.y;
 
-    Refresh( TRUE, &rect );
+    Refresh(TRUE, &rect);
 
     AdjustMyScrollbars();
 }
@@ -2885,20 +3302,12 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
     if (m_dirty) return;
 
-    wxClientDC dc(this);
-    PrepareDC( dc );
-
-    int cw = 0;
-    int ch = 0;
-    GetClientSize( &cw, &ch );
-
     wxRect rect;
-    rect.x = dc.LogicalToDeviceX( 0 );
-    rect.y = dc.LogicalToDeviceY( item->GetY() );
-    rect.width = cw;
+    CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
+    rect.width = GetClientSize().x;
     rect.height = GetLineHeight(item); //dc.GetCharHeight() + 6;
 
-    Refresh( TRUE, &rect );
+    Refresh(TRUE, &rect);
 }
 
 void wxGenericTreeCtrl::RefreshSelected()
@@ -2922,4 +3331,28 @@ void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
     }
 }
 
+// ----------------------------------------------------------------------------
+// changing colours: we need to refresh the tree control
+// ----------------------------------------------------------------------------
+
+bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetBackgroundColour(colour) )
+        return FALSE;
+
+    Refresh();
+
+    return TRUE;
+}
+
+bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
+{
+    if ( !wxWindow::SetForegroundColour(colour) )
+        return FALSE;
+
+    Refresh();
+
+    return TRUE;
+}
+
 #endif // wxUSE_TREECTRL