]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
Added logic, API and docs for wxDataViewModel::HasDefaultCompare indicating a compare...
[wxWidgets.git] / src / generic / treectlg.cpp
index f968f6a9b80051263f4f34964b84b37e7599bd94..800e58ad60f36bbc2f928a4de5a7d4c03efcdb43 100644 (file)
@@ -49,7 +49,7 @@
 // array types
 // -----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxGenericTreeItem;
+class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem;
 
 WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
@@ -548,7 +548,7 @@ wxGenericTreeItem::~wxGenericTreeItem()
 
 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
 {
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
         wxGenericTreeItem *child = m_children[n];
@@ -570,7 +570,7 @@ void wxGenericTreeItem::SetText( const wxString &text )
 
 size_t wxGenericTreeItem::GetChildrenCount(bool recursively) const
 {
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     if ( !recursively )
         return count;
 
@@ -593,7 +593,7 @@ void wxGenericTreeItem::GetSize( int &x, int &y,
 
     if (IsExpanded())
     {
-        size_t count = m_children.Count();
+        size_t count = m_children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
             m_children[n]->GetSize( x, y, theButton );
@@ -668,7 +668,7 @@ wxGenericTreeItem *wxGenericTreeItem::HitTest(const wxPoint& point,
     }
 
     // evaluate children
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
         wxGenericTreeItem *res = m_children[n]->HitTest( point,
@@ -720,6 +720,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxGenericTreeCtrl, wxControl)
 
 BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase)
     EVT_PAINT          (wxGenericTreeCtrl::OnPaint)
+    EVT_SIZE           (wxGenericTreeCtrl::OnSize)
     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse)
     EVT_CHAR           (wxGenericTreeCtrl::OnChar)
     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus)
@@ -819,7 +820,14 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     style |= wxTR_NO_LINES;
     if (major < 10)
         style |= wxTR_ROW_LINES;
+        
+    if (style == 0 || style & wxTR_DEFAULT_STYLE)
+        style |= wxTR_FULL_ROW_HIGHLIGHT;
+        
 #endif // __WXMAC__
+#ifdef __WXGTK20__
+    style |= wxTR_NO_LINES;
+#endif
 
     if ( !wxControl::Create( parent, id, pos, size,
                              style|wxHSCROLL|wxVSCROLL,
@@ -844,7 +852,7 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
 
     m_dottedPen = wxPen( wxT("grey"), 0, 0 );
 
-    SetBestSize(size);
+    SetInitialSize(size);
 
     return true;
 }
@@ -1021,6 +1029,12 @@ void wxGenericTreeCtrl::SetItemBold(const wxTreeItemId& item, bool bold)
     if ( pItem->IsBold() != bold )
     {
         pItem->SetBold(bold);
+
+        // recalculate the item size as bold and non bold fonts have different
+        // widths
+        wxClientDC dc(this);
+        CalculateSize(pItem, dc);
+
         RefreshLine(pItem);
     }
 }
@@ -1189,7 +1203,7 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
     // it's ok to cast cookie to size_t, we never have indices big enough to
     // overflow "void *"
     size_t *pIndex = (size_t *)&cookie;
-    if ( *pIndex < children.Count() )
+    if ( *pIndex < children.GetCount() )
     {
         return children.Item((*pIndex)++);
     }
@@ -1200,36 +1214,6 @@ wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
     }
 }
 
-#if WXWIN_COMPATIBILITY_2_4
-
-wxTreeItemId wxGenericTreeCtrl::GetFirstChild(const wxTreeItemId& item,
-                                              long& cookie) const
-{
-    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
-
-    cookie = 0;
-    return GetNextChild(item, cookie);
-}
-
-wxTreeItemId wxGenericTreeCtrl::GetNextChild(const wxTreeItemId& item,
-                                             long& cookie) const
-{
-    wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
-
-    wxArrayGenericTreeItems& children = ((wxGenericTreeItem*) item.m_pItem)->GetChildren();
-    if ( (size_t)cookie < children.Count() )
-    {
-        return children.Item((size_t)cookie++);
-    }
-    else
-    {
-        // there are no more of them
-        return wxTreeItemId();
-    }
-}
-
-#endif // WXWIN_COMPATIBILITY_2_4
-
 wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
@@ -1255,7 +1239,7 @@ wxTreeItemId wxGenericTreeCtrl::GetNextSibling(const wxTreeItemId& item) const
     wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
 
     size_t n = (size_t)(index + 1);
