]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
Ensure there is valid context for DrawRectangle
[wxWidgets.git] / src / generic / treectlg.cpp
index c143230058fd2718c2b40878ba172f75d96a25c4..d7193a9febe4380661f50f6e188580b8a453bb14 100644 (file)
@@ -86,7 +86,7 @@ public:
 private:
     wxGenericTreeCtrl *m_owner;
 
 private:
     wxGenericTreeCtrl *m_owner;
 
-    DECLARE_NO_COPY_CLASS(wxTreeRenameTimer)
+    wxDECLARE_NO_COPY_CLASS(wxTreeRenameTimer);
 };
 
 // control used for in-place edit
 };
 
 // control used for in-place edit
@@ -114,7 +114,7 @@ private:
     bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
     bool                m_aboutToFinish;
 
     DECLARE_EVENT_TABLE()
-    DECLARE_NO_COPY_CLASS(wxTreeTextCtrl)
+    wxDECLARE_NO_COPY_CLASS(wxTreeTextCtrl);
 };
 
 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
 };
 
 // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed
@@ -127,12 +127,12 @@ public:
 
     wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
 
 
     wxTreeFindTimer( wxGenericTreeCtrl *owner ) { m_owner = owner; }
 
-    virtual void Notify() { m_owner->m_findPrefix.clear(); }
+    virtual void Notify() { m_owner->ResetFindState(); }
 
 private:
     wxGenericTreeCtrl *m_owner;
 
 
 private:
     wxGenericTreeCtrl *m_owner;
 
-    DECLARE_NO_COPY_CLASS(wxTreeFindTimer)
+    wxDECLARE_NO_COPY_CLASS(wxTreeFindTimer);
 };
 
 // a tree item
 };
 
 // a tree item
@@ -355,7 +355,7 @@ private:
     unsigned int        m_isBold      :1; // render the label in bold font
     unsigned int        m_ownsAttr    :1; // delete attribute when done
 
     unsigned int        m_isBold      :1; // render the label in bold font
     unsigned int        m_ownsAttr    :1; // delete attribute when done
 
-    DECLARE_NO_COPY_CLASS(wxGenericTreeItem)
+    wxDECLARE_NO_COPY_CLASS(wxGenericTreeItem);
 };
 
 // =============================================================================
 };
 
 // =============================================================================
@@ -423,8 +423,8 @@ BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
 END_EVENT_TABLE()
 
 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
 END_EVENT_TABLE()
 
 wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
-                               wxGenericTreeItem *item)
-              : m_itemEdited(item), m_startValue(item->GetText())
+                               wxGenericTreeItem *itm)
+              : m_itemEdited(itm), m_startValue(itm->GetText())
 {
     m_owner = owner;
     m_aboutToFinish = false;
 {
     m_owner = owner;
     m_aboutToFinish = false;
@@ -441,7 +441,7 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
     rect.y -= 2;
     rect.width  += 8;
     rect.height += 4;
     rect.y -= 2;
     rect.width  += 8;
     rect.height += 4;
-#elif defined(__WXMAC__)
+#elif defined(wxOSX_USE_CARBON) && wxOSX_USE_CARBON
     int bestHeight = GetBestSize().y - 8;
     if ( rect.height > bestHeight )
     {
     int bestHeight = GetBestSize().y - 8;
     if ( rect.height > bestHeight )
     {
@@ -454,7 +454,7 @@ wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
     (void)Create(m_owner, wxID_ANY, m_startValue,
                  rect.GetPosition(), rect.GetSize());
 
     (void)Create(m_owner, wxID_ANY, m_startValue,
                  rect.GetPosition(), rect.GetSize());
 
-    SetSelection(-1, -1);
+    SelectAll();
 }
 
 void wxTreeTextCtrl::EndEdit(bool discardChanges)
 }
 
 void wxTreeTextCtrl::EndEdit(bool discardChanges)
@@ -541,7 +541,7 @@ void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
         wxPoint myPos = GetPosition();
         wxSize mySize = GetSize();
         int sx, sy;
         wxPoint myPos = GetPosition();
         wxSize mySize = GetSize();
         int sx, sy;
-        GetTextExtent(GetValue() + _T("M"), &sx, &sy);
+        GetTextExtent(GetValue() + wxT("M"), &sx, &sy);
         if (myPos.x + sx > parentSize.x)
             sx = parentSize.x - myPos.x;
         if (mySize.x > sx)
         if (myPos.x + sx > parentSize.x)
             sx = parentSize.x - myPos.x;
         if (mySize.x > sx)
@@ -902,21 +902,13 @@ BEGIN_EVENT_TABLE(wxGenericTreeCtrl, wxTreeCtrlBase)
     EVT_PAINT          (wxGenericTreeCtrl::OnPaint)
     EVT_SIZE           (wxGenericTreeCtrl::OnSize)
     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse)
     EVT_PAINT          (wxGenericTreeCtrl::OnPaint)
     EVT_SIZE           (wxGenericTreeCtrl::OnSize)
     EVT_MOUSE_EVENTS   (wxGenericTreeCtrl::OnMouse)
+    EVT_KEY_DOWN       (wxGenericTreeCtrl::OnKeyDown)
     EVT_CHAR           (wxGenericTreeCtrl::OnChar)
     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus)
     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus)
     EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip)
 END_EVENT_TABLE()
 
     EVT_CHAR           (wxGenericTreeCtrl::OnChar)
     EVT_SET_FOCUS      (wxGenericTreeCtrl::OnSetFocus)
     EVT_KILL_FOCUS     (wxGenericTreeCtrl::OnKillFocus)
     EVT_TREE_ITEM_GETTOOLTIP(wxID_ANY, wxGenericTreeCtrl::OnGetToolTip)
 END_EVENT_TABLE()
 
