fix crash when the user code refuses to validate the new text when editing the item and a generic label editing code cleanup
git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@16083 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -353,8 +353,7 @@ protected:
|
|||||||
|
|
||||||
wxGenericTreeItem *m_anchor;
|
wxGenericTreeItem *m_anchor;
|
||||||
wxGenericTreeItem *m_current,
|
wxGenericTreeItem *m_current,
|
||||||
*m_key_current,
|
*m_key_current;
|
||||||
*m_currentEdit;
|
|
||||||
unsigned short m_indent;
|
unsigned short m_indent;
|
||||||
unsigned short m_spacing;
|
unsigned short m_spacing;
|
||||||
int m_lineHeight;
|
int m_lineHeight;
|
||||||
@@ -367,7 +366,6 @@ protected:
|
|||||||
m_ownsImageListState,
|
m_ownsImageListState,
|
||||||
m_ownsImageListButtons;
|
m_ownsImageListButtons;
|
||||||
bool m_isDragging; // true between BEGIN/END drag events
|
bool m_isDragging; // true between BEGIN/END drag events
|
||||||
bool m_renameAccept;
|
|
||||||
bool m_lastOnSame; // last click on the same item as prev
|
bool m_lastOnSame; // last click on the same item as prev
|
||||||
wxImageList *m_imageListNormal,
|
wxImageList *m_imageListNormal,
|
||||||
*m_imageListState,
|
*m_imageListState,
|
||||||
@@ -380,7 +378,6 @@ protected:
|
|||||||
wxGenericTreeItem *m_oldSelection;
|
wxGenericTreeItem *m_oldSelection;
|
||||||
|
|
||||||
wxTimer *m_renameTimer;
|
wxTimer *m_renameTimer;
|
||||||
wxString m_renameRes;
|
|
||||||
|
|
||||||
wxBitmap *m_arrowRight,
|
wxBitmap *m_arrowRight,
|
||||||
*m_arrowDown;
|
*m_arrowDown;
|
||||||
@@ -431,7 +428,7 @@ protected:
|
|||||||
void RefreshSelectedUnder(wxGenericTreeItem *item);
|
void RefreshSelectedUnder(wxGenericTreeItem *item);
|
||||||
|
|
||||||
void OnRenameTimer();
|
void OnRenameTimer();
|
||||||
void OnRenameAccept();
|
bool OnRenameAccept(wxGenericTreeItem *item, const wxString& value);
|
||||||
|
|
||||||
void FillArray(wxGenericTreeItem*, wxArrayTreeItemIds&) const;
|
void FillArray(wxGenericTreeItem*, wxArrayTreeItemIds&) const;
|
||||||
void SelectItemRange( wxGenericTreeItem *item1, wxGenericTreeItem *item2 );
|
void SelectItemRange( wxGenericTreeItem *item1, wxGenericTreeItem *item2 );
|
||||||
|
@@ -126,26 +126,19 @@ private:
|
|||||||
class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
|
class WXDLLEXPORT wxTreeTextCtrl: public wxTextCtrl
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
wxTreeTextCtrl( wxWindow *parent,
|
wxTreeTextCtrl(wxGenericTreeCtrl *owner, wxGenericTreeItem *item);
|
||||||
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 );
|
|
||||||
|
|
||||||
|
protected:
|
||||||
void OnChar( wxKeyEvent &event );
|
void OnChar( wxKeyEvent &event );
|
||||||
void OnKeyUp( wxKeyEvent &event );
|
void OnKeyUp( wxKeyEvent &event );
|
||||||
void OnKillFocus( wxFocusEvent &event );
|
void OnKillFocus( wxFocusEvent &event );
|
||||||
|
|
||||||
|
bool AcceptChanges();
|
||||||
|
void Finish();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool *m_accept;
|
|
||||||
wxString *m_res;
|
|
||||||
wxGenericTreeCtrl *m_owner;
|
wxGenericTreeCtrl *m_owner;
|
||||||
|
wxGenericTreeItem *m_itemEdited;
|
||||||
wxString m_startValue;
|
wxString m_startValue;
|
||||||
bool m_finished;
|
bool m_finished;
|
||||||
|
|
||||||
@@ -353,99 +346,131 @@ BEGIN_EVENT_TABLE(wxTreeTextCtrl,wxTextCtrl)
|
|||||||
EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus)
|
EVT_KILL_FOCUS (wxTreeTextCtrl::OnKillFocus)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
wxTreeTextCtrl::wxTreeTextCtrl( wxWindow *parent,
|
wxTreeTextCtrl::wxTreeTextCtrl(wxGenericTreeCtrl *owner,
|
||||||
const wxWindowID id,
|
wxGenericTreeItem *item)
|
||||||
bool *accept,
|
: m_itemEdited(item), m_startValue(item->GetText())
|
||||||
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;
|
|
||||||
m_owner = owner;
|
m_owner = owner;
|
||||||
(*m_accept) = FALSE;
|
|
||||||
(*m_res) = wxEmptyString;
|
|
||||||
m_startValue = value;
|
|
||||||
m_finished = FALSE;
|
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));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool wxTreeTextCtrl::AcceptChanges()
|
||||||
|
{
|
||||||
|
const wxString value = GetValue();
|
||||||
|
|
||||||
|
if ( value == m_startValue )
|
||||||
|
{
|
||||||
|
// nothing changed, always accept
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !m_owner->OnRenameAccept(m_itemEdited, value) )
|
||||||
|
{
|
||||||
|
// vetoed by the user
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
|
void wxTreeTextCtrl::OnChar( wxKeyEvent &event )
|
||||||
{
|
{
|
||||||
if (event.m_keyCode == WXK_RETURN)
|
switch ( event.m_keyCode )
|
||||||
{
|
{
|
||||||
(*m_accept) = TRUE;
|
case WXK_RETURN:
|
||||||
(*m_res) = GetValue();
|
if ( !AcceptChanges() )
|
||||||
|
{
|
||||||
|
// vetoed by the user, don't disappear
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
//else: fall through
|
||||||
|
|
||||||
if ((*m_res) != m_startValue)
|
case WXK_ESCAPE:
|
||||||
m_owner->OnRenameAccept();
|
Finish();
|
||||||
|
break;
|
||||||
|
|
||||||
if (!wxPendingDelete.Member(this))
|
default:
|
||||||
wxPendingDelete.Append(this);
|
event.Skip();
|
||||||
|
|
||||||
m_finished = TRUE;
|
|
||||||
m_owner->SetFocus(); // This doesn't work. TODO.
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
if (event.m_keyCode == WXK_ESCAPE)
|
|
||||||
{
|
|
||||||
(*m_accept) = FALSE;
|
|
||||||
(*m_res) = "";
|
|
||||||
|
|
||||||
if (!wxPendingDelete.Member(this))
|
|
||||||
wxPendingDelete.Append(this);
|
|
||||||
|
|
||||||
m_finished = TRUE;
|
|
||||||
m_owner->SetFocus(); // This doesn't work. TODO.
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
event.Skip();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
|
void wxTreeTextCtrl::OnKeyUp( wxKeyEvent &event )
|
||||||
{
|
{
|
||||||
if (m_finished)
|
if ( !m_finished )
|
||||||
{
|
{
|
||||||
event.Skip();
|
// auto-grow the textctrl:
|
||||||
return;
|
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();
|
event.Skip();
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
|
void wxTreeTextCtrl::OnKillFocus( wxFocusEvent &event )
|
||||||
{
|
{
|
||||||
if (m_finished)
|
if ( m_finished )
|
||||||
{
|
{
|
||||||
event.Skip();
|
event.Skip();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!wxPendingDelete.Member(this))
|
if ( AcceptChanges() )
|
||||||
wxPendingDelete.Append(this);
|
{
|
||||||
|
Finish();
|
||||||
(*m_accept) = TRUE;
|
}
|
||||||
(*m_res) = GetValue();
|
|
||||||
|
|
||||||
if ((*m_res) != m_startValue)
|
|
||||||
m_owner->OnRenameAccept();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@@ -2692,8 +2717,8 @@ wxTreeItemId wxGenericTreeCtrl::HitTest(const wxPoint& point, int& flags)
|
|||||||
|
|
||||||
// get the bounding rectangle of the item (or of its label only)
|
// get the bounding rectangle of the item (or of its label only)
|
||||||
bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
|
bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
|
||||||
wxRect& rect,
|
wxRect& rect,
|
||||||
bool WXUNUSED(textOnly)) const
|
bool WXUNUSED(textOnly)) const
|
||||||
{
|
{
|
||||||
wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
|
wxCHECK_MSG( item.IsOk(), FALSE, _T("invalid item in wxGenericTreeCtrl::GetBoundingRect") );
|
||||||
|
|
||||||
@@ -2711,80 +2736,48 @@ bool wxGenericTreeCtrl::GetBoundingRect(const wxTreeItemId& item,
|
|||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* **** */
|
|
||||||
|
|
||||||
void wxGenericTreeCtrl::Edit( const wxTreeItemId& item )
|
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() );
|
wxTreeEvent te( wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, GetId() );
|
||||||
te.m_item = (long) m_currentEdit;
|
te.m_item = (long) itemEdit;
|
||||||
te.SetEventObject( this );
|
te.SetEventObject( this );
|
||||||
GetEventHandler()->ProcessEvent( te );
|
if ( GetEventHandler()->ProcessEvent( te ) && !te.IsAllowed() )
|
||||||
|
{
|
||||||
if (!te.IsAllowed()) return;
|
// vetoed by user
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// We have to call this here because the label in
|
// We have to call this here because the label in
|
||||||
// question might just have been added and no screen
|
// question might just have been added and no screen
|
||||||
// update taken place.
|
// update taken place.
|
||||||
if (m_dirty) wxYieldIfNeeded();
|
if ( m_dirty )
|
||||||
|
wxYieldIfNeeded();
|
||||||
|
|
||||||
wxString s = m_currentEdit->GetText();
|
wxTreeTextCtrl *text = new wxTreeTextCtrl(this, itemEdit);
|
||||||
int w = m_currentEdit->GetWidth();
|
|
||||||
int h = m_currentEdit->GetHeight();
|
|
||||||
int x, y;
|
|
||||||
CalcScrolledPosition(m_currentEdit->GetX(), m_currentEdit->GetY(), &x, &y);
|
|
||||||
|
|
||||||
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();
|
text->SetFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxGenericTreeCtrl::OnRenameAccept(wxGenericTreeItem *item,
|
||||||
|
const wxString& value)
|
||||||
|
{
|
||||||
|
wxTreeEvent le( wxEVT_COMMAND_TREE_END_LABEL_EDIT, GetId() );
|
||||||
|
le.m_item = (long) item;
|
||||||
|
le.SetEventObject( this );
|
||||||
|
le.m_label = value;
|
||||||
|
|
||||||
|
return !GetEventHandler()->ProcessEvent( le ) || le.IsAllowed();
|
||||||
|
}
|
||||||
|
|
||||||
void wxGenericTreeCtrl::OnRenameTimer()
|
void wxGenericTreeCtrl::OnRenameTimer()
|
||||||
{
|
{
|
||||||
Edit( m_current );
|
Edit( m_current );
|
||||||
}
|
}
|
||||||
|
|
||||||
void wxGenericTreeCtrl::OnRenameAccept()
|
|
||||||
{
|
|
||||||
// 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.SetEventObject( this );
|
|
||||||
le.m_label = m_renameRes;
|
|
||||||
GetEventHandler()->ProcessEvent( le );
|
|
||||||
|
|
||||||
if (!le.IsAllowed()) return;
|
|
||||||
|
|
||||||
SetItemText( m_currentEdit, m_renameRes );
|
|
||||||
}
|
|
||||||
|
|
||||||
void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
|
void wxGenericTreeCtrl::OnMouse( wxMouseEvent &event )
|
||||||
{
|
{
|
||||||
if ( !m_anchor ) return;
|
if ( !m_anchor ) return;
|
||||||
|
Reference in New Issue
Block a user