-    return n == siblings.Count() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
+    return n == siblings.GetCount() ? wxTreeItemId() : wxTreeItemId(siblings[n]);
 }
 
 wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
@@ -1389,10 +1373,12 @@ wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
         }
 
         // and try all the items (stop when we get to the one we started from)
-        while ( id != idParent && !GetItemText(id).Lower().StartsWith(prefix) )
+        while (id.IsOk() && id != idParent && !GetItemText(id).Lower().StartsWith(prefix) )
         {
             id = GetNext(id);
         }
+        // If we haven't found the item, id.IsOk() will be false, as per
+        // documentation
     }
 
     return id;
@@ -1429,6 +1415,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
     parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
                                                  : previous );
 
+    InvalidateBestSize();
     return item;
 }
 
@@ -1463,6 +1450,7 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
         m_current->SetHilight( true );
     }
 
+    InvalidateBestSize();
     return m_anchor;
 }
 
@@ -1494,7 +1482,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId,
 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
 {
     wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item);
-    ProcessEvent( event );
+    GetEventHandler()->ProcessEvent( event );
 }
 
 // Don't leave edit or selection on a child which is about to disappear
@@ -1523,6 +1511,7 @@ void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
     ChildrenClosing(item);
     item->DeleteChildren(this);
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
@@ -1587,6 +1576,8 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
         m_select_me = NULL;
 
     delete item;
+
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
@@ -1613,7 +1604,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 
     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
 
-    if ( ProcessEvent( event ) && !event.IsAllowed() )
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
         return;
@@ -1625,26 +1616,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     RefreshSubtree(item);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
-    ProcessEvent( event );
-}
-
-void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
-{
-    if ( !HasFlag(wxTR_HIDE_ROOT) || item != GetRootItem())
-    {
-        Expand(item);
-        if ( !IsExpanded(item) )
-            return;
-    }
-
-    wxTreeItemIdValue cookie;
-    wxTreeItemId child = GetFirstChild(item, cookie);
-    while ( child.IsOk() )
-    {
-        ExpandAll(child);
-
-        child = GetNextChild(item, cookie);
-    }
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
@@ -1658,7 +1630,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
         return;
 
     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item);
-    if ( ProcessEvent( event ) && !event.IsAllowed() )
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
         return;
@@ -1669,7 +1641,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 
 #if 0  // TODO why should items be collapsed recursively?
     wxArrayGenericTreeItems& children = item->GetChildren();