-#if !defined(__WXMSW__) || defined(__WXUNIVERSAL__)
-/*
- * wxTreeCtrl has to be a real class or we have problems with
- * the run-time information.
- */
-
-IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl)
-#endif
-
 // -----------------------------------------------------------------------------
 // construction/destruction
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 // construction/destruction
 // -----------------------------------------------------------------------------
@@ -964,6 +956,7 @@ void wxGenericTreeCtrl::Init()
     m_renameTimer = NULL;
 
     m_findTimer = NULL;
     m_renameTimer = NULL;
 
     m_findTimer = NULL;
+    m_findBell = 0;  // default is to not ring bell at all
 
     m_dropEffectAboveItem = false;
 
 
     m_dropEffectAboveItem = false;
 
@@ -973,21 +966,11 @@ void wxGenericTreeCtrl::Init()
     m_lastOnSame = false;
 
 #if defined( __WXMAC__ )
     m_lastOnSame = false;
 
 #if defined( __WXMAC__ )
-#if wxOSX_USE_ATSU_TEXT
-    m_normalFont.MacCreateFromThemeFont( kThemeViewsFont ) ;
-#else
-    m_normalFont.MacCreateFromUIFont( kCTFontViewsFontType ) ;
-#endif
+    m_normalFont = wxFont(wxOSX_SYSTEM_FONT_VIEWS);
 #else
     m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
 #endif
 #else
     m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT );
 #endif
-    m_boldFont = wxFont(m_normalFont.GetPointSize(),
-                        m_normalFont.GetFamily(),
-                        m_normalFont.GetStyle(),
-                        wxBOLD,
-                        m_normalFont.GetUnderlined(),
-                        m_normalFont.GetFaceName(),
-                        m_normalFont.GetEncoding());
+    m_boldFont = m_normalFont.Bold();
 }
 
 bool wxGenericTreeCtrl::Create(wxWindow *parent,
 }
 
 bool wxGenericTreeCtrl::Create(wxWindow *parent,
@@ -1004,10 +987,18 @@ bool wxGenericTreeCtrl::Create(wxWindow *parent,
 
     if (major < 10)
         style |= wxTR_ROW_LINES;
 
     if (major < 10)
         style |= wxTR_ROW_LINES;
+
+    if (style & wxTR_HAS_BUTTONS)
+        style |= wxTR_NO_LINES;
 #endif // __WXMAC__
 
 #endif // __WXMAC__
 
+#ifdef __WXGTK20__
+    if (style & wxTR_HAS_BUTTONS)
+        style |= wxTR_NO_LINES;
+#endif
+
     if ( !wxControl::Create( parent, id, pos, size,
     if ( !wxControl::Create( parent, id, pos, size,
-                             style|wxHSCROLL|wxVSCROLL,
+                             style|wxHSCROLL|wxVSCROLL|wxWANTS_CHARS,
                              validator,
                              name ) )
         return false;
                              validator,
                              name ) )
         return false;
@@ -1055,6 +1046,11 @@ wxGenericTreeCtrl::~wxGenericTreeCtrl()
         delete m_imageListButtons;
 }
 
         delete m_imageListButtons;
 }
 
