X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/1ec3a9848a6843aca1b3590f636a149dd274efdc..7581faf616eef3617152b9ad05b939999f442502:/src/generic/treectlg.cpp diff --git a/src/generic/treectlg.cpp b/src/generic/treectlg.cpp index 6d56dc596d..f0be2d8723 100644 --- a/src/generic/treectlg.cpp +++ b/src/generic/treectlg.cpp @@ -5,7 +5,7 @@ // Created: 01/02/97 // Modified: 22/10/98 - almost total rewrite, simpler interface (VZ) // Id: $Id$ -// Copyright: (c) 1998 Robert Roebling, Julian Smart and Markus Holzem +// Copyright: (c) 1998 Robert Roebling and Julian Smart // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// @@ -38,6 +38,10 @@ #include "wx/settings.h" #include "wx/dcclient.h" +#ifdef __WXMAC__ + #include "wx/mac/private.h" +#endif + // ----------------------------------------------------------------------------- // array types // ----------------------------------------------------------------------------- @@ -120,36 +124,32 @@ public: private: wxGenericTreeCtrl *m_owner; + + DECLARE_NO_COPY_CLASS(wxTreeRenameTimer) }; // control used for in-place edit 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; DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxTreeTextCtrl) }; // timer used to clear wxGenericTreeCtrl::m_findPrefix if no key was pressed @@ -166,6 +166,8 @@ public: private: wxGenericTreeCtrl *m_owner; + + DECLARE_NO_COPY_CLASS(wxTreeFindTimer) }; // a tree item @@ -294,7 +296,7 @@ private: short m_images[wxTreeItemIcon_Max]; wxCoord m_x; // (virtual) offset from top - short m_y; // (virtual) offset from left + wxCoord m_y; // (virtual) offset from left short m_width; // width of this item unsigned char m_height; // height of this item @@ -305,6 +307,8 @@ private: // children but has a [+] button int m_isBold :1; // render the label in bold font int m_ownsAttr :1; // delete attribute when done + + DECLARE_NO_COPY_CLASS(wxGenericTreeItem) }; // ============================================================================= @@ -329,6 +333,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 +374,134 @@ 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; + + 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 ) + { + 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!")); + } + } + + // FIXME: what are all these hardcoded 4, 8 and 11s really? + x += image_w; + w -= image_w + 4; + + (void)Create(m_owner, wxID_ANY, m_startValue, + wxPoint(x - 4, y - 4), wxSize(w + 11, h + 8)); } -void wxTreeTextCtrl::OnChar( wxKeyEvent &event ) +bool wxTreeTextCtrl::AcceptChanges() { - if (event.m_keyCode == WXK_RETURN) + const wxString value = GetValue(); + + if ( value == m_startValue ) { - (*m_accept) = TRUE; - (*m_res) = GetValue(); + // nothing changed, always accept + return TRUE; + } - if ((*m_res) != m_startValue) - m_owner->OnRenameAccept(); + if ( !m_owner->OnRenameAccept(m_itemEdited, value) ) + { + // vetoed by the user + return FALSE; + } - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); + // accepted, do rename the item + m_owner->SetItemText(m_itemEdited, value); - m_finished = TRUE; - m_owner->SetFocus(); // This doesn't work. TODO. + return TRUE; +} - return; - } - if (event.m_keyCode == WXK_ESCAPE) +void wxTreeTextCtrl::Finish() +{ + if ( !m_finished ) { - (*m_accept) = FALSE; - (*m_res) = ""; + m_owner->ResetTextControl(); - if (!wxPendingDelete.Member(this)) - wxPendingDelete.Append(this); + 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(); + m_owner->OnRenameCancelled(m_itemEdited); + 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(); + } } // ----------------------------------------------------------------------------- @@ -678,7 +734,7 @@ IMPLEMENT_DYNAMIC_CLASS(wxTreeCtrl, wxGenericTreeCtrl) void wxGenericTreeCtrl::Init() { - m_current = m_key_current = m_anchor = (wxGenericTreeItem *) NULL; + m_current = m_key_current = m_anchor = m_select_me = (wxGenericTreeItem *) NULL; m_hasFocus = FALSE; m_dirty = FALSE; @@ -712,6 +768,7 @@ void wxGenericTreeCtrl::Init() m_dragCount = 0; m_isDragging = FALSE; m_dropTarget = m_oldSelection = (wxGenericTreeItem *)NULL; + m_textCtrl = NULL; m_renameTimer = NULL; m_findTimer = NULL; @@ -719,11 +776,13 @@ void wxGenericTreeCtrl::Init() m_lastOnSame = FALSE; m_normalFont = wxSystemSettings::GetFont( wxSYS_DEFAULT_GUI_FONT ); - m_boldFont = wxFont( m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined()); + m_boldFont = wxFont(m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName(), + m_normalFont.GetEncoding()); } bool wxGenericTreeCtrl::Create(wxWindow *parent, @@ -835,9 +894,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; } @@ -868,6 +935,30 @@ wxTreeItemData *wxGenericTreeCtrl::GetItemData(const wxTreeItemId& item) const return ((wxGenericTreeItem*) item.m_pItem)->GetData(); } +wxColour wxGenericTreeCtrl::GetItemTextColour(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetTextColour(); +} + +wxColour wxGenericTreeCtrl::GetItemBackgroundColour(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullColour, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetBackgroundColour(); +} + +wxFont wxGenericTreeCtrl::GetItemFont(const wxTreeItemId& item) const +{ + wxCHECK_MSG( item.IsOk(), wxNullFont, wxT("invalid tree item") ); + + wxGenericTreeItem *pItem = (wxGenericTreeItem*) item.m_pItem; + return pItem->Attr().GetFont(); +} + void wxGenericTreeCtrl::SetItemText(const wxTreeItemId& item, const wxString& text) { wxCHECK_RET( item.IsOk(), wxT("invalid tree item") ); @@ -956,11 +1047,13 @@ bool wxGenericTreeCtrl::SetFont( const wxFont &font ) wxScrolledWindow::SetFont(font); m_normalFont = font ; - m_boldFont = wxFont( m_normalFont.GetPointSize(), - m_normalFont.GetFamily(), - m_normalFont.GetStyle(), - wxBOLD, - m_normalFont.GetUnderlined()); + m_boldFont = wxFont(m_normalFont.GetPointSize(), + m_normalFont.GetFamily(), + m_normalFont.GetStyle(), + wxBOLD, + m_normalFont.GetUnderlined(), + m_normalFont.GetFaceName(), + m_normalFont.GetEncoding()); return TRUE; } @@ -1039,7 +1132,7 @@ bool wxGenericTreeCtrl::IsBold(const wxTreeItemId& item) const // navigation // ----------------------------------------------------------------------------- -wxTreeItemId wxGenericTreeCtrl::GetParent(const wxTreeItemId& item) const +wxTreeItemId wxGenericTreeCtrl::GetItemParent(const wxTreeItemId& item) const { wxCHECK_MSG( item.IsOk(), wxTreeItemId(), wxT("invalid tree item") ); @@ -1139,7 +1232,7 @@ wxTreeItemId wxGenericTreeCtrl::GetNext(const wxTreeItemId& item) const do { toFind = GetNextSibling(p); - p = GetParent(p); + p = GetItemParent(p); } while (p.IsOk() && !toFind.IsOk()); return toFind; } @@ -1186,6 +1279,12 @@ wxTreeItemId wxGenericTreeCtrl::GetPrevVisible(const wxTreeItemId& item) const return wxTreeItemId(); } +// called by wxTextTreeCtrl when it marks itself for deletion +void wxGenericTreeCtrl::ResetTextControl() +{ + m_textCtrl = NULL; +} + // find the first item starting with the given prefix after the given item wxTreeItemId wxGenericTreeCtrl::FindItem(const wxTreeItemId& idParent, const wxString& prefixOrig) const @@ -1383,33 +1482,49 @@ 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(); + // Don't silently change the selection: + // do it properly in idle time, so event + // handlers get called. + + // m_key_current = parent; + m_key_current = NULL; } - wxGenericTreeItem *parent = item->GetParent(); + // m_select_me records whether we need to select + // a different item, in idle time. + if ( m_select_me && IsDescendantOf(item, m_select_me) ) + { + m_select_me = parent; + } + + if ( IsDescendantOf(item, m_current) ) + { + // Don't silently change the selection: + // do it properly in idle time, so event + // handlers get called. + + // m_current = parent; + m_current = NULL; + m_select_me = 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 +1534,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 +1573,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); + Expand(item); + if ( !IsExpanded(item) ) + return; + } - child = GetNextChild(item, cookie); - } + long cookie; + wxTreeItemId child = GetFirstChild(item, cookie); + while ( child.IsOk() ) + { + ExpandAll(child); + + child = GetNextChild(item, cookie); } } @@ -1537,6 +1650,9 @@ void wxGenericTreeCtrl::Unselect() { m_current->SetHilight( FALSE ); RefreshLine( m_current ); + + m_current = NULL; + m_select_me = NULL; } } @@ -1622,6 +1738,7 @@ void wxGenericTreeCtrl::SelectItemRange(wxGenericTreeItem *item1, wxGenericTreeI { // item2 is not necessary after item1 wxGenericTreeItem *first=NULL, *last=NULL; + m_select_me = NULL; // choice first' and 'last' between item1 and item2 if (item1->GetY()GetY()) @@ -1649,6 +1766,8 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, { wxCHECK_RET( itemId.IsOk(), wxT("invalid tree item") ); + m_select_me = NULL; + bool is_single=!(GetWindowStyleFlag() & wxTR_MULTIPLE); wxGenericTreeItem *item = (wxGenericTreeItem*) itemId.m_pItem; @@ -1680,13 +1799,13 @@ void wxGenericTreeCtrl::SelectItem(const wxTreeItemId& itemId, if ( GetEventHandler()->ProcessEvent( event ) && !event.IsAllowed() ) return; - wxTreeItemId parent = GetParent( itemId ); + wxTreeItemId parent = GetItemParent( itemId ); while (parent.IsOk()) { if (!IsExpanded(parent)) Expand( parent ); - parent = GetParent( parent ); + parent = GetItemParent( parent ); } EnsureVisible( itemId ); @@ -2035,7 +2154,20 @@ 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 } else { @@ -2216,10 +2348,26 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level if (HasFlag(wxTR_AQUA_BUTTONS)) { + // This causes update problems, so disabling for now. +#if 0 // def __WXMAC__ + wxMacPortSetter helper(&dc) ; + wxMacWindowClipper clipper(this) ; + wxDC::MacSetupBackgroundForCurrentPort( MacGetBackgroundBrush() ) ; + + int loc_x = x - 5 ; + int loc_y = y_mid - 6 ; + MacWindowToRootWindow( & loc_x , & loc_y ) ; + Rect bounds = { loc_y , loc_x , loc_y + 18 , loc_x + 12 } ; + ThemeButtonDrawInfo info = { kThemeStateActive , item->IsExpanded() ? kThemeDisclosureDown : kThemeDisclosureRight , + kThemeAdornmentNone }; + DrawThemeButton( &bounds, kThemeDisclosureButton , + &info , NULL , NULL , NULL , NULL ) ; +#else if (item->IsExpanded()) dc.DrawBitmap( *m_arrowDown, x-5, y_mid-6, TRUE ); else dc.DrawBitmap( *m_arrowRight, x-5, y_mid-6, TRUE ); +#endif } else { @@ -2292,7 +2440,23 @@ void wxGenericTreeCtrl::PaintLevel( wxGenericTreeItem *item, wxDC &dc, int level // draw line down to last child oldY += GetLineHeight(children[n-1])>>1; if (HasButtons()) y_mid += 5; - dc.DrawLine(x, y_mid, x, oldY); + + // Only draw the portion of the line that is visible, in case it is huge + wxCoord xOrigin=0, yOrigin=0, width, height; + dc.GetDeviceOrigin(&xOrigin, &yOrigin); + yOrigin = abs(yOrigin); + GetClientSize(&width, &height); + + // Move end points to the begining/end of the view? + if (y_mid < yOrigin) + y_mid = yOrigin; + if (oldY > yOrigin + height) + oldY = yOrigin + height; + + // after the adjustments if y_mid is larger than oldY then the line + // isn't visible at all so don't draw anything + if (y_mid < oldY) + dc.DrawLine(x, y_mid, x, oldY); } } } @@ -2436,7 +2600,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) // home : go to root // end : go to last item without opening parents // alnum : start or continue searching for the item with this prefix - int keyCode = event.KeyCode(); + int keyCode = event.GetKeyCode(); switch ( keyCode ) { case '+': @@ -2467,12 +2631,20 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) case ' ': case WXK_RETURN: + if ( !event.HasModifiers() ) { wxTreeEvent event( wxEVT_COMMAND_TREE_ITEM_ACTIVATED, GetId() ); event.m_item = (long) m_current; event.SetEventObject( this ); GetEventHandler()->ProcessEvent( event ); } + + // in any case, also generate the normal key event for this key, + // even if we generated the ACTIVATED event above: this is what + // wxMSW does and it makes sense because you might not want to + // process ACTIVATED event at all and handle Space and Return + // directly (and differently) which would be impossible otherwise + event.Skip(); break; // up goes to the previous sibling or to the last @@ -2482,7 +2654,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) wxTreeItemId prev = GetPrevSibling( m_key_current ); if (!prev) { - prev = GetParent( m_key_current ); + prev = GetItemParent( m_key_current ); if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) { break; // don't go to root if it is hidden @@ -2521,7 +2693,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) // left arrow goes to the parent case WXK_LEFT: { - wxTreeItemId prev = GetParent( m_current ); + wxTreeItemId prev = GetItemParent( m_current ); if ((prev == GetRootItem()) && HasFlag(wxTR_HIDE_ROOT)) { // don't go to root if it is hidden @@ -2557,7 +2729,7 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) wxTreeItemId current = m_key_current; while (current && !next) { - current = GetParent( current ); + current = GetItemParent( current ); if (current) next = GetNextSibling( current ); } } @@ -2616,14 +2788,14 @@ void wxGenericTreeCtrl::OnChar( wxKeyEvent &event ) default: // do not use wxIsalnum() here - if ( !event.HasModifiers() && + 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() ) { @@ -2684,8 +2856,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") ); @@ -2703,78 +2875,70 @@ 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(); - - 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); + if ( m_dirty ) + wxYieldIfNeeded(); - int image_h = 0; - int image_w = 0; + m_textCtrl = new wxTreeTextCtrl(this, itemEdit); - 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 + m_textCtrl->SetFocus(); +} - wxTreeTextCtrl *text = new wxTreeTextCtrl(this, -1, - &m_renameAccept, - &m_renameRes, - this, - s, - wxPoint(x-4,y-4), - wxSize(w+11,h+8)); - text->SetFocus(); +// returns a pointer to the text edit control if the item is being +// edited, NULL otherwise (it's assumed that no more than one item may +// be edited simultaneously) +wxTextCtrl* wxGenericTreeCtrl::GetEditControl() const +{ + return m_textCtrl; } -void wxGenericTreeCtrl::OnRenameTimer() +bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item, + const wxString& value) { - Edit( m_current ); + wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() ); + le.m_item = (long) item; + le.SetEventObject( this ); + le.m_label = value; + le.m_editCancelled = FALSE; + + return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed(); } -void wxGenericTreeCtrl::OnRenameAccept() +void wxGenericTreeCtrl::OnRenameCancelled(wxGenericTreeItem *item) { - // TODO if the validator fails this causes a crash + // let owner know that the edit was cancelled 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; + le.m_label = wxEmptyString; + le.m_editCancelled = FALSE; + GetEventHandler()->ProcessEvent( le ); +} - if (!le.IsAllowed()) return; - SetItemText( m_currentEdit, m_renameRes ); + + +void wxGenericTreeCtrl::OnRenameTimer() +{ + Edit( m_current ); } void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) @@ -2996,6 +3160,18 @@ void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event ) void wxGenericTreeCtrl::OnIdle( wxIdleEvent &WXUNUSED(event) ) { + // Check if we need to select the root item + // because nothing else has been selected. + // Delaying it means that we can invoke event handlers + // as required, when a first item is selected. + if (!HasFlag(wxTR_MULTIPLE) && !GetSelection().IsOk()) + { + if (m_select_me) + SelectItem(m_select_me); + else if (GetRootItem().IsOk()) + SelectItem(GetRootItem()); + } + /* after all changes have been done to the tree control, * we actually redraw the tree when everything is over */