]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
Avoid using wxHtmlTag::HasParam() unnecessarily.
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 2eb12f119acd62fce18626f9d4df8be0b7d29c94..e00ff83983f07b9a80e7f4a47162a0ef77adb86c 100644 (file)
@@ -662,7 +662,7 @@ int wxRichTextObject::ConvertPixelsToTenthsMM(int ppi, int pixels, double scale)
 
 // Draw the borders and background for the given rectangle and attributes.
 // Width and height are taken to be the outer margin size, not the content.
-bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags)
+bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, const wxRichTextAttr& attr, const wxRect& boxRect, int flags, wxRichTextObject* obj)
 {
     // Assume boxRect is the area around the content
     wxRect marginRect = boxRect;
@@ -692,12 +692,24 @@ bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, con
 
     if (flags & wxRICHTEXT_DRAW_GUIDELINES)
     {
-        wxRichTextAttr editBorderAttr = attr;
+        wxRichTextAttr editBorderAttr;
         // TODO: make guideline colour configurable
         editBorderAttr.GetTextBoxAttr().GetBorder().SetColour(*wxLIGHT_GREY);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS);
         editBorderAttr.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID);
 
+        if (obj)
+        {
+            wxRichTextCell* cell = wxDynamicCast(obj, wxRichTextCell);
+            if (cell)
+            {
+                // This ensures that thin lines drawn by adjacent cells (left and above)
+                // don't get overwritten by the guidelines.
+                editBorderAttr.GetTextBoxAttr().GetBorder().GetLeft().Reset();
+                editBorderAttr.GetTextBoxAttr().GetBorder().GetTop().Reset();
+            }
+        }
+
         DrawBorder(dc, buffer, editBorderAttr.GetTextBoxAttr().GetBorder(), borderRect, flags);
     }
 
@@ -1847,7 +1859,7 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, wxRichTextDrawingContext& cont
     int theseFlags = flags;
     if (!GetParent())
         theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
-    DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags);
+    DrawBoxAttributes(dc, GetBuffer(), attr, thisRect, theseFlags, this);
 
     if (wxRichTextBuffer::GetFloatingLayoutMode())
         DrawFloats(dc, context, range, selection, rect, descent, style);
@@ -7711,6 +7723,53 @@ wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuf
     return obj;
 }
 
+bool wxRichTextParagraphLayoutBox::SetObjectPropertiesWithUndo(wxRichTextObject& obj, const wxRichTextProperties& properties)
+{
+    wxRichTextBuffer* buffer = GetBuffer();
+    wxCHECK_MSG(buffer, false, wxT("Invalid buffer"));
+    wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
+    wxCHECK_MSG(rtc, false, wxT("Invalid rtc"));
+
+    wxRichTextAction* action = NULL;
+    wxRichTextObject* clone = NULL;
+
+#if 1
+    if (rtc->SuppressingUndo())
+        obj.SetProperties(properties);
+    else
+    {
+        clone = obj.Clone();
+        clone->SetProperties(obj.GetProperties());
+        action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, obj.GetParentContainer(), rtc);
+        action->SetOldAndNewObjects(& obj, clone);
+        action->SetPosition(obj.GetRange().GetStart());
+        action->SetRange(obj.GetRange());
+        buffer->SubmitAction(action);
+    }
+#else
+    if (!rtc->SuppressingUndo())
+    {
+        // Create a clone containing the current state of the object. It will be used to Undo the action
+        clone = obj.Clone();
+        clone->SetParent(obj.GetParent());
+        action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, rtc->GetFocusObject(), rtc);
+        action->SetObject(&obj);
+        action->SetPosition(GetRange().GetStart());
+    }
+
+    obj.SetProperties(properties);
+
+    if (!rtc->SuppressingUndo())
+    {
+        buffer->SubmitAction(action);
+        // Finally store the original-state clone; doing so earlier would cause various failures
+        action->StoreObject(clone);
+    }
+#endif
+
+    return true;
+}
+
 /// Get the style that is appropriate for a new paragraph at this position.
 /// If the previous paragraph has a paragraph style name, look up the next-paragraph
 /// style.
@@ -9363,8 +9422,6 @@ bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
 {
     wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
 
-    // Now draw the table outline, if any, to ensure there are no breaks caused by
-    // different-coloured cell dividers overwriting the overall table border.
     int colCount = GetColumnCount();
     int rowCount = GetRowCount();
     int col, row;
@@ -9375,7 +9432,7 @@ bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wx
             if (row == 0 || row == (rowCount-1) || col == 0 || col == (colCount-1))
             {
                 wxRichTextCell* cell = GetCell(row, col);
-                if (cell && !cell->GetRange().IsOutside(range))
+                if (cell && cell->IsShown() && !cell->GetRange().IsOutside(range))
                 {
                     wxRect childRect(cell->GetPosition(), cell->GetCachedSize());
                     wxRichTextAttr attr(cell->GetAttributes());
@@ -10524,24 +10581,6 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows)
     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())
@@ -10549,7 +10588,7 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows)
         // 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 = new wxRichTextAction(NULL, _("Delete Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10592,24 +10631,6 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
     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())