+void wxGenericTreeCtrl::EnableBellOnNoMatch( bool on )
+{
+    m_findBell = on;
+}
+
 // -----------------------------------------------------------------------------
 // accessors
 // -----------------------------------------------------------------------------
 // -----------------------------------------------------------------------------
 // accessors
 // -----------------------------------------------------------------------------
@@ -1294,14 +1290,8 @@ bool wxGenericTreeCtrl::SetFont( const wxFont &font )
 {
     wxTreeCtrlBase::SetFont(font);
 
 {
     wxTreeCtrlBase::SetFont(font);
 
-    m_normalFont = font ;
-    m_boldFont = wxFont(m_normalFont.GetPointSize(),
-                        m_normalFont.GetFamily(),
-                        m_normalFont.GetStyle(),
-                        wxBOLD,
-                        m_normalFont.GetUnderlined(),
-                        m_normalFont.GetFaceName(),
-                        m_normalFont.GetEncoding());
+    m_normalFont = font;
+    m_boldFont = m_normalFont.Bold();
 
     if (m_anchor)
         m_anchor->RecursiveResetTextSize();
 
     if (m_anchor)
         m_anchor->RecursiveResetTextSize();
@@ -1500,16 +1490,16 @@ wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const
 
 wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 {
 
 wxTreeItemId wxGenericTreeCtrl::GetFirstVisibleItem() const
 {
-    wxTreeItemId id = GetRootItem();
-    if (!id.IsOk())
-        return id;
+    wxTreeItemId itemid = GetRootItem();
+    if (!itemid.IsOk())
+        return itemid;
 
     do
     {
 
     do
     {
-        if (IsVisible(id))
-              return id;
-        id = GetNext(id);
-    } while (id.IsOk());
+        if (IsVisible(itemid))
+              return itemid;
+        itemid = GetNext(itemid);
+    } while (itemid.IsOk());
 
     return wxTreeItemId();
 }
 
     return wxTreeItemId();
 }
@@ -1573,6 +1563,13 @@ void wxGenericTreeCtrl::ResetTextControl()
     m_textCtrl = NULL;
 }
 
     m_textCtrl = NULL;
 }
 
+void wxGenericTreeCtrl::ResetFindState()
+{
+    m_findPrefix.clear();
+    if ( m_findBell )
+        m_findBell = 1;
+}
+
 // find the first item starting with the given prefix after the given item
 wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
                                          const wxString& prefixOrig) const
 // find the first item starting with the given prefix after the given item
 wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
                                          const wxString& prefixOrig) const
@@ -1586,40 +1583,44 @@ wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent,
     // 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
     // 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;
+    wxTreeItemId itemid = idParent;
     if ( prefix.length() == 1 )
     {
     if ( prefix.length() == 1 )
     {
-        id = GetNext(id);
+        itemid = GetNext(itemid);
     }
 
     // look for the item starting with the given prefix after it
     }
 
     // look for the item starting with the given prefix after it
-    while ( id.IsOk() && !GetItemText(id).Lower().StartsWith(prefix) )
+    while ( itemid.IsOk() && !GetItemText(itemid).Lower().StartsWith(prefix) )
     {
     {
-        id = GetNext(id);
+        itemid = GetNext(itemid);
     }
 
     // if we haven't found anything...
     }
 
     // if we haven't found anything...
-    if ( !id.IsOk() )
+    if ( !itemid.IsOk() )
     {
         // ... wrap to the beginning
     {
         // ... wrap to the beginning
-        id = GetRootItem();
+        itemid = GetRootItem();
         if ( HasFlag(wxTR_HIDE_ROOT) )
         {
             // can't select virtual root
         if ( HasFlag(wxTR_HIDE_ROOT) )
         {
             // can't select virtual root
-            id = GetNext(id);
+            itemid = GetNext(itemid);
         }
 
         // and try all the items (stop when we get to the one we started from)
         }
 
         // and try all the items (stop when we get to the one we started from)
-        while ( id.IsOk() && id != idParent &&
-                    !GetItemText(id).Lower().StartsWith(prefix) )
+        while ( itemid.IsOk() && itemid != idParent &&
+                    !GetItemText(itemid).Lower().StartsWith(prefix) )
+        {
+            itemid = GetNext(itemid);
+        }
+        // If we haven't found the item but wrapped back to the one we started
+        // from, id.IsOk() must be false
+        if ( itemid == idParent )
         {
         {
-            id = GetNext(id);
+            itemid = wxTreeItemId();
         }
         }
-        // If we haven't found the item, id.IsOk() will be false, as per
-        // documentation
     }
 
     }
 