-    size_t count = children.Count();
+    size_t count = children.GetCount();
     for ( size_t n = 0; n < count; n++ )
     {
         Collapse(children[n]);
@@ -1681,7 +1653,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
     RefreshSubtree(item);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
-    ProcessEvent( event );
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
@@ -1723,7 +1695,7 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
     if (item->HasChildren())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
-        size_t count = children.Count();
+        size_t count = children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
             UnselectAllChildren(children[n]);
@@ -1759,7 +1731,7 @@ bool wxGenericTreeCtrl::TagNextChildren(wxGenericTreeItem *crt_item, wxGenericTr
     int index = children.Index(crt_item);
     wxASSERT( index != wxNOT_FOUND ); // I'm not a child of my parent?
 
-    size_t count = children.Count();
+    size_t count = children.GetCount();
     for (size_t n=(size_t)(index+1); n<count; ++n)
     {
         if (TagAllChildrenUntilLast(children[n], last_item, select)) return true;
@@ -1779,7 +1751,7 @@ bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxG
     if (crt_item->HasChildren())
     {
         wxArrayGenericTreeItems& children = crt_item->GetChildren();
-        size_t count = children.Count();
+        size_t count = children.GetCount();
         for ( size_t n = 0; n < count; ++n )
         {
             if (TagAllChildrenUntilLast(children[n], last_item, select))
@@ -1903,9 +1875,16 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
     {
         wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
         wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+        
+        wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+        if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+            return;
 
         item->SetHilight(false);
         RefreshLine(item);
+
+        event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+        GetEventHandler()->ProcessEvent( event );
     }
 }
 
@@ -1934,7 +1913,7 @@ size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
     }
     //else: the tree is empty, so no selections
 
-    return array.Count();
+    return array.GetCount();
 }
 
 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
@@ -1981,7 +1960,7 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
 #if defined( __WXMSW__ ) || defined(__WXMAC__)
         Update();
 #else
-        wxYieldIfNeeded();
+        DoDirtyProcessing();
 #endif
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
@@ -2045,7 +2024,7 @@ void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
 
     wxArrayGenericTreeItems& children = item->GetChildren();
-    if ( children.Count() > 1 )
+    if ( children.GetCount() > 1 )
     {
         m_dirty = true;
 
@@ -2169,7 +2148,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
     else if (item->IsBold())
         dc.SetFont(m_boldFont);
 
-    long text_w = 0, text_h = 0;
+    wxCoord text_w = 0, text_h = 0;
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
 
     int image_h = 0, image_w = 0;
@@ -2192,20 +2171,7 @@ 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
         drawItemBackground = true;
     }
     else
@@ -2227,11 +2193,31 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
 
     if ( HasFlag(wxTR_FULL_ROW_HIGHLIGHT) )
     {
-        int x, y, w, h;
-
-        DoGetPosition(&x, &y);
-        DoGetSize(&w, &h);
-        dc.DrawRectangle(x, item->GetY()+offset, w, total_h-offset);
+        int x, w, h;
+        x=0;
+        GetVirtualSize(&w, &h);
+        wxRect rect( x, item->GetY()+offset, w, total_h-offset);
+#if !defined(__WXGTK20__) && !defined(__WXMAC__)
+        dc.DrawRectangle(rect);
+#else
+        if (!item->IsSelected())
+        {
+            dc.DrawRectangle(rect);
+        }
+        else
+        {
+            int flags = wxCONTROL_SELECTED;
+            if (m_hasFocus
+#ifdef __WXMAC__
+                && IsControlActive( (ControlRef)GetHandle() )
+#endif
+            )
+                flags |= wxCONTROL_FOCUSED;
+            if ((item == m_current) && (m_hasFocus))
+                flags |= wxCONTROL_CURRENT;
+            wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags );
+        }
+#endif
     }
     else
     {
@@ -2240,16 +2226,49 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
             // 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 );
+            wxRect rect( item->GetX() + image_w - 2, item->GetY()+offset,
+                         item->GetWidth() - image_w + 2, total_h-offset );
+#if !defined(__WXGTK20__) && !defined(__WXMAC__)
+            dc.DrawRectangle( rect );
+#else
+            rect.x -= 1;
+            rect.width += 2;
+        
+            int flags = wxCONTROL_SELECTED;
+            if (m_hasFocus)
+                flags |= wxCONTROL_FOCUSED;
+            if ((item == m_current) && (m_hasFocus))
+                flags |= wxCONTROL_CURRENT;
+            wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags );
+#endif
         }
         // On GTK+ 2, drawing a 'normal' background is wrong for themes that
         // don't allow backgrounds to be customized. Not drawing the background,
         // except for custom item backgrounds, works for both kinds of theme.
         else if (drawItemBackground)
         {
-            dc.DrawRectangle( item->GetX()-2, item->GetY()+offset,
-                              item->GetWidth()+2, total_h-offset );
+            wxRect rect( item->GetX()-2, item->GetY()+offset,
+                         item->GetWidth()+2, total_h-offset );
+#if !defined(__WXGTK20__) && !defined(__WXMAC__)
+            dc.DrawRectangle( rect );
+#else
+            if ( attr && attr->HasBackgroundColour() )
+            {
+                dc.DrawRectangle( rect );
+            }
+            else
+            {
+                rect.x -= 1;
+                rect.width += 2;
+                
+                int flags = wxCONTROL_SELECTED;
+                if (m_hasFocus)
+                    flags |= wxCONTROL_FOCUSED;
+                if ((item == m_current) && (m_hasFocus))
+                    flags |= wxCONTROL_CURRENT;
+                wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags );
+            }
+#endif
         }
     }
 
@@ -2286,7 +2305,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         // always expand hidden root
         int origY = y;
         wxArrayGenericTreeItems& children = item->GetChildren();
