]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
Misc validity fixes to samples/xrc/rc/*.xrc.
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 4847d40e1d874f30906fa115f30c66ad15fb693f..be804ef4d0eb3783c74a0a20d242a81c354d9da1 100644 (file)
@@ -4,7 +4,6 @@
 // Author:      Julian Smart
 // Modified by:
 // Created:     2005-09-30
 // Author:      Julian Smart
 // Modified by:
 // Created:     2005-09-30
-// RCS-ID:      $Id$
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
 // Copyright:   (c) Julian Smart
 // Licence:     wxWindows licence
 /////////////////////////////////////////////////////////////////////////////
@@ -663,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.
 
 // 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;
 {
     // Assume boxRect is the area around the content
     wxRect marginRect = boxRect;
@@ -693,12 +692,24 @@ bool wxRichTextObject::DrawBoxAttributes(wxDC& dc, wxRichTextBuffer* buffer, con
 
     if (flags & wxRICHTEXT_DRAW_GUIDELINES)
     {
 
     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);
 
         // 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);
     }
 
         DrawBorder(dc, buffer, editBorderAttr.GetTextBoxAttr().GetBorder(), borderRect, flags);
     }
 
@@ -770,7 +781,7 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
             wxBrush brush(col);
             dc.SetPen(pen);
             dc.SetBrush(brush);
             wxBrush brush(col);
             dc.SetPen(pen);
             dc.SetBrush(brush);
-            dc.DrawRectangle(rect.x + rect.width - borderRight, rect.y, borderRight, rect.height);
+            dc.DrawRectangle(rect.x + rect.width - borderRight, rect.y, borderRight, rect.height + 1);
         }
     }
 
         }
     }
 
@@ -827,7 +838,7 @@ bool wxRichTextObject::DrawBorder(wxDC& dc, wxRichTextBuffer* buffer, const wxTe
             wxBrush brush(col);
             dc.SetPen(pen);
             dc.SetBrush(brush);
             wxBrush brush(col);
             dc.SetPen(pen);
             dc.SetBrush(brush);
-            dc.DrawRectangle(rect.x, rect.y + rect.height - borderBottom, rect.width, borderBottom);
+            dc.DrawRectangle(rect.x, rect.y + rect.height - borderBottom + 1, rect.width, borderBottom);
         }
     }
 
         }
     }
 
@@ -1841,14 +1852,14 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, wxRichTextDrawingContext& cont
     context.ApplyVirtualAttributes(attr, this);
 
     int flags = style;
     context.ApplyVirtualAttributes(attr, this);
 
     int flags = style;
-    if (selection.IsValid() && GetParentContainer() != this && selection.WithinSelection(GetRange().GetStart(), GetParentContainer()))
+    if (selection.IsValid() && GetParentContainer() != this && selection.GetContainer() == this && selection.WithinSelection(GetRange().GetStart(), GetParentContainer()))
         flags |= wxRICHTEXT_DRAW_SELECTED;
 
     // Don't draw guidelines if at top level
     int theseFlags = flags;
     if (!GetParent())
         theseFlags &= ~wxRICHTEXT_DRAW_GUIDELINES;
         flags |= wxRICHTEXT_DRAW_SELECTED;
 
     // Don't draw guidelines if at top level
     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);
 
     if (wxRichTextBuffer::GetFloatingLayoutMode())
         DrawFloats(dc, context, range, selection, rect, descent, style);
@@ -7447,7 +7458,10 @@ bool wxRichTextParagraphLayoutBox::InsertParagraphsWithUndo(wxRichTextBuffer* bu
 /// Submit command to insert the given text
 bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags)
 {
 /// Submit command to insert the given text
 bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRichTextCtrl* ctrl, int flags)
 {
-    return ctrl->GetFocusObject()->InsertTextWithUndo(this, pos, text, ctrl, flags);
+    if (ctrl)
+        return ctrl->GetFocusObject()->InsertTextWithUndo(this, pos, text, ctrl, flags);
+    else
+        return wxRichTextParagraphLayoutBox::InsertTextWithUndo(this, pos, text, ctrl, flags);
 }
 
 /// Submit command to insert the given text
 }
 
 /// Submit command to insert the given text
@@ -7709,6 +7723,39 @@ wxRichTextField* wxRichTextParagraphLayoutBox::InsertFieldWithUndo(wxRichTextBuf
     return obj;
 }
 
     return obj;
 }
 
+bool wxRichTextParagraphLayoutBox::SetObjectPropertiesWithUndo(wxRichTextObject& obj, const wxRichTextProperties& properties, wxRichTextObject* objToSet)
+{
+    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;
+
+    // The object on which to set properties will usually be 'obj', but use objToSet if it's valid.
+    // This is necessary e.g. on setting a wxRichTextCell's properties, when obj will be the parent table
+    if (objToSet == NULL)
+        objToSet = &obj;
+
+    if (rtc->SuppressingUndo())
+        objToSet->SetProperties(properties);
+    else
+    {
+        clone = obj.Clone();
+        objToSet->SetProperties(properties);
+
+        // The 'true' parameter in the next line says "Ignore first time"; otherwise the objects are prematurely switched
+        action = new wxRichTextAction(NULL, _("Change Properties"), wxRICHTEXT_CHANGE_OBJECT, buffer, obj.GetParentContainer(), rtc, true);
+        action->SetOldAndNewObjects(& obj, clone);
+        action->SetPosition(obj.GetRange().GetStart());
+        action->SetRange(obj.GetRange());
+        buffer->SubmitAction(action);
+    }
+
+    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.
 /// 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.
@@ -7865,11 +7912,14 @@ bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
 
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
     {
 
     if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
     {
-        wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
-        cmd->AddAction(action);
-        cmd->Do();
-        cmd->GetActions().Clear();
-        delete cmd;
+        if (!action->GetIgnoreFirstTime())
+        {
+            wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
+            cmd->AddAction(action);
+            cmd->Do();
+            cmd->GetActions().Clear();
+            delete cmd;
+        }
 
         m_batchedCommand->AddAction(action);
     }
 
         m_batchedCommand->AddAction(action);
     }
@@ -7879,7 +7929,14 @@ bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
         cmd->AddAction(action);
 
         // Only store it if we're not suppressing undo.
         cmd->AddAction(action);
 
         // Only store it if we're not suppressing undo.
-        return GetCommandProcessor()->Submit(cmd, !SuppressingUndo());
+        if (!action->GetIgnoreFirstTime())
+        {
+            return GetCommandProcessor()->Submit(cmd, !SuppressingUndo());
+        }
+        else if (!SuppressingUndo())
+        {
+            GetCommandProcessor()->Store(cmd); // Just store it, without Do()ing anything
+        }
     }
 
     return true;
     }
 
     return true;
@@ -8317,6 +8374,7 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save, wxArrayInt* t
     return wildcard;
 }
 
     return wildcard;
 }
 
+#if wxUSE_FFILE && wxUSE_STREAMS
 /// Load a file
 bool wxRichTextBuffer::LoadFile(const wxString& filename, wxRichTextFileType type)
 {
 /// Load a file
 bool wxRichTextBuffer::LoadFile(const wxString& filename, wxRichTextFileType type)
 {
@@ -8345,7 +8403,9 @@ bool wxRichTextBuffer::SaveFile(const wxString& filename, wxRichTextFileType typ
     else
         return false;
 }
     else
         return false;
 }
+#endif // wxUSE_FFILE && wxUSE_STREAMS
 
 
+#if wxUSE_STREAMS
 /// Load from a stream
 bool wxRichTextBuffer::LoadFile(wxInputStream& stream, wxRichTextFileType type)
 {
 /// Load from a stream
 bool wxRichTextBuffer::LoadFile(wxInputStream& stream, wxRichTextFileType type)
 {
@@ -8374,6 +8434,7 @@ bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, wxRichTextFileType type)
     else
         return false;
 }
     else
         return false;
 }
+#endif // wxUSE_STREAMS
 
 /// Copy the range to the clipboard
 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
 
 /// Copy the range to the clipboard
 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
@@ -9221,6 +9282,22 @@ bool wxRichTextCell::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxR
     return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
 }
 
     return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
 }
 
+int wxRichTextCell::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+{
+    int ret = wxRichTextParagraphLayoutBox::HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
+    if (ret != wxRICHTEXT_HITTEST_NONE)
+    {
+        return ret;
+    }
+    else
+    {
+        textPosition = m_ownRange.GetEnd()-1;
+        *obj = this;
+        *contextObj = this;
+        return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
+    }
+}
+
 /// Copy
 void wxRichTextCell::Copy(const wxRichTextCell& obj)
 {
 /// Copy
 void wxRichTextCell::Copy(const wxRichTextCell& obj)
 {
@@ -9269,18 +9346,20 @@ bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
     else
         caption = _("Cell Properties");
 
     else
         caption = _("Cell Properties");
 
+    // We don't want position and floating controls for a cell.
+    wxRichTextSizePage::ShowPositionControls(false);
+    wxRichTextSizePage::ShowFloatingControls(false);
+    wxRichTextSizePage::ShowAlignmentControls(true);
+
     wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
     cellDlg.SetAttributes(attr);
 
     wxRichTextObjectPropertiesDialog cellDlg(this, wxGetTopLevelParent(parent), wxID_ANY, caption);
     cellDlg.SetAttributes(attr);
 
-    wxRichTextSizePage* sizePage = wxDynamicCast(cellDlg.FindPage(wxCLASSINFO(wxRichTextSizePage)), wxRichTextSizePage);
-    if (sizePage)
-    {
-        // We don't want position and floating controls for a cell.
-        sizePage->ShowPositionControls(false);
-        sizePage->ShowFloatingControls(false);
-    }
+    bool ok = (cellDlg.ShowModal() == wxID_OK);
+
+    wxRichTextSizePage::ShowPositionControls(true);
+    wxRichTextSizePage::ShowFloatingControls(true);
 
 
-    if (cellDlg.ShowModal() == wxID_OK)
+    if (ok)
     {
         if (multipleCells)
         {
     {
         if (multipleCells)
         {
@@ -9301,6 +9380,29 @@ bool wxRichTextCell::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
         return false;
 }
 
+// The next 2 methods return span values. Note that the default is 1, not 0
+int wxRichTextCell::GetColspan() const
+{
+    int span = 1;
+    if (GetProperties().HasProperty(wxT("colspan")))
+    {
+        span = GetProperties().GetPropertyLong(wxT("colspan"));
+    }
+
+    return span;
+}
+
+int wxRichTextCell::GetRowspan() const
+{
+    int span = 1;
+    if (GetProperties().HasProperty(wxT("rowspan")))
+    {
+        span = GetProperties().GetPropertyLong(wxT("rowspan"));
+    }
+
+    return span;
+}
+
 WX_DEFINE_OBJARRAY(wxRichTextObjectPtrArrayArray)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextTable, wxRichTextBox)
 WX_DEFINE_OBJARRAY(wxRichTextObjectPtrArrayArray)
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextTable, wxRichTextBox)
@@ -9314,11 +9416,197 @@ wxRichTextTable::wxRichTextTable(wxRichTextObject* parent): wxRichTextBox(parent
 // Draws the object.
 bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
 // Draws the object.
 bool wxRichTextTable::Draw(wxDC& dc, wxRichTextDrawingContext& context, const wxRichTextRange& range, const wxRichTextSelection& selection, const wxRect& rect, int descent, int style)
 {
-    return wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
+    wxRichTextBox::Draw(dc, context, range, selection, rect, descent, style);
+
+    int colCount = GetColumnCount();
+    int rowCount = GetRowCount();
+    int col, row;
+    for (col = 0; col < colCount; col++)
+    {
+        for (row = 0; row < rowCount; row++)
+        {
+            if (row == 0 || row == (rowCount-1) || col == 0 || col == (colCount-1))
+            {
+                wxRichTextCell* cell = GetCell(row, col);
+                if (cell && cell->IsShown() && !cell->GetRange().IsOutside(range))
+                {
+                    wxRect childRect(cell->GetPosition(), cell->GetCachedSize());
+                    wxRichTextAttr attr(cell->GetAttributes());
+                    if (row != 0)
+                        attr.GetTextBoxAttr().GetBorder().GetTop().Reset();
+                    if (row != (rowCount-1))
+                        attr.GetTextBoxAttr().GetBorder().GetBottom().Reset();
+                    if (col != 0)
+                        attr.GetTextBoxAttr().GetBorder().GetLeft().Reset();
+                    if (col != (colCount-1))
+                        attr.GetTextBoxAttr().GetBorder().GetRight().Reset();
+
+                    if (attr.GetTextBoxAttr().GetBorder().IsValid())
+                    {
+                        wxRect boxRect(cell->GetPosition(), cell->GetCachedSize());
+                        wxRect marginRect = boxRect;
+                        wxRect contentRect, borderRect, paddingRect, outlineRect;
+
+                        cell->GetBoxRects(dc, GetBuffer(), attr, marginRect, borderRect, contentRect, paddingRect, outlineRect);
+                        cell->DrawBorder(dc, GetBuffer(), attr.GetTextBoxAttr().GetBorder(), borderRect);
+                    }
+                }
+            }
+        }
+    }
+
+    return true;
 }
 
 }
 
-WX_DECLARE_OBJARRAY(wxRect, wxRichTextRectArray);
-WX_DEFINE_OBJARRAY(wxRichTextRectArray);
+    // Helper function for Layout() that clears the space needed by a cell with rowspan > 1
+int GetRowspanDisplacement(const wxRichTextTable* table, int row, int col, int paddingX, const wxArrayInt& colWidths)
+{
+    // If one or more cells above-left of this one has rowspan > 1, the affected cells below it
+    // will have been hidden and have width 0. As a result they are ignored by the layout algorithm,
+    // and all cells to their right are effectively shifted left. As a result there's no hole for
+    // the spanning cell to fill.
+    // So search back along the current row for hidden cells. However there's also the annoying issue of a 
+    // rowspanning cell that also has colspam. So we can't rely on the rowspanning cell being directly above
+    // the first hidden one we come to. We also can't rely on a cell being hidden only by one type of span;
+    // there's nothing to stop a cell being hidden by colspan, and then again hidden from above by rowspan.
+    // The answer is to look above each hidden cell in turn, which I think covers all bases.
+    int deltaX = 0;
+    for (int prevcol = 0; prevcol < col; ++prevcol)
+    {
+        if (!table->GetCell(row, prevcol)->IsShown())
+        {
+            // We've found a hidden cell. If it's hidden because of colspan to its left, it's
+            // already been taken into account; but not if there's a rowspanning cell above
+            for (int prevrow = row-1; prevrow >= 0; --prevrow)
+            {
+                wxRichTextCell* cell = table->GetCell(prevrow, prevcol);
+                if (cell && cell->IsShown())
+                {
+                    int rowSpan = cell->GetRowspan();
+                    if (rowSpan > 1 && rowSpan > (row-prevrow))
+                    {
+                        // There is a rowspanning cell above above the hidden one, so we need
+                        // to right-shift the index cell by this column's width. Furthermore, 
+                        // if the cell also colspans, we need to shift by all affected columns
+                        for (int colSpan = 0; colSpan < cell->GetColspan(); ++colSpan)
+                            deltaX += (colWidths[prevcol+colSpan] + paddingX);
+                        break;
+                    }
+                }
+            }
+        }
+    }
+    return deltaX;
+}
+
+    // Helper function for Layout() that expands any cell with rowspan > 1
+void ExpandCellsWithRowspan(const wxRichTextTable* table, int paddingY, int& bottomY, wxDC& dc, wxRichTextDrawingContext& context, const wxRect& availableSpace, int style)
+{
+    // This is called when the table's cell layout is otherwise complete.
+    // For any cell with rowspan > 1, expand downwards into the row(s) below.
+    
+    // Start by finding the current 'y' of the top of each row, plus the bottom of the available area for cells.
+    // Deduce this from the top of a visible cell in the row below. (If none are visible, the row will be invisible anyway and can be ignored.)
+    const int rowCount = table->GetRowCount();
+    const int colCount = table->GetColumnCount();
+    wxArrayInt rowTops;
+    rowTops.Add(0, rowCount+1);
+    int row;
+    for (row = 0; row < rowCount; ++row)
+    {
+        for (int column = 0; column < colCount; ++column)
+        {
+            wxRichTextCell* cell = table->GetCell(row, column);
+            if (cell && cell->IsShown())
+            {
+                rowTops[row] = cell->GetPosition().y;
+                break;
+            }
+        }
+    }
+    rowTops[rowCount] = bottomY + paddingY;  // The table bottom, which was passed to us
+    
+    bool needsRelay = false;
+
+    for (row = 0; row < rowCount-1; ++row) // -1 as the bottom row can't rowspan
+    {
+        for (int col = 0; col < colCount; ++col)
+        {
+            wxRichTextCell* cell = table->GetCell(row, col);
+            if (cell && cell->IsShown())
+            {
+                int span = cell->GetRowspan();
+                if (span > 1)
+                {
+                    span = wxMin(span, rowCount-row); // Don't try to span below the table!
+                    if (span < 2)
+                        continue;
+                    
+                    int availableHeight = rowTops[row+span] - rowTops[row] - paddingY;
+                    wxSize newSize = wxSize(cell->GetCachedSize().GetWidth(), availableHeight);
+                    wxRect availableCellSpace = wxRect(cell->GetPosition(), newSize);
+                    cell->Invalidate(wxRICHTEXT_ALL);
+                    cell->Layout(dc, context, availableCellSpace, availableSpace, style);
+                    // Ensure there's room in the span to display its contents, else it'll overwrite lower rows
+                    int overhang = cell->GetCachedSize().GetHeight() - availableHeight;
+                    cell->SetCachedSize(newSize);
+
+                    if (overhang > 0)
+                    {
+                        // There are 3 things to get right:
+                        // 1) The easiest is the rows below the span: they need to be downshifted by the overhang, and so does the table bottom itself
+                        // 2) The rows within the span, including the one holding this cell, need to be deepened by their share of the overhang
+                        //    e.g. if rowspan == 3, each row should increase in depth by 1/3rd of the overhang.
+                        // 3) The cell with the rowspan shouldn't be touched in 2); its height will be set to the whole span later.
+                        int deltaY = overhang / span;
+                        int spare  = overhang % span;
+                        
+                        // Each row in the span needs to by deepened by its share of the overhang (give the first row any spare).
+                        // This is achieved by increasing the value stored in the following row's rowTops
+                        for (int spannedRows = 0; spannedRows < span; ++spannedRows)
+                        {
+                            rowTops[row+spannedRows+1] += ((deltaY * (spannedRows+1))  + (spannedRows == 0 ? spare:0));
+                        }
+                        
+                        // Any rows below the span need shifting down
+                        for (int rowsBelow = row + span+1; rowsBelow <= rowCount; ++rowsBelow)
+                        {
+                            rowTops[rowsBelow] += overhang;
+                        }                        
+
+                        needsRelay = true;
+                    }
+                }
+            }
+        }
+    }
+   
+    if (!needsRelay)
+        return;
+
+    // There were overflowing rowspanning cells, so layout yet again to make the increased row depths show
+    for (row = 0; row < rowCount; ++row)
+    {
+        for (int col = 0; col < colCount; ++col)
+        {
+            wxRichTextCell* cell = table->GetCell(row, col);
+            if (cell && cell->IsShown())
+            {
+                wxPoint position(cell->GetPosition().x, rowTops[row]);
+
+                // GetRowspan() will usually return 1, but may be greater
+                wxSize size(cell->GetCachedSize().GetWidth(), rowTops[row + cell->GetRowspan()] - rowTops[row] - paddingY);
+
+                wxRect availableCellSpace = wxRect(position, size);
+                cell->Invalidate(wxRICHTEXT_ALL);
+                cell->Layout(dc, context, availableCellSpace, availableSpace, style);
+                cell->SetCachedSize(size);
+            }
+        }
+        
+        bottomY = rowTops[rowCount] - paddingY;
+    }
+}
 
 // Lays the object out. rect is the space available for layout. Often it will
 // be the specified overall space for this object, if trying to constrain
 
 // Lays the object out. rect is the space available for layout. Often it will
 // be the specified overall space for this object, if trying to constrain
@@ -9329,7 +9617,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 {
     SetPosition(rect.GetPosition());
 
 {
     SetPosition(rect.GetPosition());
 
-    // TODO: the meaty bit. Calculate sizes of all cells and rows. Try to use
+    // The meaty bit. Calculate sizes of all cells and rows. Try to use
     // minimum size if within alloted size, then divide up remaining size
     // between rows/cols.
 
     // minimum size if within alloted size, then divide up remaining size
     // between rows/cols.
 
@@ -9343,12 +9631,13 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     wxRichTextAttr attr(GetAttributes());
     context.ApplyVirtualAttributes(attr, this);
 
     wxRichTextAttr attr(GetAttributes());
     context.ApplyVirtualAttributes(attr, this);
 
+    bool tableHasPercentWidth = (attr.GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE);
     // If we have no fixed table size, and assuming we're not pushed for
     // space, then we don't have to try to stretch the table to fit the contents.
     // If we have no fixed table size, and assuming we're not pushed for
     // space, then we don't have to try to stretch the table to fit the contents.
-    bool stretchToFitTableWidth = false;
-
+    bool stretchToFitTableWidth = tableHasPercentWidth;
+    
     int tableWidth = rect.width;
     int tableWidth = rect.width;
-    if (attr.GetTextBoxAttr().GetWidth().IsValid())
+    if (attr.GetTextBoxAttr().GetWidth().IsValid() && !tableHasPercentWidth)
     {
         tableWidth = converter.GetPixels(attr.GetTextBoxAttr().GetWidth());
 
     {
         tableWidth = converter.GetPixels(attr.GetTextBoxAttr().GetWidth());
 
@@ -9445,12 +9734,9 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     {
         for (i = 0; i < m_colCount; i++)
         {
     {
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
-            int colSpan = 1, rowSpan = 1;
-            if (cell->GetProperties().HasProperty(wxT("colspan")))
-                colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-            if (cell->GetProperties().HasProperty(wxT("rowspan")))
-                rowSpan = cell->GetProperties().GetPropertyLong(wxT("rowspan"));
+            wxRichTextCell* cell = GetCell(j, i);
+            int colSpan = cell->GetColspan();
+            int rowSpan = cell->GetRowspan();
             if (colSpan > 1 || rowSpan > 1)
             {
                 rectArray.Add(wxRect(i, j, colSpan, rowSpan));
             if (colSpan > 1 || rowSpan > 1)
             {
                 rectArray.Add(wxRect(i, j, colSpan, rowSpan));
@@ -9462,18 +9748,16 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     {
         for (i = 0; i < m_colCount; i++)
         {
     {
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (rectArray.GetCount() == 0)
             {
                 cell->Show(true);
             }
             else
             {
             if (rectArray.GetCount() == 0)
             {
                 cell->Show(true);
             }
             else
             {
-                int colSpan = 1, rowSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-                if (cell->GetProperties().HasProperty(wxT("rowspan")))
-                    rowSpan = cell->GetProperties().GetPropertyLong(wxT("rowspan"));
+                int colSpan = cell->GetColspan();
+                int rowSpan = cell->GetRowspan();
+
                 if (colSpan > 1 || rowSpan > 1)
                 {
                     // Assume all spanning cells are shown
                 if (colSpan > 1 || rowSpan > 1)
                 {
                     // Assume all spanning cells are shown
@@ -9496,7 +9780,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         }
     }
 
         }
     }
 
-    // TODO: find the first spanned cell in each row that spans the most columns and doesn't
+    // Find the first spanned cell in each row that spans the most columns and doesn't
     // overlap with a spanned cell starting at a previous column position.
     // This means we need to keep an array of rects so we can check. However
     // it does also mean that some spans simply may not be taken into account
     // overlap with a spanned cell starting at a previous column position.
     // This means we need to keep an array of rects so we can check. However
     // it does also mean that some spans simply may not be taken into account
@@ -9536,12 +9820,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
         for (i = 0; i < m_colCount; i++)
         {
 
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (cell->IsShown())
             {
             if (cell->IsShown())
             {
-                int colSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
+                int colSpan = cell->GetColspan();
 
                 // Lay out cell to find min/max widths
                 cell->Invalidate(wxRICHTEXT_ALL);
 
                 // Lay out cell to find min/max widths
                 cell->Invalidate(wxRICHTEXT_ALL);
@@ -9661,13 +9943,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
         for (i = 0; i < m_colCount; i++)
         {
 
         for (i = 0; i < m_colCount; i++)
         {
-            wxRichTextBox* cell = GetCell(j, i);
+            wxRichTextCell* cell = GetCell(j, i);
             if (cell->IsShown())
             {
             if (cell->IsShown())
             {
-                int colSpan = 1;
-                if (cell->GetProperties().HasProperty(wxT("colspan")))
-                    colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-
+                int colSpan = cell->GetColspan();
                 if (colSpan > 1)
                 {
                     int spans = wxMin(colSpan, m_colCount - i);
                 if (colSpan > 1)
                 {
                     int spans = wxMin(colSpan, m_colCount - i);
@@ -9750,7 +10029,6 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
     int stretchColCount = 0;
     for (i = 0; i < m_colCount; i++)
     {
     int stretchColCount = 0;
     for (i = 0; i < m_colCount; i++)
     {
-        // TODO: we need to take into account min widths.
         // Subtract min width from width left, then
         // add the colShare to the min width
         if (colWidths[i] > 0) // absolute or proportional width has been specified
         // Subtract min width from width left, then
         // add the colShare to the min width
         if (colWidths[i] > 0) // absolute or proportional width has been specified
@@ -9856,19 +10134,16 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
 
                 if (colWidths[i] > 0) // absolute or proportional width has been specified
                 {
 
                 if (colWidths[i] > 0) // absolute or proportional width has been specified
                 {
-                    int colSpan = 1;
-                    if (cell->GetProperties().HasProperty(wxT("colspan")))
-                        colSpan = cell->GetProperties().GetPropertyLong(wxT("colspan"));
-
+                    int colSpan = cell->GetColspan();
                     wxRect availableCellSpace;
 
                     wxRect availableCellSpace;
 
-                    // TODO: take into acount spans
+                    // Take into account spans
                     if (colSpan > 1)
                     {
                         // Calculate the size of this spanning cell from its constituent columns
                     if (colSpan > 1)
                     {
                         // Calculate the size of this spanning cell from its constituent columns
-                        int xx = x;
+                        int xx = 0;
                         int spans = wxMin(colSpan, m_colCount - i);
                         int spans = wxMin(colSpan, m_colCount - i);
-                        for (k = i; k < spans; k++)
+                        for (k = i; k < (i+spans); k++)
                         {
                             if (k != i)
                                 xx += paddingX;
                         {
                             if (k != i)
                                 xx += paddingX;
@@ -9882,6 +10157,10 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                     // Store actual width so we can force cell to be the appropriate width on the final loop
                     actualWidths[i] = availableCellSpace.GetWidth();
 
                     // Store actual width so we can force cell to be the appropriate width on the final loop
                     actualWidths[i] = availableCellSpace.GetWidth();
 
+                    // We now need to shift right by the width of any rowspanning cells above-left of us
+                    int deltaX = GetRowspanDisplacement(this, j, i, paddingX, colWidths);
+                    availableCellSpace.SetX(availableCellSpace.GetX() + deltaX);
+
                     // Lay out cell
                     cell->Invalidate(wxRICHTEXT_ALL);
                     cell->Layout(dc, context, availableCellSpace, availableSpace, style);
                     // Lay out cell
                     cell->Invalidate(wxRICHTEXT_ALL);
                     cell->Layout(dc, context, availableCellSpace, availableSpace, style);
@@ -9889,7 +10168,7 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
                     // TODO: use GetCachedSize().x to compute 'natural' size
 
                     x += (availableCellSpace.GetWidth() + paddingX);
                     // TODO: use GetCachedSize().x to compute 'natural' size
 
                     x += (availableCellSpace.GetWidth() + paddingX);
-                    if (cell->GetCachedSize().y > maxCellHeight)
+                    if ((cell->GetCachedSize().y > maxCellHeight) && (cell->GetRowspan() < 2))
                         maxCellHeight = cell->GetCachedSize().y;
                 }
             }
                         maxCellHeight = cell->GetCachedSize().y;
                 }
             }
@@ -9919,6 +10198,9 @@ bool wxRichTextTable::Layout(wxDC& dc, wxRichTextDrawingContext& context, const
         if (j < (m_rowCount-1))
             y += paddingY;
     }
         if (j < (m_rowCount-1))
             y += paddingY;
     }
+    
+    // Finally we need to expand any cell with rowspan > 1. We couldn't earlier; lower rows' heights weren't known
+    ExpandCellsWithRowspan(this, paddingY, y, dc, context, availableSpace, style);
 
     // We need to add back the margins etc.
     {
 
     // We need to add back the margins etc.
     {
@@ -10095,6 +10377,9 @@ bool wxRichTextTable::CreateTable(int rows, int cols)
 {
     ClearTable();
 
 {
     ClearTable();
 
+    wxRichTextAttr cellattr;
+    cellattr.SetTextColour(GetBasicStyle().GetTextColour());
+
     m_rowCount = rows;
     m_colCount = cols;
 
     m_rowCount = rows;
     m_colCount = cols;
 
@@ -10107,6 +10392,8 @@ bool wxRichTextTable::CreateTable(int rows, int cols)
         for (j = 0; j < cols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < cols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
+            cell->GetAttributes() = cellattr;
+
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
@@ -10262,6 +10549,23 @@ wxPosition wxRichTextTable::GetFocusedCell() const
     return position;
 }
 
     return position;
 }
 
+int wxRichTextTable::HitTest(wxDC& dc, wxRichTextDrawingContext& context, const wxPoint& pt, long& textPosition, wxRichTextObject** obj, wxRichTextObject** contextObj, int flags)
+{
+    for (int row = 0; row < GetRowCount(); ++row)
+    {
+        for (int col = 0; col < GetColumnCount(); ++col)
+        {
+            wxRichTextCell* cell = GetCell(row, col);
+            if (cell->wxRichTextObject::HitTest(dc, context, pt, textPosition, obj, contextObj, flags) != wxRICHTEXT_HITTEST_NONE)
+            {
+                return cell->HitTest(dc, context, pt, textPosition, obj, contextObj, flags);
+            }
+        }
+    }
+
+    return wxRICHTEXT_HITTEST_NONE;
+}
+
 bool wxRichTextTable::DeleteRows(int startRow, int noRows)
 {
     wxASSERT((startRow + noRows) <= m_rowCount);
 bool wxRichTextTable::DeleteRows(int startRow, int noRows)
 {
     wxASSERT((startRow + noRows) <= m_rowCount);
@@ -10273,24 +10577,6 @@ bool wxRichTextTable::DeleteRows(int startRow, int noRows)
     wxRichTextBuffer* buffer = GetBuffer();
     wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
 
     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())
     wxRichTextAction* action = NULL;
     wxRichTextTable* clone = NULL;
     if (!rtc->SuppressingUndo())
@@ -10298,7 +10584,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());
         // 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());
     }
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10341,24 +10627,6 @@ bool wxRichTextTable::DeleteColumns(int startCol, int noCols)
     wxRichTextBuffer* buffer = GetBuffer();
     wxRichTextCtrl* rtc = buffer->GetRichTextCtrl();
 
     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())
     wxRichTextAction* action = NULL;
     wxRichTextTable* clone = NULL;
     if (!rtc->SuppressingUndo())
@@ -10366,7 +10634,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());
         // 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());
     }
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
@@ -10411,16 +10679,21 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at
     wxRichTextBuffer* buffer = GetBuffer();
     wxRichTextAction* action = NULL;
     wxRichTextTable* clone = NULL;
     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());
     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());
     }
 
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
 
+    wxRichTextAttr cellattr = attr;
+    if (!cellattr.GetTextColour().IsOk())
+        cellattr.SetTextColour(buffer->GetBasicStyle().GetTextColour());
+
     int i, j;
     for (i = 0; i < noRows; i++)
     {
     int i, j;
     for (i = 0; i < noRows; i++)
     {
@@ -10440,7 +10713,7 @@ bool wxRichTextTable::AddRows(int startRow, int noRows, const wxRichTextAttr& at
         for (j = 0; j < m_colCount; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < m_colCount; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
-            cell->GetAttributes() = attr;
+            cell->GetAttributes() = cellattr;
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
@@ -10469,16 +10742,21 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
     wxRichTextBuffer* buffer = GetBuffer();
     wxRichTextAction* action = NULL;
     wxRichTextTable* clone = NULL;
     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());
     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());
     }
 
         action->SetObject(this);
         action->SetPosition(GetRange().GetStart());
     }
 
+    wxRichTextAttr cellattr = attr;
+    if (!cellattr.GetTextColour().IsOk())
+        cellattr.SetTextColour(buffer->GetBasicStyle().GetTextColour());
+
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
     int i, j;
     for (i = 0; i < m_rowCount; i++)
     {
@@ -10486,7 +10764,7 @@ bool wxRichTextTable::AddColumns(int startCol, int noCols, const wxRichTextAttr&
         for (j = 0; j < noCols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
         for (j = 0; j < noCols; j++)
         {
             wxRichTextCell* cell = new wxRichTextCell;
-            cell->GetAttributes() = attr;
+            cell->GetAttributes() = cellattr;
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
 
             AppendChild(cell);
             cell->AddParagraph(wxEmptyString);
@@ -10525,6 +10803,90 @@ bool wxRichTextTable::EditProperties(wxWindow* parent, wxRichTextBuffer* buffer)
         return false;
 }
 
         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
  */
 /*
  * Module to initialise and clean up handlers
  */
@@ -10907,6 +11269,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
             // 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
@@ -10915,7 +11283,7 @@ bool wxRichTextAction::Do()
             else
                 container->InvalidateHierarchy(GetRange());
 
             else
                 container->InvalidateHierarchy(GetRange());
 
-            UpdateAppearance(GetPosition());
+            UpdateAppearance(GetPosition(), true);
 
             // TODO: send new kind of modification event
 
 
             // TODO: send new kind of modification event
 
@@ -13644,9 +14012,8 @@ void wxTextAttrCollectCommonAttributes(wxTextAttr& currentStyle, const wxTextAtt
 }
 
 WX_DEFINE_OBJARRAY(wxRichTextVariantArray);
 }
 
 WX_DEFINE_OBJARRAY(wxRichTextVariantArray);
-
-// JACS 2013-01-27
 WX_DEFINE_OBJARRAY(wxRichTextAttrArray);
 WX_DEFINE_OBJARRAY(wxRichTextAttrArray);
+WX_DEFINE_OBJARRAY(wxRichTextRectArray);
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)
 
 
 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties, wxObject)