-    return id;
+    return itemid;
 }
 
 // -----------------------------------------------------------------------------
 }
 
 // -----------------------------------------------------------------------------
@@ -1776,6 +1777,16 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 
     wxGenericTreeItem *parent = item->GetParent();
 
 
     wxGenericTreeItem *parent = item->GetParent();
 
+    // if the selected item will be deleted, select the parent ...
+    wxGenericTreeItem *to_be_selected = parent;
+    if (parent)
+    {
+        // .. unless there is a next sibling like wxMSW does it
+        int pos = parent->GetChildren().Index( item );
+        if ((int)(parent->GetChildren().GetCount()) > pos+1)
+            to_be_selected = parent->GetChildren().Item( pos+1 );
+    }
+
     // don't keep stale pointers around!
     if ( IsDescendantOf(item, m_key_current) )
     {
     // don't keep stale pointers around!
     if ( IsDescendantOf(item, m_key_current) )
     {
@@ -1791,7 +1802,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
     // a different item, in idle time.
     if ( m_select_me && IsDescendantOf(item, m_select_me) )
     {
     // a different item, in idle time.
     if ( m_select_me && IsDescendantOf(item, m_select_me) )
     {
-        m_select_me = parent;
+        m_select_me = to_be_selected;
     }
 
     if ( IsDescendantOf(item, m_current) )
     }
 
     if ( IsDescendantOf(item, m_current) )
@@ -1802,7 +1813,7 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 
         // m_current = parent;
         m_current = NULL;
 
         // m_current = parent;
         m_current = NULL;
-        m_select_me = parent;
+        m_select_me = to_be_selected;
     }
 
     // remove the item from the tree
     }
 
     // remove the item from the tree
@@ -1840,9 +1851,9 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 {
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
 {
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
-    wxCHECK_RET( item, _T("invalid item in wxGenericTreeCtrl::Expand") );
+    wxCHECK_RET( item, wxT("invalid item in wxGenericTreeCtrl::Expand") );
     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
-                 _T("can't expand hidden root") );
+                 wxT("can't expand hidden root") );
 
     if ( !item->HasPlus() )
         return;
 
     if ( !item->HasPlus() )
         return;
@@ -1877,7 +1888,7 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 {
     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
 void wxGenericTreeCtrl::Collapse(const wxTreeItemId& itemId)
 {
     wxCHECK_RET( !HasFlag(wxTR_HIDE_ROOT) || itemId != GetRootItem(),
-                 _T("can't collapse hidden root") );
+                 wxT("can't collapse hidden root") );
 
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
 
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
@@ -1939,6 +1950,20 @@ void wxGenericTreeCtrl::Unselect()
     }
 }
 
     }
 }
 
+void wxGenericTreeCtrl::ClearFocusedItem()
+{
+    wxTreeItemId item = GetFocusedItem();
+    if ( item.IsOk() )
+        SelectItem(item, false);
+}
+
+void wxGenericTreeCtrl::SetFocusedItem(const wxTreeItemId& item)
+{
+    wxCHECK_RET( item.IsOk(), wxT("invalid tree item") );
+
+    SelectItem(item, true);
+}
+
 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 {
     if (item->IsSelected())
 void wxGenericTreeCtrl::UnselectAllChildren(wxGenericTreeItem *item)
 {
     if (item->IsSelected())
@@ -1969,6 +1994,42 @@ void wxGenericTreeCtrl::UnselectAll()
     }
 }
 
     }
 }
 
+void wxGenericTreeCtrl::SelectChildren(const wxTreeItemId& parent)
+{
+    wxCHECK_RET( HasFlag(wxTR_MULTIPLE),
+                 "this only works with multiple selection controls" );
+
+    UnselectAll();
+
+    if ( !HasChildren(parent) )
+        return;
+
+
+    wxArrayGenericTreeItems&
+        children = ((wxGenericTreeItem*) parent.m_pItem)->GetChildren();
+    size_t count = children.GetCount();
+
+    wxGenericTreeItem *
+        item = (wxGenericTreeItem*) ((wxTreeItemId)children[0]).m_pItem;
+    wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
+    event.m_itemOld = m_current;
+
+    if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
+        return;
+
+    for ( size_t n = 0; n < count; ++n )
+    {
+        m_current = m_key_current = children[n];
+        m_current->SetHilight(true);
+        RefreshSelected();
+    }
+
+
+    event.SetEventType(wxEVT_COMMAND_TREE_SEL_CHANGED);
+    GetEventHandler()->ProcessEvent( event );
+}
+
+
 // Recursive function !
 // To stop we must have crt_item<last_item
 // Algorithm :
 // Recursive function !
 // To stop we must have crt_item<last_item
 // Algorithm :
