]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
moved assertdlg_gtk.[ch] to GTK_LOWLEVEL_SRC/HDR to fix wxUniv/GTK build
[wxWidgets.git] / src / generic / treectlg.cpp
index 0daf721601d712f5c3b3b5b9b7b0c5deb16e2fc5..7b29dca54f673b1df91dd7dfcbea5b866e51fae9 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        treectlg.cpp
+// Name:        src/generic/treectlg.cpp
 // Purpose:     generic tree control implementation
 // Author:      Robert Roebling
 // Created:     01/02/97
 
 #if wxUSE_TREECTRL
 
-#include "wx/treebase.h"
 #include "wx/treectrl.h"
+
+#ifndef WX_PRECOMP
+    #include "wx/dcclient.h"
+    #include "wx/timer.h"
+    #include "wx/settings.h"
+    #include "wx/listbox.h"
+    #include "wx/textctrl.h"
+#endif
+
 #include "wx/generic/treectlg.h"
-#include "wx/timer.h"
-#include "wx/textctrl.h"
 #include "wx/imaglist.h"
-#include "wx/settings.h"
-#include "wx/dcclient.h"
 
 #include "wx/renderer.h"
 
@@ -199,9 +203,9 @@ public:
     wxGenericTreeItem *GetParent() const { return m_parent; }
 
     // operations
-        // deletes all children notifying the treectrl about it if !NULL
-        // pointer given
-    void DeleteChildren(wxGenericTreeCtrl *tree = NULL);
+
+    // deletes all children notifying the treectrl about it
+    void DeleteChildren(wxGenericTreeCtrl *tree);
 
     // get count of all children (and grand children if 'recursively')
     size_t GetChildrenCount(bool recursively = true) const;
@@ -548,11 +552,10 @@ void wxGenericTreeItem::DeleteChildren(wxGenericTreeCtrl *tree)
     for ( size_t n = 0; n < count; n++ )
     {
         wxGenericTreeItem *child = m_children[n];
-        if (tree)
-            tree->SendDeleteEvent(child);
+        tree->SendDeleteEvent(child);
 
         child->DeleteChildren(tree);
-        if (child == tree->m_select_me)
+        if ( child == tree->m_select_me )
             tree->m_select_me = NULL;
         delete child;
     }
@@ -717,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)
@@ -816,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,
@@ -841,7 +852,7 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
 
     m_dottedPen = wxPen( wxT("grey"), 0, 0 );
 
-    SetBestSize(size);
+    SetInitialSize(size);
 
     return true;
 }
@@ -864,7 +875,7 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl()
 // accessors
 // -----------------------------------------------------------------------------
 
-size_t wxGenericTreeCtrl::GetCount() const
+unsigned int wxGenericTreeCtrl::GetCount() const
 {
     if ( !m_anchor )
     {
@@ -872,7 +883,7 @@ size_t wxGenericTreeCtrl::GetCount() const
         return 0;
     }
 
-    size_t count = m_anchor->GetChildrenCount();
+    unsigned int count = m_anchor->GetChildrenCount();
     if ( !HasFlag(wxTR_HIDE_ROOT) )
     {
         // take the root itself into account
@@ -1018,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);
     }
 }
@@ -1386,10 +1403,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;
@@ -1490,9 +1509,7 @@ wxTreeItemId wxGenericTreeCtrl::DoInsertAfter(const wxTreeItemId& parentId,
 
 void wxGenericTreeCtrl::SendDeleteEvent(wxGenericTreeItem *item)
 {
-    wxTreeEvent event( wxEVT_COMMAND_TREE_DELETE_ITEM, GetId() );
-    event.m_item = item;
-    event.SetEventObject( this );
+    wxTreeEvent event(wxEVT_COMMAND_TREE_DELETE_ITEM, this, item);
     ProcessEvent( event );
 }
 
@@ -1610,9 +1627,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     if ( item->IsExpanded() )
         return;
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_EXPANDING, GetId() );
-    event.m_item = item;
-    event.SetEventObject( this );
+    wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_EXPANDING, this, item);
 
     if ( ProcessEvent( event ) && !event.IsAllowed() )
     {
@@ -1629,25 +1644,6 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
     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);