@@ -10617,7 +10638,7 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
         // 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 = new wxRichTextAction(NULL, _("Delete Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, rtc);
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10662,12 +10683,13 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at
     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 = new wxRichTextAction(NULL, _("Add Row"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10724,12 +10746,13 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
     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 = new wxRichTextAction(NULL, _("Add Column"), wxRICHTEXT_CHANGE_OBJECT, buffer, this, buffer->GetRichTextCtrl());
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10784,6 +10807,90 @@ bool wxRichTextTable::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
+bool wxRichTextTableBlock::ComputeBlockForSelection(wxRichTextTable* table, wxRichTextCtrl* ctrl, bool requireCellSelection)
+{
+    if (!ctrl)
+        return false;
+
+    ColStart() = 0;
+    ColEnd() = table->GetColumnCount()-1;
+    RowStart() = 0;
+    RowEnd() = table->GetRowCount()-1;
+
+    wxRichTextSelection selection = ctrl->GetSelection();
+    if (selection.IsValid() && selection.GetContainer() == table)
+    {
+        // Start with an invalid block and increase.
+        wxRichTextTableBlock selBlock(-1, -1, -1, -1);
+        wxRichTextRangeArray ranges = selection.GetRanges();
+        int row, col;
+        for (row = 0; row < table->GetRowCount(); row++)
+        {
+            for (col = 0; col < table->GetColumnCount(); col++)
+            {
+                if (selection.WithinSelection(table->GetCell(row, col)->GetRange().GetStart()))
+                {
+                    if (selBlock.ColStart() == -1)
+                        selBlock.ColStart() = col;
+                    if (selBlock.ColEnd() == -1)
+                        selBlock.ColEnd() = col;
+                    if (col < selBlock.ColStart())
+                        selBlock.ColStart() = col;
+                    if (col > selBlock.ColEnd())
+                        selBlock.ColEnd() = col;
+
+                    if (selBlock.RowStart() == -1)
+                        selBlock.RowStart() = row;
+                    if (selBlock.RowEnd() == -1)
+                        selBlock.RowEnd() = row;
+                    if (row < selBlock.RowStart())
+                        selBlock.RowStart() = row;
+                    if (row > selBlock.RowEnd())
+                        selBlock.RowEnd() = row;
+                }
+            }
+        }
+
+        if (selBlock.RowStart() != -1 && selBlock.RowEnd() != -1 && selBlock.ColStart() != -1 && selBlock.ColEnd() != -1)
+            (*this) = selBlock;
+    }
+    else
+    {
+        // See if a whole cell's contents is selected, in which case we can treat the cell as selected.
+        // wxRTC lacks the ability to select a single cell.
+        wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+        if (cell && (!requireCellSelection || (ctrl->HasSelection() && ctrl->GetSelectionRange() == cell->GetOwnRange())))
+        {
+            int row, col;
+            if (table->GetCellRowColumnPosition(cell->GetRange().GetStart(), row, col))
+            {
+                RowStart() = row;
+                RowEnd() = row;
+                ColStart() = col;
+                ColEnd() = col;
+            }
+        }
+    }
+
+    return true;
+}
+
+// Does this block represent the whole table?
+bool wxRichTextTableBlock::IsWholeTable(wxRichTextTable* table) const
+{
+    return (ColStart() == 0 && RowStart() == 0 && ColEnd() == (table->GetColumnCount()-1) && RowEnd() == (table->GetRowCount()-1));
+}
+
+// Returns the cell focused in the table, if any
+wxRichTextCell* wxRichTextTableBlock::GetFocusedCell(wxRichTextCtrl* ctrl)
+{
+    if (!ctrl)
+        return NULL;
+
+    wxRichTextCell* cell = wxDynamicCast(ctrl->GetFocusObject(), wxRichTextCell);
+    return cell;
+}
+
 /*
  * Module to initialise and clean up handlers
  */
@@ -11166,6 +11273,12 @@ bool wxRichTextAction::Do()
                 }
             }
 
+            // We can't rely on the current focus-object remaining valid, if it's e.g. a table's cell.
+            // And we can't cope with this in the calling code: a user may later click in the cell
+            // before deciding to Undo() or Redo(). So play safe and set focus to the buffer.
+            if (m_ctrl)
+                m_ctrl->SetFocusObject(m_buffer, false);
+            
             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object,
             // Layout() would stop prematurely at the top level.
             // Invalidate the whole buffer if there were floating objects
@@ -11174,7 +11287,7 @@ bool wxRichTextAction::Do()
             else
                 container->InvalidateHierarchy(GetRange());
 
-            UpdateAppearance(GetPosition());
+            UpdateAppearance(GetPosition(), true);
 
             // TODO: send new kind of modification event