@@ -2010,7 +2071,8 @@ wxGenericTreeCtrl::TagAllChildrenUntilLast(wxGenericTreeItem *crt_item,
     if (crt_item==last_item)
         return true;
 
     if (crt_item==last_item)
         return true;
 
-    if (crt_item->HasChildren())
+    // We should leave the not shown children of collapsed items alone.
+    if (crt_item->HasChildren() && crt_item->IsExpanded())
     {
         wxArrayGenericTreeItems& children = crt_item->GetChildren();
         size_t count = children.GetCount();
     {
         wxArrayGenericTreeItems& children = crt_item->GetChildren();
         size_t count = children.GetCount();
@@ -2132,15 +2194,16 @@ void wxGenericTreeCtrl::DoSelectItem(const wxTreeItemId& itemId,
 
 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
 {
 
 void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, bool select)
 {
+    wxGenericTreeItem * const item = (wxGenericTreeItem*) itemId.m_pItem;
+    wxCHECK_RET( item, wxT("SelectItem(): invalid tree item") );
+
     if ( select )
     {
     if ( select )
     {
-        DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE));
+        if ( !item->IsSelected() )
+            DoSelectItem(itemId, !HasFlag(wxTR_MULTIPLE));
     }
     else // deselect
     {
     }
     else // deselect
     {
-        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;
         wxTreeEvent event(wxEVT_COMMAND_TREE_SEL_CHANGING, this, item);
         if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() )
             return;
@@ -2216,61 +2279,53 @@ void wxGenericTreeCtrl::EnsureVisible(const wxTreeItemId& item)
 
 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
 {
 
 void wxGenericTreeCtrl::ScrollTo(const wxTreeItemId &item)
 {
-    if (!item.IsOk()) return;
+    if (!item.IsOk())
+        return;
 
 
-    // We have to call this here because the label in
-    // question might just have been added and no screen
-    // update taken place.
+    // update the control before scrolling it
     if (m_dirty)
     if (m_dirty)
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
+    {
+#if defined( __WXMSW__ ) 
         Update();
         Update();
+#elif defined(__WXMAC__)
+        Update();
+        DoDirtyProcessing();
 #else
         DoDirtyProcessing();
 #endif
 #else
         DoDirtyProcessing();
 #endif
+    }
+        
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
     wxGenericTreeItem *gitem = (wxGenericTreeItem*) item.m_pItem;
 
-    // now scroll to the item
-    int item_y = gitem->GetY();
+    int itemY = gitem->GetY();
 
     int start_x = 0;
     int start_y = 0;
     GetViewStart( &start_x, &start_y );
 
     int start_x = 0;
     int start_y = 0;
     GetViewStart( &start_x, &start_y );
-    start_y *= PIXELS_PER_UNIT;
 
 
-    int client_h = 0;
-    int client_w = 0;
-    GetClientSize( &client_w, &client_h );
+    const int clientHeight = GetClientSize().y;
+
+    const int itemHeight = GetLineHeight(gitem) + 2;
 
 
-    if (item_y < start_y+3)
+    if ( itemY + itemHeight > start_y*PIXELS_PER_UNIT + clientHeight )
     {
     {
-        // going down
-        int x = 0;
-        int y = 0;
-        m_anchor->GetSize( x, y, this );
-        y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        int x_pos = GetScrollPos( wxHORIZONTAL );
-        // Item should appear at top
-        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT,
-                       x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT,
-                       x_pos, item_y/PIXELS_PER_UNIT );
+        // need to scroll up by enough to show this item fully
+        itemY += itemHeight - clientHeight;
+#ifdef __WXOSX__
+        // because itemY below will be divided by PIXELS_PER_UNIT it may
+        // be rounded down, with the result of the item still only being 
+        // partially visible, so make sure we are rounding up
+        itemY += PIXELS_PER_UNIT-1;
+#endif
     }
     }
-    else if (item_y+GetLineHeight(gitem) > start_y+client_h)
+    else if ( itemY > start_y*PIXELS_PER_UNIT )
     {
     {
-        // going up
-        int x = 0;
-        int y = 0;
-        m_anchor->GetSize( x, y, this );
-        y += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        x += PIXELS_PER_UNIT+2; // one more scrollbar unit + 2 pixels
-        item_y += PIXELS_PER_UNIT+2;
-        int x_pos = GetScrollPos( wxHORIZONTAL );
-        // Item should appear at bottom
-        SetScrollbars( PIXELS_PER_UNIT, PIXELS_PER_UNIT,
-                       x/PIXELS_PER_UNIT, y/PIXELS_PER_UNIT,
-                       x_pos,
-                       (item_y+GetLineHeight(gitem)-client_h)/PIXELS_PER_UNIT );
+        // item is already fully visible, don't do anything
+        return;
     }
     }
+    //else: scroll down to make this item the top one displayed
+
+    Scroll(-1, itemY/PIXELS_PER_UNIT);
 }
 
 // FIXME: tree sorting functions are not reentrant and not MT-safe!
 }
 
 // FIXME: tree sorting functions are not reentrant and not MT-safe!
@@ -2733,7 +2788,10 @@ wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item,
 #ifdef __WXMAC__
             colText = *wxWHITE;
 #else
 #ifdef __WXMAC__
             colText = *wxWHITE;
 #else
-            colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+            if (m_hasFocus)
+                colText = wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT);
+            else
+                colText = wxSystemSettings::GetColour(wxSYS_COLOUR_LISTBOXHIGHLIGHTTEXT);
 #endif
         }
         else
 #endif
         }
         else