-    }
-}
-
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 {
     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
@@ -1658,9 +1654,7 @@ void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
     if ( !item->IsExpanded() )
         return;
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_COLLAPSING, GetId() );
-    event.m_item = item;
-    event.SetEventObject( this );
+    wxTreeEvent event(wxEVT_COMMAND_TREE_ITEM_COLLAPSING, this, item);
     if ( ProcessEvent( event ) && !event.IsAllowed() )
     {
         // cancelled by program
@@ -1840,10 +1834,8 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
             return;
     }
 
-    wxTreeEvent event( wxEVT_COMMAND_TREE_SEL_CHANGING, GetId() );
-    event.m_item = item;
+    wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
     event.m_itemOld = m_current;
-    event.SetEventObject( this );
     // TODO : Here we don't send any selection mode yet !
 
     if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
@@ -1858,8 +1850,6 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
         parent = GetItemParent( parent );
     }
 
-    EnsureVisible( itemId );
-
     // ctrl press
     if (unselect_others)
     {
@@ -1891,6 +1881,11 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
         RefreshLine( m_current );
     }
 
+    // This can cause idle processing to select the root
+    // if no item is selected, so it must be after the
+    // selection is set
+    EnsureVisible( itemId );
+
     event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
     GetEventHandler()->ProcessEvent( event );
 }
@@ -1905,9 +1900,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 );
     }
 }
 
@@ -1983,7 +1985,7 @@ void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
 #if defined( __WXMSW__ ) || defined(__WXMAC__)
         Update();
 #else
-        wxYieldIfNeeded();
+        DoDirtyProcessing();
 #endif
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
@@ -2194,20 +2196,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
@@ -2229,11 +2218,27 @@ 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)
+                flags |= wxCONTROL_FOCUSED;
+            if ((item == m_current) && (m_hasFocus))
+                flags |= wxCONTROL_CURRENT;
+            wxRendererNative::Get().DrawItemSelectionRect( this, dc, rect, flags );
+        }
+#endif
     }
     else
     {
@@ -2242,16 +2247,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
         }
     }
 
@@ -2321,7 +2359,7 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
 
     if (IsExposed(exposed_x, exposed_y, 10000, h))  // 10000 = very much
     {
-        wxPen *pen =
+        const wxPen *pen =
 #ifndef __WXMAC__
             // don't draw rect outline if we already have the
             // background color under Mac
@@ -2330,9 +2368,21 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level
             wxTRANSPARENT_PEN;
 
         wxColour colText;
-        if ( item->IsSelected() )
+        if ( item->IsSelected()
+#ifdef __WXMAC__
+            // On wxMac, if the tree doesn't have the focus we draw an empty
+            // 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
+#endif
+            )
         {
+#ifdef __WXMAC__
+            colText = *wxWHITE;
+#else
             colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+#endif
         }
         else
         {
@@ -2527,6 +2577,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);
@@ -2566,9 +2626,8 @@ void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
 
 void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 {
-    wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, GetId() );
+    wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
     te.m_evtKey = event;
-    te.SetEventObject( this );
     if ( GetEventHandler()->ProcessEvent( te ) )
     {
         // intercepted by the user code
@@ -2588,6 +2647,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
@@ -2615,7 +2682,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
@@ -2634,22 +2701,19 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                 wxRect ItemRect;
                 GetBoundingRect(m_current, ItemRect, true);
 
-                wxTreeEvent eventMenu( wxEVT_COMMAND_TREE_ITEM_MENU, GetId() );
-                eventMenu.m_item = m_current;
+                wxTreeEvent eventMenu(wxEVT_COMMAND_TREE_ITEM_MENU, this, m_current);
                 // Use the left edge, vertical middle
                 eventMenu.m_pointDrag = wxPoint(ItemRect.GetX(),
                                                 ItemRect.GetY() + ItemRect.GetHeight() / 2);
-                eventMenu.SetEventObject( this );
                 GetEventHandler()->ProcessEvent( eventMenu );
-                break;
             }
+            break;
+
         case ' ':
         case WXK_RETURN:
             if ( !event.HasModifiers() )
             {
-                wxTreeEvent eventAct( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                eventAct.m_item = m_current;
-                eventAct.SetEventObject( this );
+                wxTreeEvent eventAct(wxEVT_COMMAND_TREE_ITEM_ACTIVATED, this, m_current);
                 GetEventHandler()->ProcessEvent( eventAct );
             }
 
@@ -2838,11 +2902,9 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     }
 }
 
