X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/a9fd42ccebb2534cfd3910bc7108171f4ee6d54b..fb8d7eb7a880f1f2e32d8830f9c5e12b2536e05f:/src/richtext/richtextbuffer.cpp diff --git a/src/richtext/richtextbuffer.cpp b/src/richtext/richtextbuffer.cpp index b68fbfde3c..4847d40e1d 100644 --- a/src/richtext/richtextbuffer.cpp +++ b/src/richtext/richtextbuffer.cpp @@ -10087,6 +10087,8 @@ void wxRichTextTable::ClearTable() { m_cells.Clear(); DeleteChildren(); + m_rowCount = 0; + m_colCount = 0; } bool wxRichTextTable::CreateTable(int rows, int cols) @@ -10239,12 +10241,68 @@ 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) + 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 (!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, rtc); + action->SetObject(this); + action->SetPosition(GetRange().GetStart()); + } + int i, j; for (i = startRow; i < (startRow+noRows); i++) { @@ -10262,25 +10320,68 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows) m_rowCount = m_rowCount - noRows; + if (!rtc->SuppressingUndo()) + { + buffer->SubmitAction(action); + // Finally store the original-state clone; doing so earlier would cause various failures + action->StoreObject(clone); + } + return true; } bool wxRichTextTable::DeleteColumns(int startCol, int noCols) { - wxASSERT((startCol + noCols) < m_colCount); - if ((startCol + noCols) >= m_colCount) + wxASSERT((startCol + noCols) <= m_colCount); + 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 (!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, rtc); + action->SetObject(this); + action->SetPosition(GetRange().GetStart()); + } + bool deleteRows = (noCols == m_colCount); int i, j; for (i = 0; i < m_rowCount; i++) { wxRichTextObjectPtrArray& colArray = m_cells[deleteRows ? 0 : i]; - for (j = startCol; j < (startCol+noCols); j++) + for (j = 0; j < noCols; j++) { - wxRichTextObject* cell = colArray[j]; + wxRichTextObject* cell = colArray[startCol]; RemoveChild(cell, true); + colArray.RemoveAt(startCol); } if (deleteRows) @@ -10291,6 +10392,13 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols) m_rowCount = 0; m_colCount = m_colCount - noCols; + if (!rtc->SuppressingUndo()) + { + buffer->SubmitAction(action); + // Finally store the original-state clone; doing so earlier would cause various failures + action->StoreObject(clone); + } + return true; } @@ -10300,6 +10408,19 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at if (startRow > m_rowCount) return false; + wxRichTextBuffer* buffer = GetBuffer(); + wxRichTextAction* action = NULL; + wxRichTextTable* clone = NULL; + if (!buffer->GetRichTextCtrl()->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, _("Add row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl()); + action->SetObject(this); + action->SetPosition(GetRange().GetStart()); + } + int i, j; for (i = 0; i < noRows; i++) { @@ -10328,6 +10449,14 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at } m_rowCount = m_rowCount + noRows; + + if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + { + buffer->SubmitAction(action); + // Finally store the original-state clone; doing so earlier would cause various failures + action->StoreObject(clone); + } + return true; } @@ -10337,6 +10466,19 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr& if (startCol > m_colCount) return false; + wxRichTextBuffer* buffer = GetBuffer(); + wxRichTextAction* action = NULL; + wxRichTextTable* clone = NULL; + if (!buffer->GetRichTextCtrl()->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, _("Add column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl()); + action->SetObject(this); + action->SetPosition(GetRange().GetStart()); + } + int i, j; for (i = 0; i < m_rowCount; i++) { @@ -10358,6 +10500,13 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr& m_colCount = m_colCount + noCols; + if (!buffer->GetRichTextCtrl()->SuppressingUndo()) + { + buffer->SubmitAction(action); + // Finally store the original-state clone; doing so earlier would cause various failures + action->StoreObject(clone); + } + return true; } @@ -10425,8 +10574,8 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextModule, wxModule) void wxRichTextModuleInit() { wxModule* module = new wxRichTextModule; - module->Init(); wxModule::RegisterModule(module); + wxModule::InitializeModules(); } @@ -10735,10 +10884,21 @@ bool wxRichTextAction::Do() case wxRICHTEXT_CHANGE_OBJECT: { wxRichTextObject* obj = m_objectAddress.GetObject(m_buffer); - // wxRichTextObject* obj = container->GetChildAtPosition(GetRange().GetStart()); - if (obj && m_object) + if (obj && m_object && m_ctrl) { - wxRichTextObjectList::compatibility_iterator node = container->GetChildren().Find(obj); + // 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) { wxRichTextObject* obj = node->GetData(); @@ -10927,13 +11087,16 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent // 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); @@ -10981,7 +11144,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent // 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();