-        int count = children.Count();
+        int count = children.GetCount();
         if (count > 0)
         {
             int n = 0, oldY;
@@ -2334,11 +2353,15 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
             // rectangle, so we want to make sure that the text is visible
             // against the normal background, not the highlightbackground, so
             // don't use the highlight text colour unless we have the focus.
-             && m_hasFocus
+             && m_hasFocus && IsControlActive( (ControlRef)GetHandle() )
 #endif
             )
         {
+#ifdef __WXMAC__
+            colText = *wxWHITE;
+#else
             colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+#endif
         }
         else
         {
@@ -2430,7 +2453,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
     if (item->IsExpanded())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
-        int count = children.Count();
+        int count = children.GetCount();
         if (count > 0)
         {
             int n = 0, oldY;
@@ -2533,6 +2556,16 @@ void wxGenericTreeCtrl::DrawLine(const wxTreeItemId &item, bool below)
 // wxWidgets callbacks
 // -----------------------------------------------------------------------------
 
+void wxGenericTreeCtrl::OnSize( wxSizeEvent &event )
+{
+#ifdef __WXGTK__
+    if (HasFlag( wxTR_FULL_ROW_HIGHLIGHT) && m_current)
+        RefreshLine( m_current );
+#endif
+
+    event.Skip(true);
+}
+
 void wxGenericTreeCtrl::OnPaint( wxPaintEvent &WXUNUSED(event) )
 {
     wxPaintDC dc(this);
@@ -2593,6 +2626,14 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                         event.CmdDown(),
                         is_multiple, extended_select, unselect_others);
 
+    if (GetLayoutDirection() == wxLayout_RightToLeft)
+    {
+        if (event.GetKeyCode() == WXK_RIGHT)
+            event.m_keyCode = WXK_LEFT;
+        else if (event.GetKeyCode() == WXK_LEFT)
+            event.m_keyCode = WXK_RIGHT;
+    }
+
     // + : Expand
     // - : Collaspe
     // * : Expand all/Collapse all
@@ -2620,7 +2661,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             if ( !IsExpanded(m_current) )
             {
                 // expand all
-                ExpandAll(m_current);
+                ExpandAllChildren(m_current);
                 break;
             }
             //else: fall through to Collapse() it
@@ -2725,7 +2766,11 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
         case WXK_RIGHT:
             // this works the same as the down arrow except that we
             // also expand the item if it wasn't expanded yet
-            Expand(m_current);
+            if (m_current != GetRootItem().m_pItem || !HasFlag(wxTR_HIDE_ROOT))
+                Expand(m_current);
+            //else: don't try to expand hidden root item (which can be the
+            //      current one when the tree is empty)
+
             // fall through
 
         case WXK_DOWN:
@@ -2734,6 +2779,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 {
                     wxTreeItemIdValue cookie;
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
+                    if ( !child )
+                        break;
+
                     DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
                 }
@@ -2925,7 +2973,7 @@ wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
 #if defined( __WXMSW__ ) || defined(__WXMAC__)
         Update();
 #else
-        wxYieldIfNeeded();
+        DoDirtyProcessing();
 #endif
 
     // TODO: use textCtrlClass here to create the control of correct class
@@ -3035,11 +3083,12 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
     }
 #endif
 
-    // we process left mouse up event (enables in-place edit), right down
+    // we process left mouse up event (enables in-place edit), middle/right down
     // (pass to the user code), left dbl click (activate item) and
     // dragging/moving events for items drag-and-drop
     if ( !(event.LeftDown() ||
            event.LeftUp() ||
+           event.MiddleDown() ||
            event.RightDown() ||
            event.LeftDClick() ||
            event.Dragging() ||
@@ -3190,6 +3239,12 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             nevent2.m_pointDrag = CalcScrolledPosition(pt);
             GetEventHandler()->ProcessEvent(nevent2);
         }
+        else if ( event.MiddleDown() )
+        {
+            wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_MIDDLE_CLICK,  this, item);
+            nevent.m_pointDrag = CalcScrolledPosition(pt);
+            event.Skip(!GetEventHandler()->ProcessEvent(nevent));
+        }
         else if ( event.LeftUp() )
         {
             // this facilitates multiple-item drag-and-drop
@@ -3229,7 +3284,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 m_lastOnSame = false;
             }
         }
-        else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
+        else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick()
         {
             if ( event.LeftDown() )
             {
@@ -3312,17 +3367,10 @@ void wxGenericTreeCtrl::OnInternalIdle()
             SelectItem(GetRootItem());
     }
 
-    /* after all changes have been done to the tree control,
-     * we actually redraw the tree when everything is over */
-
-    if (!m_dirty) return;
-    if (m_freezeCount) return;
-
-    m_dirty = false;
-
-    CalculatePositions();
-    Refresh();
-    AdjustMyScrollbars();
+    // after all changes have been done to the tree control,
+    // actually redraw the tree when everything is over
+    if (m_dirty)
+        DoDirtyProcessing();
 }
 
 void wxGenericTreeCtrl::CalculateSize( wxGenericTreeItem *item, wxDC &dc )
