Fix infinite recursion if wxGrid is modified from event handler
Calling wxGrid::{Insert,Delete}{Rows,Cols}() from wxEVT_GRID_CELL_CHANGE event handler resulted in infinite recursion because it tried to hide the grid editor control again, which resulted in another CELL_CHANGE event being generated and so on. Break this infinite recursion in the usual way, i.e. by updating the state of wxGrid before invoking the user-defined event handler. This required separating SaveEditControlValue() in 2 functions, the main one retaining IsCellEditControlEnabled() check for compatibility, and the new DoSaveEditControlValue() that can be called even after disabling the editor. Closes #2287. Closes https://github.com/wxWidgets/wxWidgets/pull/1540
This commit is contained in:
@@ -2482,6 +2482,10 @@ private:
|
|||||||
void SetNativeHeaderColCount();
|
void SetNativeHeaderColCount();
|
||||||
void SetNativeHeaderColOrder();
|
void SetNativeHeaderColOrder();
|
||||||
|
|
||||||
|
// Unlike the public SaveEditControlValue(), this method doesn't check if
|
||||||
|
// the edit control is shown, but just supposes that it is.
|
||||||
|
void DoSaveEditControlValue();
|
||||||
|
|
||||||
// these sets contain the indices of fixed, i.e. non-resizable
|
// these sets contain the indices of fixed, i.e. non-resizable
|
||||||
// interactively, grid rows or columns and are NULL if there are no fixed
|
// interactively, grid rows or columns and are NULL if there are no fixed
|
||||||
// elements (which is the default)
|
// elements (which is the default)
|
||||||
|
@@ -6858,10 +6858,14 @@ void wxGrid::EnableCellEditControl( bool enable )
|
|||||||
SendEvent(wxEVT_GRID_EDITOR_HIDDEN);
|
SendEvent(wxEVT_GRID_EDITOR_HIDDEN);
|
||||||
|
|
||||||
HideCellEditControl();
|
HideCellEditControl();
|
||||||
SaveEditControlValue();
|
|
||||||
|
|
||||||
// do it after HideCellEditControl()
|
// do it after HideCellEditControl() but before invoking
|
||||||
m_cellEditCtrlEnabled = enable;
|
// user-defined handlers invoked by DoSaveEditControlValue() to
|
||||||
|
// ensure that we don't enter infinite loop if any of them try to
|
||||||
|
// disable the edit control again.
|
||||||
|
m_cellEditCtrlEnabled = false;
|
||||||
|
|
||||||
|
DoSaveEditControlValue();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -7115,36 +7119,41 @@ void wxGrid::SaveEditControlValue()
|
|||||||
{
|
{
|
||||||
if ( IsCellEditControlEnabled() )
|
if ( IsCellEditControlEnabled() )
|
||||||
{
|
{
|
||||||
int row = m_currentCellCoords.GetRow();
|
DoSaveEditControlValue();
|
||||||
int col = m_currentCellCoords.GetCol();
|
|
||||||
|
|
||||||
wxString oldval = GetCellValue(row, col);
|
|
||||||
|
|
||||||
wxGridCellAttr* attr = GetCellAttr(row, col);
|
|
||||||
wxGridCellEditor* editor = attr->GetEditor(this, row, col);
|
|
||||||
|
|
||||||
wxString newval;
|
|
||||||
bool changed = editor->EndEdit(row, col, this, oldval, &newval);
|
|
||||||
|
|
||||||
if ( changed && SendEvent(wxEVT_GRID_CELL_CHANGING, newval) != -1 )
|
|
||||||
{
|
|
||||||
editor->ApplyEdit(row, col, this);
|
|
||||||
|
|
||||||
// for compatibility reasons dating back to wx 2.8 when this event
|
|
||||||
// was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING
|
|
||||||
// didn't exist we allow vetoing this one too
|
|
||||||
if ( SendEvent(wxEVT_GRID_CELL_CHANGED, oldval) == -1 )
|
|
||||||
{
|
|
||||||
// Event has been vetoed, set the data back.
|
|
||||||
SetCellValue(row, col, oldval);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
editor->DecRef();
|
|
||||||
attr->DecRef();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void wxGrid::DoSaveEditControlValue()
|
||||||
|
{
|
||||||
|
int row = m_currentCellCoords.GetRow();
|
||||||
|
int col = m_currentCellCoords.GetCol();
|
||||||
|
|
||||||
|
wxString oldval = GetCellValue(row, col);
|
||||||
|
|
||||||
|
wxGridCellAttr* attr = GetCellAttr(row, col);
|
||||||
|
wxGridCellEditor* editor = attr->GetEditor(this, row, col);
|
||||||
|
|
||||||
|
wxString newval;
|
||||||
|
bool changed = editor->EndEdit(row, col, this, oldval, &newval);
|
||||||
|
|
||||||
|
if ( changed && SendEvent(wxEVT_GRID_CELL_CHANGING, newval) != -1 )
|
||||||
|
{
|
||||||
|
editor->ApplyEdit(row, col, this);
|
||||||
|
|
||||||
|
// for compatibility reasons dating back to wx 2.8 when this event
|
||||||
|
// was called wxEVT_GRID_CELL_CHANGE and wxEVT_GRID_CELL_CHANGING
|
||||||
|
// didn't exist we allow vetoing this one too
|
||||||
|
if ( SendEvent(wxEVT_GRID_CELL_CHANGED, oldval) == -1 )
|
||||||
|
{
|
||||||
|
// Event has been vetoed, set the data back.
|
||||||
|
SetCellValue(row, col, oldval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
editor->DecRef();
|
||||||
|
attr->DecRef();
|
||||||
|
}
|
||||||
|
|
||||||
void wxGrid::OnHideEditor(wxCommandEvent& WXUNUSED(event))
|
void wxGrid::OnHideEditor(wxCommandEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
DisableCellEditControl();
|
DisableCellEditControl();
|
||||||
|
Reference in New Issue
Block a user