@@ -2849,7 +2907,7 @@ wxGenericTreeCtrl::PaintLevel(wxGenericTreeItem *item,
                 yOrigin = abs(yOrigin);
                 GetClientSize(&width, &height);
 
                 yOrigin = abs(yOrigin);
                 GetClientSize(&width, &height);
 
-                // Move end points to the begining/end of the view?
+                // Move end points to the beginning/end of the view?
                 if (y_mid < yOrigin)
                     y_mid = yOrigin;
                 if (oldY > yOrigin + height)
                 if (y_mid < yOrigin)
                     y_mid = yOrigin;
                 if (oldY > yOrigin + height)
@@ -2987,16 +3045,19 @@ void wxGenericTreeCtrl::OnKillFocus( wxFocusEvent &event )
     event.Skip();
 }
 
     event.Skip();
 }
 
-void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+void wxGenericTreeCtrl::OnKeyDown( wxKeyEvent &event )
 {
 {
+    // send a tree event
     wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
     te.m_evtKey = event;
     if ( GetEventHandler()->ProcessEvent( te ) )
     wxTreeEvent te( wxEVT_COMMAND_TREE_KEY_DOWN, this);
     te.m_evtKey = event;
     if ( GetEventHandler()->ProcessEvent( te ) )
-    {
-        // intercepted by the user code
         return;
         return;
-    }
 
 
+    event.Skip();
+}
+
+void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
+{
     if ( (m_current == 0) || (m_key_current == 0) )
     {
         event.Skip();
     if ( (m_current == 0) || (m_key_current == 0) )
     {
         event.Skip();
@@ -3030,6 +3091,21 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
     // end   : go to last item without opening parents
     // alnum : start or continue searching for the item with this prefix
     int keyCode = event.GetKeyCode();
     // end   : go to last item without opening parents
     // alnum : start or continue searching for the item with this prefix
     int keyCode = event.GetKeyCode();
+
+#ifdef __WXOSX__
+    // Make the keys work as they do in the native control:
+    // right => expand
+    // left => collapse if current item is expanded
+    if (keyCode == WXK_RIGHT)
+    {
+        keyCode = '+';
+    }
+    else if (keyCode == WXK_LEFT && IsExpanded(m_current))
+    {
+        keyCode = '-';
+    }
+#endif // __WXOSX__
+
     switch ( keyCode )
     {
         case '+':
     switch ( keyCode )
     {
         case '+':
@@ -3246,21 +3322,28 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
             if ( !event.HasModifiers() &&
                  ((keyCode >= '0' && keyCode <= '9') ||
                   (keyCode >= 'a' && keyCode <= 'z') ||
             if ( !event.HasModifiers() &&
                  ((keyCode >= '0' && keyCode <= '9') ||
                   (keyCode >= 'a' && keyCode <= 'z') ||
-                  (keyCode >= 'A' && keyCode <= 'Z' )))
+                  (keyCode >= 'A' && keyCode <= 'Z') ||
+                  (keyCode == '_')))
             {
                 // find the next item starting with the given prefix
                 wxChar ch = (wxChar)keyCode;
             {
                 // find the next item starting with the given prefix
                 wxChar ch = (wxChar)keyCode;
+                wxTreeItemId id;
 
 
-                wxTreeItemId id = FindItem(m_current, m_findPrefix + ch);
-                if ( !id.IsOk() )
+                // if the same character is typed multiple times then go to the
+                // next entry starting with that character instead of searching
+                // for an item starting with multiple copies of this character,
+                // this is more useful and is how it works under Windows.
+                if ( m_findPrefix.length() == 1 && m_findPrefix[0] == ch )
                 {
                 {
-                    // no such item
-                    break;
+                    id = FindItem(m_current, ch);
+                }
+                else
+                {
+                    const wxString newPrefix(m_findPrefix + ch);
+                    id = FindItem(m_current, newPrefix);
+                    if ( id.IsOk() )
+                        m_findPrefix = newPrefix;
                 }
                 }
-
-                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
 
                 // also start the timer to reset the current prefix if the user
                 // doesn't press any more alnum keys soon -- we wouldn't want
@@ -3270,7 +3353,32 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
                     m_findTimer = new wxTreeFindTimer(this);
                 }
 
                     m_findTimer = new wxTreeFindTimer(this);
                 }
 
+                // Notice that we should start the timer even if we didn't find
+                // anything to make sure we reset the search state later.
                 m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
                 m_findTimer->Start(wxTreeFindTimer::DELAY, wxTIMER_ONE_SHOT);
+
+                if ( id.IsOk() )
+                {
+                    SelectItem(id);
+
+                    // Reset the bell flag if it had been temporarily disabled
+                    // before.
+                    if ( m_findBell )
+                        m_findBell = 1;
+                }
+                else // No such item
+                {
+                    // Signal it with a bell if enabled.
+                    if ( m_findBell == 1 )
+                    {
+                        ::wxBell();
+
+                        // Disable it for the next unsuccessful match, we only
+                        // beep once, this is usually enough and continuing to
+                        // do it would be annoying.
+                        m_findBell = -1;
+                    }
+                }
             }
             else
             {
             }
             else
             {
@@ -3360,7 +3468,7 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
 wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
                                   wxClassInfo * WXUNUSED(textCtrlClass))
 {
 wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
                                   wxClassInfo * WXUNUSED(textCtrlClass))
 {
-    wxCHECK_MSG( item.IsOk(), NULL, _T("can't edit an invalid item") );
+    wxCHECK_MSG( item.IsOk(), NULL, wxT("can't edit an invalid item") );
 
     wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
 
     wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
@@ -3375,11 +3483,7 @@ wxTextCtrl *wxGenericTreeCtrl::EditLabel(const wxTreeItemId& item,
     // question might just have been added and no screen
     // update taken place.
     if ( m_dirty )
     // question might just have been added and no screen
     // update taken place.
     if ( m_dirty )
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
-        Update();
-#else
         DoDirtyProcessing();
         DoDirtyProcessing();
-#endif
 
     // TODO: use textCtrlClass here to create the control of correct class
     m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
 
     // TODO: use textCtrlClass here to create the control of correct class
     m_textCtrl = new wxTreeTextCtrl(this, itemEdit);
@@ -3400,7 +3504,7 @@ wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const
 void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item),
                                      bool discardChanges)
 {
 void wxGenericTreeCtrl::EndEditLabel(const wxTreeItemId& WXUNUSED(item),
                                      bool discardChanges)
 {
-    wxCHECK_RET( m_textCtrl, _T("not editing label") );
+    wxCHECK_RET( m_textCtrl, wxT("not editing label") );
 
     m_textCtrl->EndEdit(discardChanges);
 }
 
     m_textCtrl->EndEdit(discardChanges);
 }
@@ -3486,9 +3590,21 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
         wxTreeEvent
             hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP,  this, hoverItem);
 
         wxTreeEvent
             hevent(wxEVT_COMMAND_TREE_ITEM_GETTOOLTIP,  this, hoverItem);
 
-        if ( GetEventHandler()->ProcessEvent(hevent) && hevent.IsAllowed() )
+        // setting a tooltip upon leaving a view is getting the tooltip displayed
+        // on the neighbouring view ...
+#ifdef __WXOSX__
+        if ( event.Leaving() )
+            SetToolTip(NULL);
+        else
+#endif
+        if ( GetEventHandler()->ProcessEvent(hevent) )
         {
         {
-            SetToolTip(hevent.m_label);
+            // If the user permitted the tooltip change, update it, otherwise
+            // remove any old tooltip we might have.
+            if ( hevent.IsAllowed() )
+                SetToolTip(hevent.m_label);
+            else
+                SetToolTip(NULL);
         }
     }
 #endif
         }
     }
 #endif
@@ -3576,6 +3692,8 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
             Update();
 #else
 #if defined(__WXMSW__) || defined(__WXMAC__) || defined(__WXGTK20__)
             Update();
 #else
+            // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+            //       instead (needs to be tested!)
             wxYieldIfNeeded();
 #endif
         }
             wxYieldIfNeeded();
 #endif
         }
