From: Julian Smart Date: Sun, 26 May 2013 15:32:12 +0000 (+0000) Subject: Applied patch for #15189 - avoid crash when deleting focused cell (dghart) X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/4c86168d9aaa36cffc74afbc6abd1ff5b270db64 Applied patch for #15189 - avoid crash when deleting focused cell (dghart) git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@74058 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/include/wx/richtext/richtextbuffer.h b/include/wx/richtext/richtextbuffer.h index ce85bc5e69..761ed468a4 100644 --- a/include/wx/richtext/richtextbuffer.h +++ b/include/wx/richtext/richtextbuffer.h @@ -66,6 +66,7 @@ #include "wx/cmdproc.h" #include "wx/txtstrm.h" #include "wx/variant.h" +#include "wx/position.h" #if wxUSE_DATAOBJ #include "wx/dataobj.h" @@ -5683,6 +5684,11 @@ public: */ virtual bool GetCellRowColumnPosition(long pos, int& row, int& col) const; + /** + Returns the coordinates of the cell with keyboard focus, or (-1,-1) if none. + */ + virtual wxPosition GetFocusedCell() const; + // Operations /** diff --git a/interface/wx/richtext/richtextbuffer.h b/interface/wx/richtext/richtextbuffer.h index 7a12ac6392..7490004cbd 100644 --- a/interface/wx/richtext/richtextbuffer.h +++ b/interface/wx/richtext/richtextbuffer.h @@ -5506,6 +5506,11 @@ public: */ virtual bool GetCellRowColumnPosition(long pos, int& row, int& col) const; + /** + Returns the coordinates of the cell with keyboard focus, or (-1,-1) if none. + */ + virtual wxPosition GetFocusedCell() const; + // Operations /** diff --git a/src/richtext/richtextbuffer.cpp b/src/richtext/richtextbuffer.cpp index dfcc768eea..ec9da81006 100644 --- a/src/richtext/richtextbuffer.cpp +++ b/src/richtext/richtextbuffer.cpp @@ -10241,21 +10241,64 @@ bool wxRichTextTable::SetCellStyle(const wxRichTextSelection& selection, const w return true; } +wxPosition wxRichTextTable::GetFocusedCell() const +{ + wxPosition position(-1, -1); + const wxRichTextObject* focus = GetBuffer()->GetRichTextCtrl()->GetFocusObject(); + + for (int row = 0; row < GetRowCount(); ++row) + { + for (int col = 0; col < GetColumnCount(); ++col) + { + if (GetCell(row, col) == focus) + { + position.SetRow(row); + position.SetCol(col); + return position; + } + } + } + + return position; +} + bool wxRichTextTable::DeleteRows(int startRow, int noRows) { wxASSERT((startRow + noRows) <= m_rowCount); if ((startRow + noRows) > m_rowCount) return false; + wxCHECK_MSG(noRows != m_rowCount, false, "Trying to delete all the cells in a table"); + wxRichTextBuffer* buffer = GetBuffer(); + wxRichTextCtrl* rtc = buffer->GetRichTextCtrl(); + + wxPosition position = GetFocusedCell(); + int focusCol = position.GetCol(); + int focusRow = position.GetRow(); + if (focusRow >= startRow && focusRow < (startRow+noRows)) + { + // Deleting a focused cell causes a segfault later when laying out, due to GetFocusedObject() returning an invalid object + if ((startRow + noRows) < m_rowCount) + { + // There are more rows after the one(s) to be deleted, so set focus in the first of them + rtc->SetFocusObject(GetCell(startRow + noRows, focusCol)); + } + else + { + // Otherwise set focus in the preceding row + rtc->SetFocusObject(GetCell(startRow - 1, focusCol)); + } + } + wxRichTextAction* action = NULL; wxRichTextTable* clone = NULL; - if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + if (!rtc->SuppressingUndo()) { // Create a clone containing the current state of the table. It will be used to Undo the action clone = wxStaticCast(this->Clone(), wxRichTextTable); clone->SetParent(GetParent()); - action = new wxRichTextAction(NULL, _("Delete row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl()); + action = new wxRichTextAction(NULL, _("Delete row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc); action->SetObject(this); action->SetPosition(GetRange().GetStart()); } @@ -10277,7 +10320,7 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows) m_rowCount = m_rowCount - noRows; - if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + if (!rtc->SuppressingUndo()) { buffer->SubmitAction(action); // Finally store the original-state clone; doing so earlier would cause various failures @@ -10293,15 +10336,37 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols) if ((startCol + noCols) > m_colCount) return false; + wxCHECK_MSG(noCols != m_colCount, false, "Trying to delete all the cells in a table"); + wxRichTextBuffer* buffer = GetBuffer(); + wxRichTextCtrl* rtc = buffer->GetRichTextCtrl(); + + wxPosition position = GetFocusedCell(); + int focusCol = position.GetCol(); + int focusRow = position.GetRow(); + if (focusCol >= startCol && focusCol < (startCol+noCols)) + { + // Deleting a focused cell causes a segfault later when laying out, due to GetFocusedObject() returning an invalid object + if ((startCol + noCols) < m_colCount) + { + // There are more columns after the one(s) to be deleted, so set focus in the first of them + rtc->SetFocusObject(GetCell(focusRow, startCol + noCols)); + } + else + { + // Otherwise set focus in the preceding column + rtc->SetFocusObject(GetCell(focusRow, startCol - 1)); + } + } + wxRichTextAction* action = NULL; wxRichTextTable* clone = NULL; - if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + if (!rtc->SuppressingUndo()) { // Create a clone containing the current state of the table. It will be used to Undo the action clone = wxStaticCast(this->Clone(), wxRichTextTable); clone->SetParent(GetParent()); - action = new wxRichTextAction(NULL, _("Delete column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl()); + action = new wxRichTextAction(NULL, _("Delete column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc); action->SetObject(this); action->SetPosition(GetRange().GetStart()); } @@ -10327,7 +10392,7 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols) m_rowCount = 0; m_colCount = m_colCount - noCols; - if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + if (!rtc->SuppressingUndo()) { buffer->SubmitAction(action); // Finally store the original-state clone; doing so earlier would cause various failures