-wxTreeItemId wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags)
+wxTreeItemId
+wxGenericTreeCtrl::DoTreeHitTest(const wxPoint& point, int& flags) const
 {
-    // JACS: removed wxYieldIfNeeded() because it can cause the window
-    // to be deleted from under us if a close window event is pending
-
     int w, h;
     GetSize(&w, &h);
     flags=0;
@@ -2877,12 +2939,9 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
 
     wxGenericTreeItem *i = (wxGenericTreeItem*) item.m_pItem;
 
-    int startX, startY;
-    GetViewStart(& startX, & startY);
-
     if ( textOnly )
     {
-        rect.x = i->GetX() - startX*PIXELS_PER_UNIT;
+        rect.x = i->GetX();
         rect.width = i->GetWidth();
 
         if ( m_imageListNormal )
@@ -2898,9 +2957,12 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
         rect.width = GetClientSize().x;
     }
 
-    rect.y = i->GetY() - startY*PIXELS_PER_UNIT;
+    rect.y = i->GetY();
     rect.height = GetLineHeight(i);
 
+    // we have to return the logical coordinates, not physical ones
+    rect.SetTopLeft(CalcScrolledPosition(rect.GetTopLeft()));
+
     return true;
 }
 
@@ -2911,9 +2973,7 @@ wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
 
     wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
-    wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
-    te.m_item = itemEdit;
-    te.SetEventObject( this );
+    wxTreeEvent te(wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, this, itemEdit);
     if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
     {
         // vetoed by user
@@ -2927,7 +2987,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
@@ -2957,9 +3017,7 @@ void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item),
 bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
                                        const wxString& value)
 {
-    wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = item;
-    le.SetEventObject( this );
+    wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
     le.m_label = value;
     le.m_editCancelled = false;
 
@@ -2969,9 +3027,7 @@ bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
 void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item)
 {
     // let owner know that the edit was cancelled
-    wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = item;
-    le.SetEventObject( this );
+    wxTreeEvent le(wxEVT_COMMAND_TREE_END_LABEL_EDIT, this, item);
     le.m_label = wxEmptyString;
     le.m_editCancelled = true;
 
@@ -2985,7 +3041,7 @@ void wxGenericTreeCtrl::OnRenameTimer()
 
 void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 {
-    if ( !m_anchor ) return;
+    if ( !m_anchor )return;
 
     wxPoint pt = CalcUnscrolledPosition(event.GetPosition());
 
@@ -3032,9 +3088,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
     if (underMouseChanged && hoverItem.IsOk() && !m_isDragging && (!m_renameTimer || !m_renameTimer->IsRunning()))
     {
         // Ask the tree control what tooltip (if any) should be shown
-        wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP, GetId());
-        hevent.m_item = hoverItem;
-        hevent.SetEventObject(this);
+        wxTreeEvent hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP,  this, hoverItem);
 
         if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
         {
@@ -3043,11 +3097,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() ||
@@ -3079,9 +3134,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                               ? wxEVT_COMMAND_TREE_BEGIN_RDRAG
                               : wxEVT_COMMAND_TREE_BEGIN_DRAG;
 
-        wxTreeEvent nevent( command, GetId() );
-        nevent.m_item = m_current;
-        nevent.SetEventObject(this);
+        wxTreeEvent nevent(command,  this, m_current);
         nevent.SetPoint(CalcScrolledPosition(pt));
 
         // by default the dragging is not supported, the user code must
@@ -3133,6 +3186,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
     }
     else if ( (event.LeftUp() || event.RightUp()) && m_isDragging )
     {
+        ReleaseMouse();
+
         // erase the highlighting
         DrawDropEffect(m_dropTarget);
 
@@ -3144,19 +3199,15 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         }
 
         // generate the drag end event
-        wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG, GetId());
+        wxTreeEvent eventEndDrag(wxEVT_COMMAND_TREE_END_DRAG,  this, item);
 
-        eventEndDrag.m_item = item;
         eventEndDrag.m_pointDrag = CalcScrolledPosition(pt);
