]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
Add doc for wxGraphicsContext.Create(), which is a lightweight context with no target...
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index dfcc768eea2fc7aecb9605f0323d8880d814cc00..4847d40e1d874f30906fa115f30c66ad15fb693f 100644 (file)
@@ -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
@@ -10821,15 +10886,18 @@ bool wxRichTextAction::Do()
             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)
                 {
@@ -11019,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);
@@ -11073,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();