]> git.saurik.com Git - wxWidgets.git/blobdiff - src/generic/treectlg.cpp
Applied patch [ 603104 ] wxX11 wxClientDC, wxPaintDC fix
[wxWidgets.git] / src / generic / treectlg.cpp
index 104b899c6d4ba7ac78e40e65579475fe6e5dcf23..2fbe7cde63aea6449e7ecd0a36b0289812c5750f 100644 (file)
@@ -126,26 +126,19 @@ private:
 class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
 {
 public:
-    wxTreeTextCtrl( wxWindow *parent,
-                    const wxWindowID id,
-                    bool *accept,
-                    wxString *res,
-                    wxGenericTreeCtrl *owner,
-                    const wxString &value = wxEmptyString,
-                    const wxPoint &pos = wxDefaultPosition,
-                    const wxSize &size = wxDefaultSize,
-                    int style = wxSIMPLE_BORDER,
-                    const wxValidator& validator = wxDefaultValidator,
-                    const wxString &name = wxTextCtrlNameStr );
+    wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
 
+protected:
     void OnChar( wxKeyEvent &event );
     void OnKeyUp( wxKeyEvent &event );
     void OnKillFocus( wxFocusEvent &event );
 
+    bool AcceptChanges();
+    void Finish();
+
 private:
-    bool               *m_accept;
-    wxString           *m_res;
     wxGenericTreeCtrl  *m_owner;
+    wxGenericTreeItem  *m_itemEdited;
     wxString            m_startValue;
     bool                m_finished;
 
@@ -329,6 +322,23 @@ static void EventFlagsToSelType(long style,
     unselect_others = !(extended_select || (ctrlDown && is_multiple));
 }
 
+// check if the given item is under another one
+static bool IsDescendantOf(wxGenericTreeItem *parent, wxGenericTreeItem *item)
+{
+    while ( item )
+    {
+        if ( item == parent )
+        {
+            // item is a descendant of parent
+            return TRUE;
+        }
+
+        item = item->GetParent();
+    }
+
+    return FALSE;
+}
+
 // -----------------------------------------------------------------------------
 // wxTreeRenameTimer (internal)
 // -----------------------------------------------------------------------------
@@ -353,99 +363,131 @@ BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
     EVT_KILL_FOCUS     (wxTreeTextCtrl::OnKillFocus)
 END_EVENT_TABLE()
 
-wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
-                                const wxWindowID id,
-                                bool *accept,
-                                wxString *res,
-                                wxGenericTreeCtrl *owner,
-                                const wxString &value,
-                                const wxPoint &pos,
-                                const wxSize &size,
-                                int style,
-                                const wxValidator& validator,
-                                const wxString &name )
-    : wxTextCtrl( parent, id, value, pos, size, style, validator, name )
-{
-    m_res = res;
-    m_accept = accept;
+wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
+                               wxGenericTreeItem *item)
+              : m_itemEdited(item), m_startValue(item->GetText())
+{
     m_owner = owner;
-    (*m_accept) = FALSE;
-    (*m_res) = wxEmptyString;
-    m_startValue = value;
     m_finished = FALSE;
-}
 
-void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
-{
-    if (event.m_keyCode == WXK_RETURN)
+    int w = m_itemEdited->GetWidth(),
+        h = m_itemEdited->GetHeight();
+
+    int x, y;
+    m_owner->CalcScrolledPosition(item->GetX(), item->GetY(), &x, &y);
+
+    int image_h = 0,
+        image_w = 0;
+
+    int image = item->GetCurrentImage();
+    if ( image != NO_IMAGE )
     {
-        (*m_accept) = TRUE;
-        (*m_res) = GetValue();
+        if ( m_owner->m_imageListNormal )
+        {
+            m_owner->m_imageListNormal->GetSize( image, image_w, image_h );
+            image_w += 4;
+        }
+        else
+        {
+            wxFAIL_MSG(_T("you must create an image list to use images!"));
+        }
+    }
 
-        if ((*m_res) != m_startValue)
-            m_owner->OnRenameAccept();
+    // FIXME: what are all these hardcoded 4, 8 and 11s really?
+    x += image_w;
+    w -= image_w + 4;
 
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
+    (void)Create(m_owner, wxID_ANY, m_startValue,
+                 wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8));
+}
 
-        m_finished = TRUE;
-        m_owner->SetFocus(); // This doesn't work. TODO.
+bool wxTreeTextCtrl::AcceptChanges()
+{
+    const wxString value = GetValue();
 
-        return;
+    if ( value == m_startValue )
+    {
+        // nothing changed, always accept
+        return TRUE;
     }
-    if (event.m_keyCode == WXK_ESCAPE)
+
+    if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
     {
-        (*m_accept) = FALSE;
-        (*m_res) = "";
+        // vetoed by the user
+        return FALSE;
+    }
 
-        if (!wxPendingDelete.Member(this))
-            wxPendingDelete.Append(this);
+    // accepted, do rename the item
+    m_owner->SetItemText(m_itemEdited, value);
+
+    return TRUE;
+}
+
+void wxTreeTextCtrl::Finish()
+{
+    if ( !m_finished )
+    {
+        wxPendingDelete.Append(this);
 
         m_finished = TRUE;
+
         m_owner->SetFocus(); // This doesn't work. TODO.
+    }
+}
 