-        eventEndDrag.SetEventObject(this);
 
         (void)GetEventHandler()->ProcessEvent(eventEndDrag);
 
         m_isDragging = false;
         m_dropTarget = (wxGenericTreeItem *)NULL;
 
-        ReleaseMouse();
-
         SetCursor(m_oldCursor);
 
 #if defined( __WXMSW__ ) || defined(__WXMAC__)
@@ -3192,20 +3243,22 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 DoSelectItem(item, true, false);
             }
 
-            wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK, GetId());
-            nevent.m_item = item;
+            wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_RIGHT_CLICK,  this, item);
             nevent.m_pointDrag = CalcScrolledPosition(pt);
-            nevent.SetEventObject(this);
             event.Skip(!GetEventHandler()->ProcessEvent(nevent));
 
             // Consistent with MSW (for now), send the ITEM_MENU *after*
             // the RIGHT_CLICK event. TODO: This behavior may change.
-            wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU, GetId());
-            nevent2.m_item = item;
+            wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU,  this, item);
             nevent2.m_pointDrag = CalcScrolledPosition(pt);
-            nevent2.SetEventObject(this);
             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
@@ -3245,7 +3298,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 m_lastOnSame = false;
             }
         }
-        else // !RightDown() && !LeftUp() ==> LeftDown() || LeftDClick()
+        else // !RightDown() && !MiddleDown() && !LeftUp() ==> LeftDown() || LeftDClick()
         {
             if ( event.LeftDown() )
             {
@@ -3295,10 +3348,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
                 m_lastOnSame = false;
 
                 // send activate event first
-                wxTreeEvent nevent( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() );
-                nevent.m_item = item;
+                wxTreeEvent nevent(wxEVT_COMMAND_TREE_ITEM_ACTIVATED,  this, item);
                 nevent.m_pointDrag = CalcScrolledPosition(pt);
-                nevent.SetEventObject( this );
                 if ( !GetEventHandler()->ProcessEvent( nevent ) )
                 {
                     // if the user code didn't process the activate event,
@@ -3330,17 +3381,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 )
@@ -3443,10 +3487,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();
 
@@ -3462,8 +3512,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);
@@ -3475,7 +3525,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
@@ -3485,7 +3536,8 @@ void wxGenericTreeCtrl::RefreshSelected()
 
 void wxGenericTreeCtrl::RefreshSelectedUnder(wxGenericTreeItem *item)
 {
-    if (m_freezeCount) return;
+    if (m_freezeCount)
+        return;
 
     if ( item->IsSelected() )
         RefreshLine(item);
@@ -3507,7 +3559,7 @@ void wxGenericTreeCtrl::Thaw()
 {
     wxCHECK_RET( m_freezeCount > 0, _T("thawing unfrozen tree control?") );
 
-    if ( !--m_freezeCount )
+    if ( --m_freezeCount == 0 )
     {
         Refresh();
     }
@@ -3522,8 +3574,6 @@ bool wxGenericTreeCtrl::SetBackgroundColour(const wxColour& colour)
     if ( !wxWindow::SetBackgroundColour(colour) )
         return false;
 
-    if (m_freezeCount) return true;
-
     Refresh();
 
     return true;
@@ -3534,8 +3584,6 @@ bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
     if ( !wxWindow::SetForegroundColour(colour) )
         return false;
 
-    if (m_freezeCount) return true;
-
     Refresh();
 
     return true;
@@ -3553,10 +3601,6 @@ void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
 // be removed, as well as the #else case below.
 #define _USE_VISATTR 0
 
-#if _USE_VISATTR
-#include "wx/listbox.h"
-#endif
-
 //static
 wxVisualAttributes
 #if _USE_VISATTR
@@ -3591,4 +3635,47 @@ void wxGenericTreeCtrl::SetItemSelectedImage(const wxTreeItemId& item, int image
 
 #endif // WXWIN_COMPATIBILITY_2_4
 
+void wxGenericTreeCtrl::DoDirtyProcessing()
+{
+    if (m_freezeCount)
+        return;
+
+    m_dirty = false;
+
+    CalculatePositions();
+    Refresh();
+    AdjustMyScrollbars();
+}
+
+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
+    // 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);
+
+    // 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