]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
Added missing include
[wxWidgets.git] / src / generic / treectlg.cpp
index 4c9305f01ee85cf66fc7a0b00410c6216e1a6917..d30b80d4f0e97e691557f4972a845a67d5cd479f 100644 (file)
@@ -49,7 +49,7 @@
 // array types
 // -----------------------------------------------------------------------------
 
 // array types
 // -----------------------------------------------------------------------------
 
-class WXDLLEXPORT wxGenericTreeItem;
+class WXDLLIMPEXP_FWD_CORE wxGenericTreeItem;
 
 WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
 
 WX_DEFINE_EXPORTED_ARRAY_PTR(wxGenericTreeItem *, wxArrayGenericTreeItems);
 
@@ -548,7 +548,7 @@ wxGenericTreeItem::~wxGenericTreeItem()
 
 void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
 {
 
 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];
     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 wxGenericTreeItem::GetChildrenCount(bool recursively) const
 {
-    size_t count = m_children.Count();
+    size_t count = m_children.GetCount();
     if ( !recursively )
         return count;
 
     if ( !recursively )
         return count;
 
@@ -593,7 +593,7 @@ void wxGenericTreeItem::GetSize( int &x, int &y,
 
     if (IsExpanded())
     {
 
     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 );
         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
     }
 
     // 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,
     for ( size_t n = 0; n < count; n++ )
     {
         wxGenericTreeItem *res = m_children[n]->HitTest( point,
@@ -850,7 +850,14 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
     if (!m_hasFont)
         SetOwnFont(attr.font);
 
     if (!m_hasFont)
         SetOwnFont(attr.font);
 
-    m_dottedPen = wxPen( wxT("grey"), 0, 0 );
+    // this is a misnomer: it's called "dotted pen" but uses (default) wxSOLID
+    // style because we apparently get performance problems when using dotted
+    // pen for drawing in some ports -- but under MSW it seems to work fine
+#ifdef __WXMSW__
+    m_dottedPen = wxPen(*wxLIGHT_GREY, 0, wxDOT);
+#else
+    m_dottedPen = *wxGREY_PEN;
+#endif
 
     SetInitialSize(size);
 
 
     SetInitialSize(size);
 
@@ -1203,7 +1210,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;
     // 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)++);
     }
     {
         return children.Item((*pIndex)++);
     }
@@ -1214,36 +1221,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") );
 wxTreeItemId wxGenericTreeCtrl::GetLastChild(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
@@ -1269,7 +1246,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);
     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
 }
 
 wxTreeItemId wxGenericTreeCtrl::GetPrevSibling(const wxTreeItemId& item) const
@@ -1338,6 +1315,7 @@ wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
 
     wxTreeItemId id = item;
     if (id.IsOk())
 
     wxTreeItemId id = item;
     if (id.IsOk())
@@ -1354,10 +1332,37 @@ wxTreeItemId wxGenericTreeCtrl::GetNextVisible(const wxTreeItemId& item) const
 wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
 wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const
 {
     wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") );
+    wxASSERT_MSG( IsVisible(item), wxT("this item itself should be visible") );
 
 
-    wxFAIL_MSG(wxT("not implemented"));
+    // find out the starting point
+    wxTreeItemId prevItem = GetPrevSibling(item);
+    if ( !prevItem.IsOk() )
+    {
+        prevItem = GetItemParent(item);
+    }
 
 
-    return wxTreeItemId();
+    // find the first visible item after it
+    while ( prevItem.IsOk() && !IsVisible(prevItem) )
+    {
+        prevItem = GetNext(prevItem);
+        if ( !prevItem.IsOk() || prevItem == item )
+        {
+            // there are no visible items before item
+            return wxTreeItemId();
+        }
+    }
+
+    // from there we must be able to navigate until this item
+    while ( prevItem.IsOk() )
+    {
+        const wxTreeItemId nextItem = GetNextVisible(prevItem);
+        if ( !nextItem.IsOk() || nextItem == item )
+            break;
+
+        prevItem = nextItem;
+    }
+
+    return prevItem;
 }
 
 // called by wxTextTreeCtrl when it marks itself for deletion
 }
 
 // called by wxTextTreeCtrl when it marks itself for deletion
@@ -1445,6 +1450,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertItem(const wxTreeItemId& parentId,
     parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
                                                  : previous );
 
     parent->Insert( item, previous == (size_t)-1 ? parent->GetChildren().size()
                                                  : previous );
 