@@ -3606,9 +3724,11 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
 
         SetCursor(m_oldCursor);
 
 
         SetCursor(m_oldCursor);
 
-#if defined( __WXMSW__ ) || defined(__WXMAC__)
+#if defined( __WXMSW__ ) || defined(__WXMAC__) || defined(__WXGTK20__)
         Update();
 #else
         Update();
 #else
+        // TODO: remove this call or use wxEventLoopBase::GetActive()->YieldFor(wxEVT_CATEGORY_UI)
+        //       instead (needs to be tested!)
         wxYieldIfNeeded();
 #endif
     }
         wxYieldIfNeeded();
 #endif
     }
@@ -3648,7 +3768,7 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             event.Skip(!GetEventHandler()->ProcessEvent(nevent));
 
             // Consistent with MSW (for now), send the ITEM_MENU *after*
             event.Skip(!GetEventHandler()->ProcessEvent(nevent));
 
             // Consistent with MSW (for now), send the ITEM_MENU *after*
-            // the RIGHT_CLICK event. TODO: This behavior may change.
+            // the RIGHT_CLICK event. TODO: This behaviour may change.
             wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU,  this, item);
             nevent2.m_pointDrag = CalcScrolledPosition(pt);
             GetEventHandler()->ProcessEvent(nevent2);
             wxTreeEvent nevent2(wxEVT_COMMAND_TREE_ITEM_MENU,  this, item);
             nevent2.m_pointDrag = CalcScrolledPosition(pt);
             GetEventHandler()->ProcessEvent(nevent2);
