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());
}
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
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());
}
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
wxRichTextObject* obj = m_objectAddress.GetObject(m_buffer);
if (obj && m_object && m_ctrl)
{
- // If the cloned object is unparented it will cause layout asserts later
- // An alternative (would it always be valid?) could be to do: m_object->SetParent(obj->GetParent())
- wxCHECK_MSG(m_object->GetParent(), false, "The stored object must have a valid parent");
-
// The plan is to swap the current object with the stored, previous-state, clone
// We can't get 'node' from the containing buffer (as it doesn't directly store objects)
// so use the parent paragraph
wxRichTextParagraph* para = wxDynamicCast(obj->GetParent(), wxRichTextParagraph);
wxCHECK_MSG(para, false, "Invalid parent paragraph");
+
+ // The stored object, m_object, may have a stale parent paragraph. This would cause
+ // a crash during layout, so use obj's parent para, which should be the correct one.
+ // (An alternative would be to return the parent too from m_objectAddress.GetObject(),
+ // or to set obj's parent there before returning)
+ m_object->SetParent(para);
+
wxRichTextObjectList::compatibility_iterator node = para->GetChildren().Find(obj);
if (node)
{
// find the first line which is being drawn at the same position as it was
// before. Since we're talking about a simple insertion, we can assume
// that the rest of the window does not need to be redrawn.
+ long pos = GetRange().GetStart();
- wxRichTextParagraph* para = container->GetParagraphAtPosition(GetPosition());
+ wxRichTextParagraph* para = container->GetParagraphAtPosition(pos, false /* is not caret pos */);
// Since we support floating layout, we should redraw the whole para instead of just
// the first line touching the invalid range.
if (para)
{
- firstY = para->GetPosition().y;
+ // In case something was drawn above the paragraph,
+ // such as a line break, allow a little extra.
+ firstY = para->GetPosition().y - 4;
}
wxRichTextObjectList::compatibility_iterator node = container->GetChildren().Find(para);
// Stop, we're now the same as we were
foundEnd = true;
- lastY = pt.y;
+ lastY = pt.y + line->GetSize().y;
node2 = wxRichTextLineList::compatibility_iterator();
node = wxRichTextObjectList::compatibility_iterator();