+    InvalidateBestSize();
     return item;
 }
 
     return item;
 }
 
@@ -1479,6 +1485,7 @@ wxTreeItemId wxGenericTreeCtrl::AddRoot(const wxString& text,
         m_current->SetHilight( true );
     }
 
         m_current->SetHilight( true );
     }
 
+    InvalidateBestSize();
     return m_anchor;
 }
 
     return m_anchor;
 }
 
@@ -1510,7 +1517,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId,
 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
 {
     wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item);
 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
 }
 
 // Don't leave edit or selection on a child which is about to disappear
@@ -1539,6 +1546,7 @@ void wxGenericTreeCtrl::DeleteChildren(const wxTreeItemId& itemId)
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
     ChildrenClosing(item);
     item->DeleteChildren(this);
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
     ChildrenClosing(item);
     item->DeleteChildren(this);
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 }
 
 void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
@@ -1603,6 +1611,8 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
         m_select_me = NULL;
 
     delete item;
         m_select_me = NULL;
 
     delete item;
+
+    InvalidateBestSize();
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
 }
 
 void wxGenericTreeCtrl::DeleteAllItems()
@@ -1629,19 +1639,26 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 
     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
 
 
     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
 
-    if ( ProcessEvent( event ) && !event.IsAllowed() )
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
         return;
     }
 
     item->Expand();
     {
         // cancelled by program
         return;
     }
 
     item->Expand();
-    CalculatePositions();
+    if ( !m_freezeCount )
+    {
+        CalculatePositions();
 
 
-    RefreshSubtree(item);
+        RefreshSubtree(item);
+    }
+    else // frozen
+    {
+        m_dirty = true;
+    }
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_EXPANDED);
-    ProcessEvent( event );
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 }
 
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
@@ -1655,7 +1672,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
         return;
 
     wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item);
         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;
     {
         // cancelled by program
         return;
@@ -1666,7 +1683,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 
 #if 0  // TODO why should items be collapsed recursively?
     wxArrayGenericTreeItems& children = item->GetChildren();
 
 #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]);
     for ( size_t n = 0; n < count; n++ )
     {
         Collapse(children[n]);
@@ -1678,7 +1695,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
     RefreshSubtree(item);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
     RefreshSubtree(item);
 
     event.SetEventType(wxEVT_COMMAND_TREE_ITEM_COLLAPSED);
-    ProcessEvent( event );
+    GetEventHandler()->ProcessEvent( event );
 }
 
 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
 }
 
 void wxGenericTreeCtrl::CollapseAndReset(const wxTreeItemId& item)
@@ -1720,7 +1737,7 @@ void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
     if (item->HasChildren())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
     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]);
         for ( size_t n = 0; n < count; ++n )
         {
             UnselectAllChildren(children[n]);
@@ -1756,7 +1773,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?
 
     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;
     for (size_t n=(size_t)(index+1); n<count; ++n)
     {
         if (TagAllChildrenUntilLast(children[n], last_item, select)) return true;
@@ -1776,7 +1793,7 @@ bool wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item, wxG
     if (crt_item->HasChildren())
     {
         wxArrayGenericTreeItems& children = crt_item->GetChildren();
     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))
         for ( size_t n = 0; n < count; ++n )
         {
             if (TagAllChildrenUntilLast(children[n], last_item, select))
@@ -1938,7 +1955,7 @@ size_t wxGenericTreeCtrl::GetSelections(wxArrayTreeItemIds &array) const
     }
     //else: the tree is empty, so no selections
 
     }
     //else: the tree is empty, so no selections
 
-    return array.Count();
+    return array.GetCount();
 }
 
 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 }
 
 void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
@@ -2049,7 +2066,7 @@ void wxGenericTreeCtrl::SortChildren(const wxTreeItemId& itemId)
                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
 
     wxArrayGenericTreeItems& children = item->GetChildren();
                  wxT("wxGenericTreeCtrl::SortChildren is not reentrant") );
 
     wxArrayGenericTreeItems& children = item->GetChildren();