@@ -3711,7 +3831,14 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
             // ==> LeftDown() || LeftDClick()
             if ( event.LeftDown() )
             {
             // ==> LeftDown() || LeftDClick()
             if ( event.LeftDown() )
             {
-                m_lastOnSame = item == m_current;
+                // If we click on an already selected item but do it to return
+                // the focus to the control, it shouldn't start editing the
+                // item label because it's too easy to start editing
+                // accidentally (and also because nobody else does it like
+                // this). So only set this flag, used to decide whether we
+                // should start editing the label later, if we already have
+                // focus.
+                m_lastOnSame = item == m_current && HasFocus();
             }
 
             if ( flags & wxTREE_HITTEST_ONITEMBUTTON )
             }
 
             if ( flags & wxTREE_HITTEST_ONITEMBUTTON )
@@ -3952,11 +4079,24 @@ bool wxGenericTreeCtrl::SetForegroundColour(const wxColour& colour)
     return true;
 }
 
     return true;
 }
 
-// Process the tooltip event, to speed up event processing.
-// Doesn't actually get a tooltip.
 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
 {
 void wxGenericTreeCtrl::OnGetToolTip( wxTreeEvent &event )
 {
-    event.Veto();
+#if wxUSE_TOOLTIPS
+    wxTreeItemId itemId = event.GetItem();
+    const wxGenericTreeItem* const pItem = (wxGenericTreeItem*)itemId.m_pItem;
+
+    // Check if the item fits into the client area:
+    if ( pItem->GetX() + pItem->GetWidth() > GetClientSize().x )
+    {
+        // If it doesn't, show its full text in the tooltip.
+        event.SetLabel(pItem->GetText());
+    }
+    else
+#endif // wxUSE_TOOLTIPS
+    {
+        // veto processing the event, nixing any tooltip
+        event.Veto();
+    }
 }
 
 
 }