@@ -3402,7 +3450,7 @@ void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int l
 
   Recurse:
     wxArrayGenericTreeItems& children = item->GetChildren();
-    size_t n, count = children.Count();
+    size_t n, count = children.GetCount();
     ++level;
     for (n = 0; n < count; ++n )
         CalculateLevel( children[n], dc, level, y );  // recurse
@@ -3425,10 +3473,16 @@ void wxGenericTreeCtrl::CalculatePositions()
     CalculateLevel( m_anchor, dc, 0, y ); // start recursion
 }
 
+void wxGenericTreeCtrl::Refresh(bool eraseBackground, const wxRect *rect)
+{
+    if ( !m_freezeCount )
+        wxTreeCtrlBase::Refresh(eraseBackground, rect);
+}
+
 void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 {
-    if (m_dirty) return;
-    if (m_freezeCount) return;
+    if (m_dirty || m_freezeCount)
+        return;
 
     wxSize client = GetClientSize();
 
@@ -3444,8 +3498,8 @@ void wxGenericTreeCtrl::RefreshSubtree(wxGenericTreeItem *item)
 
 void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 {
-    if (m_dirty) return;
-    if (m_freezeCount) return;
+    if (m_dirty || m_freezeCount)
+        return;
 
     wxRect rect;
     CalcScrolledPosition(0, item->GetY(), NULL, &rect.y);
@@ -3457,7 +3511,8 @@ void wxGenericTreeCtrl::RefreshLine( wxGenericTreeItem *item )
 
 void wxGenericTreeCtrl::RefreshSelected()
 {
-    if (m_freezeCount) return;
+    if (m_freezeCount)
+        return;
 
     // TODO: this is awfully inefficient, we should keep the list of all
     //       selected items internally, should be much faster
@@ -3467,7 +3522,8 @@ void wxGenericTreeCtrl::RefreshSelected()
 
 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
 {
-    if (m_freezeCount) return;
+    if (m_freezeCount)
+        return;
 
     if ( item->IsSelected() )
         RefreshLine(item);
@@ -3504,8 +3560,6 @@ bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
     if ( !wxWindow::SetBackgroundColour(colour) )
         return false;
 
-    if (m_freezeCount) return true;
-
     Refresh();
 
     return true;
@@ -3516,8 +3570,6 @@ bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
     if ( !wxWindow::SetForegroundColour(colour) )
         return false;
 
-    if (m_freezeCount) return true;
-
     Refresh();
 
     return true;
@@ -3555,18 +3607,47 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 #endif
 }
 
-#if WXWIN_COMPATIBILITY_2_4
-
-int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
+void wxGenericTreeCtrl::DoDirtyProcessing()
 {
-    return GetItemImage(item, wxTreeItemIcon_Selected);
+    if (m_freezeCount)
+        return;
+
+    m_dirty = false;
+
+    CalculatePositions();
+    Refresh();
+    AdjustMyScrollbars();
 }
 
-void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
+wxSize wxGenericTreeCtrl::DoGetBestSize() const
 {
-    SetItemImage(item, image, wxTreeItemIcon_Selected);
-}
+    // make sure all positions are calculated as normally this only done during
+    // idle time but we need them for base class DoGetBestSize() to return the
+    // correct result
+    wxConstCast(this, wxGenericTreeCtrl)->CalculatePositions();
+
+    wxSize size = wxTreeCtrlBase::DoGetBestSize();
+
+    // there seems to be an implicit extra border around the items, although
+    // I'm not really sure where does it come from -- but without this, the
+    // scrollbars appear in a tree with default/best size
+    size.IncBy(4, 4);
 
-#endif // WXWIN_COMPATIBILITY_2_4
+    // and the border has to be rounded up to a multiple of PIXELS_PER_UNIT or
+    // scrollbars still appear
+    const wxSize& borderSize = GetWindowBorderSize();
+
+    int dx = (size.x - borderSize.x) % PIXELS_PER_UNIT;
+    if ( dx )
+        size.x += PIXELS_PER_UNIT - dx;
+    int dy = (size.y - borderSize.y) % PIXELS_PER_UNIT;
+    if ( dy )
+        size.y += PIXELS_PER_UNIT - dy;
+
+    // we need to update the cache too as the base class cached its own value
+    CacheBestSize(size);
+
+    return size;
+}
 
 #endif // wxUSE_TREECTRL