-    if ( children.Count() > 1 )
+    if ( children.GetCount() > 1 )
     {
         m_dirty = true;
 
     {
         m_dirty = true;
 
@@ -2173,7 +2190,7 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
     else if (item->IsBold())
         dc.SetFont(m_boldFont);
 
     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;
     dc.GetTextExtent( item->GetText(), &text_w, &text_h );
 
     int image_h = 0, image_w = 0;
@@ -2232,7 +2249,11 @@ void wxGenericTreeCtrl::PaintItem(wxGenericTreeItem *item, wxDC& dc)
         else
         {
             int flags = wxCONTROL_SELECTED;
         else
         {
             int flags = wxCONTROL_SELECTED;
-            if (m_hasFocus)
+            if (m_hasFocus
+#ifdef __WXMAC__
+                && IsControlActive( (ControlRef)GetHandle() )
+#endif
+            )
                 flags |= wxCONTROL_FOCUSED;
             if ((item == m_current) && (m_hasFocus))
                 flags |= wxCONTROL_CURRENT;
                 flags |= wxCONTROL_FOCUSED;
             if ((item == m_current) && (m_hasFocus))
                 flags |= wxCONTROL_CURRENT;
@@ -2326,7 +2347,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
         // always expand hidden root
         int origY = y;
         wxArrayGenericTreeItems& children = item->GetChildren();
         // 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;
         if (count > 0)
         {
             int n = 0, oldY;
@@ -2374,7 +2395,7 @@ 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.
             // 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
             )
         {
 #endif
             )
         {
@@ -2474,7 +2495,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
     if (item->IsExpanded())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
     if (item->IsExpanded())
     {
         wxArrayGenericTreeItems& children = item->GetChildren();
-        int count = children.Count();
+        int count = children.GetCount();
         if (count > 0)
         {
             int n = 0, oldY;
         if (count > 0)
         {
             int n = 0, oldY;
@@ -2787,7 +2808,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
         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:
             // fall through
 
         case WXK_DOWN:
@@ -2796,6 +2821,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 {
                     wxTreeItemIdValue cookie;
                     wxTreeItemId child = GetFirstChild( m_key_current, cookie );
                 {
                     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;
                 }
                     DoSelectItem( child, unselect_others, extended_select );
                     m_key_current=(wxGenericTreeItem*) child.m_pItem;
                 }
@@ -3464,7 +3492,7 @@ void wxGenericTreeCtrl::CalculateLevel( wxGenericTreeItem *item, wxDC &dc, int l
 
   Recurse:
     wxArrayGenericTreeItems& children = item->GetChildren();
 
   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
     ++level;
     for (n = 0; n < count; ++n )
         CalculateLevel( children[n], dc, level, y );  // recurse
@@ -3561,7 +3589,10 @@ void wxGenericTreeCtrl::Thaw()
 
     if ( --m_freezeCount == 0 )
     {
 
     if ( --m_freezeCount == 0 )
     {
-        Refresh();
+        if ( m_dirty )
+            DoDirtyProcessing();
+        else
+            Refresh();
     }
 }
 
     }
 }
 
@@ -3621,20 +3652,6 @@ wxGenericTreeCtrl::GetClassDefaultAttributes(wxWindowVariant WXUNUSED(variant))
 #endif
 }
 
 #endif
 }
 
-#if WXWIN_COMPATIBILITY_2_4
-
-int wxGenericTreeCtrl::GetItemSelectedImage(const wxTreeItemId& item) const
-{
-    return GetItemImage(item, wxTreeItemIcon_Selected);
-}
-
-void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image)
-{
-    SetItemImage(item, image, wxTreeItemIcon_Selected);
-}
-
-#endif // WXWIN_COMPATIBILITY_2_4
-
 void wxGenericTreeCtrl::DoDirtyProcessing()
 {
     if (m_freezeCount)
 void wxGenericTreeCtrl::DoDirtyProcessing()
 {
     if (m_freezeCount)
@@ -3649,6 +3666,11 @@ void wxGenericTreeCtrl::DoDirtyProcessing()
 
 wxSize wxGenericTreeCtrl::DoGetBestSize() const
 {
 
 wxSize wxGenericTreeCtrl::DoGetBestSize() const
 {
+    // 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
     wxSize size = wxTreeCtrlBase::DoGetBestSize();
 
     // there seems to be an implicit extra border around the items, although
@@ -3656,9 +3678,19 @@ wxSize wxGenericTreeCtrl::DoGetBestSize() const
     // scrollbars appear in a tree with default/best size
     size.IncBy(4, 4);
 
     // scrollbars appear in a tree with default/best size
     size.IncBy(4, 4);
 
-    // avoid caching (necessarily arbitrary) default size for empty tree
-    if ( GetRootItem().IsOk() )
-        CacheBestSize(size);
+    // 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;
 }
 
     return size;
 }