-        return;
+void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
+{
+    switch ( event.m_keyCode )
+    {
+        case WXK_RETURN:
+            if ( !AcceptChanges() )
+            {
+                // vetoed by the user, don't disappear
+                break;
+            }
+            //else: fall through
+
+        case WXK_ESCAPE:
+            Finish();
+            break;
+
+        default:
+            event.Skip();
     }
-    event.Skip();
 }
 
 void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
 {
-    if (m_finished)
+    if ( !m_finished )
     {
-        event.Skip();
-        return;
+        // auto-grow the textctrl:
+        wxSize parentSize = m_owner->GetSize();
+        wxPoint myPos = GetPosition();
+        wxSize mySize = GetSize();
+        int sx, sy;
+        GetTextExtent(GetValue() + _T("M"), &sx, &sy);
+        if (myPos.x + sx > parentSize.x)
+            sx = parentSize.x - myPos.x;
+        if (mySize.x > sx)
+            sx = mySize.x;
+        SetSize(sx, -1);
     }
 
-    // auto-grow the textctrl:
-    wxSize parentSize = m_owner->GetSize();
-    wxPoint myPos = GetPosition();
-    wxSize mySize = GetSize();
-    int sx, sy;
-    GetTextExtent(GetValue() + _T("M"), &sx, &sy);
-    if (myPos.x + sx > parentSize.x) sx = parentSize.x - myPos.x;
-    if (mySize.x > sx) sx = mySize.x;
-    SetSize(sx, -1);
-
     event.Skip();
 }
 
 void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
 {
-    if (m_finished)
+    if ( m_finished )
     {
         event.Skip();
         return;
     }
 
-    if (!wxPendingDelete.Member(this))
-        wxPendingDelete.Append(this);
-
-    (*m_accept) = TRUE;
-    (*m_res) = GetValue();
-
-    if ((*m_res) != m_startValue)
-        m_owner->OnRenameAccept();
+    if ( AcceptChanges() )
+    {
+        Finish();
+    }
 }
 
 // -----------------------------------------------------------------------------
@@ -835,9 +877,17 @@ size_t wxGenericTreeCtrl::GetChildrenCount(const wxTreeItemId& item, bool recurs
 
 void wxGenericTreeCtrl::SetWindowStyle(const long styles)
 {
-        // right now, just sets the styles.  Eventually, we may
-        // want to update the inherited styles, but right now
-        // none of the parents has updatable styles
+    if (!HasFlag(wxTR_HIDE_ROOT) && (styles & wxTR_HIDE_ROOT))
+    {
+        // if we will hide the root, make sure children are visible
+        m_anchor->SetHasPlus();
+        m_anchor->Expand();
+        CalculatePositions();
+    }
+
+    // right now, just sets the styles.  Eventually, we may
+    // want to update the inherited styles, but right now
+    // none of the parents has updatable styles
     m_windowStyle = styles;
     m_dirty = TRUE;
 }
@@ -1383,33 +1433,31 @@ void wxGenericTreeCtrl::Delete(const wxTreeItemId& itemId)
 
     wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem;
 
-    // don't stay with invalid m_key_current or we will crash in
-    // the next call to OnChar()
-    bool changeKeyCurrent = FALSE;
-    wxGenericTreeItem *itemKey = m_key_current;
-    while ( itemKey )
+    wxGenericTreeItem *parent = item->GetParent();
+
+    // don't keep stale pointers around!
+    if ( IsDescendantOf(item, m_key_current) )
     {
-        if ( itemKey == item )
-        {
-            // m_key_current is a descendant of the item being deleted
-            changeKeyCurrent = TRUE;
-            break;
-        }
-        itemKey = itemKey->GetParent();
+        m_key_current = parent;
     }
 
-    wxGenericTreeItem *parent = item->GetParent();
+    if ( IsDescendantOf(item, m_current) )
+    {
+        m_current = parent;
+    }
+
+    // remove the item from the tree
     if ( parent )
     {
         parent->GetChildren().Remove( item );  // remove by value
     }
-
-    if ( changeKeyCurrent )
+    else // deleting the root
     {
-        // may be NULL or not
-        m_key_current = parent;
+        // nothing will be left in the tree
+        m_anchor = NULL;
     }
 
+    // and delete all of its children and the item itself now
     item->DeleteChildren(this);
     SendDeleteEvent(item);
     delete item;
@@ -1419,12 +1467,7 @@ void wxGenericTreeCtrl::DeleteAllItems()
 {
     if ( m_anchor )
     {
-        m_dirty = TRUE;
-
-        m_anchor->DeleteChildren(this);
-        delete m_anchor;
-
-        m_anchor = NULL;
+        Delete(m_anchor);
     }
 }
 
@@ -1463,17 +1506,20 @@ void wxGenericTreeCtrl::Expand(const wxTreeItemId& itemId)
 
 void wxGenericTreeCtrl::ExpandAll(const wxTreeItemId& item)
 {
-    Expand(item);
-    if ( IsExpanded(item) )
+    if ( !HasFlag(wxTR_HIDE_ROOT) || item != GetRootItem())
     {
-        long cookie;
-        wxTreeItemId child = GetFirstChild(item, cookie);
-        while ( child.IsOk() )
-        {
-            ExpandAll(child);
-
-            child = GetNextChild(item, cookie);
-        }
+        Expand(item);
+        if ( !IsExpanded(item) )
+            return;
+    }
+    
+    long cookie;
+    wxTreeItemId child = GetFirstChild(item, cookie);
+    while ( child.IsOk() )
+    {
+        ExpandAll(child);
+        
+        child = GetNextChild(item, cookie);
     }
 }
 
@@ -1537,6 +1583,8 @@ void wxGenericTreeCtrl::Unselect()
     {
         m_current->SetHilight( FALSE );
         RefreshLine( m_current );
+
+        m_current = NULL;
     }
 }
 
@@ -2616,11 +2664,14 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event )
 
         default:
             // do not use wxIsalnum() here
-            if ( !event.HasModifiers() && isalnum(keyCode) )
+            if ( !event.HasModifiers() && 
+                 ((keyCode >= '0' && keyCode <= '9') ||
+                  (keyCode >= 'a' && keyCode <= 'z') ||
+                  (keyCode >= 'A' && keyCode <= 'Z' )))
             {
                 // find the next item starting with the given prefix
                 char ch = (char)keyCode;
-
+                
                 wxTreeItemId id = FindItem(m_current, m_findPrefix + (wxChar)ch);
                 if ( !id.IsOk() )
                 {
@@ -2681,8 +2732,8 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
 
 // get the bounding rectangle of the item (or of its label only)
 bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
-                         wxRect& rect,
-                         bool WXUNUSED(textOnly)) const
+                                        wxRect& rect,
+                                        bool WXUNUSED(textOnly)) const
 {
     wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
 
@@ -2700,78 +2751,46 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
     return TRUE;
 }
 
-/* **** */
-
 void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
 {
-    if (!item.IsOk()) return;
+    wxCHECK_RET( item.IsOk(), _T("can't edit an invalid item") );
 
-    m_currentEdit = (wxGenericTreeItem*) item.m_pItem;
+    wxGenericTreeItem *itemEdit = (wxGenericTreeItem *)item.m_pItem;
 
     wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
-    te.m_item = (long) m_currentEdit;
+    te.m_item = (long) itemEdit;
     te.SetEventObject( this );
-    GetEventHandler()->ProcessEvent( te );
-
-    if (!te.IsAllowed()) return;
+    if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
+    {
+        // vetoed by user
+        return;
+    }
 
     // We have to call this here because the label in
     // question might just have been added and no screen
     // update taken place.
-    if (m_dirty) wxYieldIfNeeded();
+    if ( m_dirty )
+        wxYieldIfNeeded();
 
-    wxString s = m_currentEdit->GetText();
-    int w = m_currentEdit->GetWidth();
-    int h = m_currentEdit->GetHeight();
-    int x, y;
-    CalcScrolledPosition(m_currentEdit->GetX(), m_currentEdit->GetY(), &x, &y);
+    wxTreeTextCtrl *text = new wxTreeTextCtrl(this, itemEdit);
 
-    int image_h = 0;
-    int image_w = 0;
-
-    int image = m_currentEdit->GetCurrentImage();
-    if ( image != NO_IMAGE )
-    {
-        if ( m_imageListNormal )
-        {
-            m_imageListNormal->GetSize( image, image_w, image_h );
-            image_w += 4;
-        }
-        else
-        {
-            wxFAIL_MSG(_T("you must create an image list to use images!"));
-        }
-    }
-    x += image_w;
-    w -= image_w + 4; // I don't know why +4 is needed
-
-    wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1,
-                                              &m_renameAccept,
-                                              &m_renameRes,
-                                              this,
-                                              s,
-                                              wxPoint(x-4,y-4),
-                                              wxSize(w+11,h+8));
     text->SetFocus();
 }
 
-void wxGenericTreeCtrl::OnRenameTimer()
-{
-    Edit( m_current );
-}
-
-void wxGenericTreeCtrl::OnRenameAccept()
+bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
+                                       const wxString& value)
 {
-    // TODO if the validator fails this causes a crash
     wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
-    le.m_item = (long) m_currentEdit;
+    le.m_item = (long) item;
     le.SetEventObject( this );
-    le.m_label = m_renameRes;
-    GetEventHandler()->ProcessEvent( le );
+    le.m_label = value;
 
-    if (!le.IsAllowed()) return;
+    return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
+}
 
-    SetItemText( m_currentEdit, m_renameRes );
+void wxGenericTreeCtrl::OnRenameTimer()
+{
+    Edit( m_current );
 }
 
 void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )