]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
[ 1563875 ] wxTreeCtrl::FindItem asserts when item not found
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index 9fcb9b2729cc03e657ed77959a55c16584643a7c..bc16bc9efdb6758dbdb7c4b30866c46f15aa7a78 100644 (file)
@@ -1,5 +1,5 @@
 /////////////////////////////////////////////////////////////////////////////
-// Name:        richtext/richtextbuffer.cpp
+// Name:        src/richtext/richtextbuffer.cpp
 // Purpose:     Buffer for wxRichTextCtrl
 // Author:      Julian Smart
 // Modified by:
 #include "wx/wxprec.h"
 
 #ifdef __BORLANDC__
-  #pragma hdrstop
+    #pragma hdrstop
 #endif
 
-#ifndef WX_PRECOMP
-  #include "wx/wx.h"
-#endif
+#if wxUSE_RICHTEXT
 
-#include "wx/image.h"
+#include "wx/richtext/richtextbuffer.h"
 
-#if wxUSE_RICHTEXT
+#ifndef WX_PRECOMP
+    #include "wx/dc.h"
+    #include "wx/intl.h"
+    #include "wx/log.h"
+    #include "wx/dataobj.h"
+    #include "wx/module.h"
+#endif
 
 #include "wx/filename.h"
 #include "wx/clipbrd.h"
 #include "wx/wfstream.h"
-#include "wx/module.h"
 #include "wx/mstream.h"
 #include "wx/sstream.h"
 
-#include "wx/richtext/richtextbuffer.h"
 #include "wx/richtext/richtextctrl.h"
 #include "wx/richtext/richtextstyles.h"
 
 #include "wx/listimpl.cpp"
 
-WX_DEFINE_LIST(wxRichTextObjectList);
-WX_DEFINE_LIST(wxRichTextLineList);
+WX_DEFINE_LIST(wxRichTextObjectList)
+WX_DEFINE_LIST(wxRichTextLineList)
 
 /*!
  * wxRichTextObject
@@ -174,9 +176,10 @@ bool wxRichTextCompositeObject::RemoveChild(wxRichTextObject* child, bool delete
     wxRichTextObjectList::compatibility_iterator node = m_children.Find(child);
     if (node)
     {
+        wxRichTextObject* obj = node->GetData();
+        m_children.Erase(node);
         if (deleteChild)
-            delete node->GetData();
-        delete node;
+            delete obj;
 
         return true;
     }
@@ -195,7 +198,7 @@ bool wxRichTextCompositeObject::DeleteChildren()
         child->Dereference(); // Only delete if reference count is zero
 
         node = node->GetNext();
-        delete oldNode;
+        m_children.Erase(oldNode);
     }
 
     return true;
@@ -368,7 +371,7 @@ bool wxRichTextCompositeObject::Defragment()
             if (child->CanMerge(nextChild) && child->Merge(nextChild))
             {
                 nextChild->Dereference();
-                delete node->GetNext();
+                m_children.Erase(node->GetNext());
 
                 // Don't set node -- we'll see if we can merge again with the next
                 // child.
@@ -440,13 +443,13 @@ bool wxRichTextBox::Layout(wxDC& dc, const wxRect& rect, int style)
 }
 
 /// Get/set the size for the given range. Assume only has one child.
-bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const
+bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
 {
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     if (node)
     {
         wxRichTextObject* child = node->GetData();
-        return child->GetRangeSize(range, size, descent, dc, flags);
+        return child->GetRangeSize(range, size, descent, dc, flags, position);
     }
     else
         return false;
@@ -548,7 +551,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
     int maxWidth = 0;
 
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
-    
+
     bool layoutAll = true;
 
     // Get invalid range, rounding to paragraph start/end.
@@ -566,7 +569,9 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
         if (firstParagraph)
         {
             wxRichTextObjectList::compatibility_iterator firstNode = m_children.Find(firstParagraph);
-            wxRichTextObjectList::compatibility_iterator previousNode = firstNode ? firstNode->GetPrevious() : (wxRichTextObjectList::compatibility_iterator) NULL;
+            wxRichTextObjectList::compatibility_iterator previousNode;
+            if ( firstNode )
+                previousNode = firstNode->GetPrevious();
             if (firstNode && previousNode)
             {
                 wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
@@ -582,16 +587,19 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
 
     // A way to force speedy rest-of-buffer layout (the 'else' below)
     bool forceQuickLayout = false;
-        
+
     while (node)
     {
         // Assume this box only contains paragraphs
 
         wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
-        wxASSERT (child != NULL);
+        wxCHECK_MSG( child, false, _T("Unknown object in layout") );
 
         // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines
-        if (child && !forceQuickLayout && (layoutAll || child->GetLines().GetCount() == 0 || !child->GetRange().IsOutside(invalidRange)))
+        if ( !forceQuickLayout &&
+                (layoutAll ||
+                    child->GetLines().IsEmpty() ||
+                        !child->GetRange().IsOutside(invalidRange)) )
         {
             child->Layout(dc, availableSpace, style);
 
@@ -651,12 +659,12 @@ void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox& obj)
 }
 
 /// Get/set the size for the given range.
-bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const
+bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
 {
     wxSize sz;
 
-    wxRichTextObjectList::compatibility_iterator startPara = NULL;
-    wxRichTextObjectList::compatibility_iterator endPara = NULL;
+    wxRichTextObjectList::compatibility_iterator startPara = wxRichTextObjectList::compatibility_iterator();
+    wxRichTextObjectList::compatibility_iterator endPara = wxRichTextObjectList::compatibility_iterator();
 
     // First find the first paragraph whose starting position is within the range.
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
@@ -707,7 +715,7 @@ bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wx
         wxSize childSize;
 
         int childDescent = 0;
-        child->GetRangeSize(rangeToFind, childSize, childDescent, dc, flags);
+        child->GetRangeSize(rangeToFind, childSize, childDescent, dc, flags, position);
 
         descent = wxMax(childDescent, descent);
 
@@ -900,7 +908,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text
 
     wxRichTextRange range(-1, -1);
     size_t i = 0;
-    size_t len = text.Length();
+    size_t len = text.length();
     wxString line;
     while (i < len)
     {
@@ -1129,8 +1137,6 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm
 
         return true;
     }
-
-    return false;
 }
 
 /// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'.
@@ -1350,7 +1356,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
                             }
 
                             wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
-                            delete node1;
+                            nextParagraph->GetChildren().Erase(node1);
 
                             node1 = next1;
                         }
@@ -1407,7 +1413,7 @@ wxString wxRichTextParagraphLayoutBox::GetText() const
 /// Get the paragraph by number
 wxRichTextParagraph* wxRichTextParagraphLayoutBox::GetParagraphAtLine(long paragraphNumber) const
 {
-    if ((size_t) paragraphNumber <= GetChildCount())
+    if ((size_t) paragraphNumber >= GetChildCount())
         return NULL;
 
     return (wxRichTextParagraph*) GetChild((size_t) paragraphNumber);
@@ -1535,7 +1541,7 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
             {
                 // We'll be using a copy of the paragraph to make style changes,
                 // not updating the buffer directly.
-                wxRichTextParagraph* newPara = NULL;
+                wxRichTextParagraph* newPara wxDUMMY_INITIALIZE(NULL);
 
                 if (haveControl && withUndo)
                 {
@@ -1560,8 +1566,8 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                     // we can start applying a different style.
                     // TODO: check that the style actually changes or is different
                     // from style outside of range
-                    wxRichTextObject* firstObject = NULL;
-                    wxRichTextObject* lastObject = NULL;
+                    wxRichTextObject* firstObject wxDUMMY_INITIALIZE(NULL);
+                    wxRichTextObject* lastObject wxDUMMY_INITIALIZE(NULL);
 
                     if (childRange.GetStart() == newPara->GetRange().GetStart())
                         firstObject = newPara->GetChildren().GetFirst()->GetData();
@@ -1590,8 +1596,8 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
                     wxRichTextObjectList::compatibility_iterator firstNode = newPara->GetChildren().Find(firstObject);
                     wxRichTextObjectList::compatibility_iterator lastNode = newPara->GetChildren().Find(lastObject);
 
-                    wxASSERT(firstNode != NULL);
-                    wxASSERT(lastNode != NULL);
+                    wxASSERT(firstNode);
+                    wxASSERT(lastNode);
 
                     wxRichTextObjectList::compatibility_iterator node2 = firstNode;
 
@@ -1627,9 +1633,9 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const
 }
 
 /// Get the text attributes for this position.
-bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style) const
+bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style)
 {
-    wxRichTextObject* obj = NULL;
+    wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
 
     if (style.IsParagraphStyle())
         obj = GetParagraphAtPosition(position);
@@ -1646,9 +1652,9 @@ bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style)
 }
 
 /// Get the text attributes for this position.
-bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style) const
+bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style)
 {
-    wxRichTextObject* obj = NULL;
+    wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
 
     if (style.IsParagraphStyle())
         obj = GetParagraphAtPosition(position);
@@ -1667,7 +1673,13 @@ bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style
 /// Set default style
 bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxTextAttrEx& style)
 {
-    m_defaultAttributes = style;
+    // keep the old attributes if the new style doesn't specify them unless the
+    // new style is empty - then reset m_defaultStyle (as there is no other way
+    // to do it)
+    if ( style.IsDefault() )
+        m_defaultAttributes = style;
+    else
+        m_defaultAttributes = wxTextAttrEx::CombineEx(style, m_defaultAttributes, NULL);
 
     return true;
 }
@@ -1780,7 +1792,7 @@ void wxRichTextParagraphLayoutBox::Reset()
 void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange& invalidRange)
 {
     SetDirty(true);
-    
+
     if (invalidRange == wxRICHTEXT_ALL)
     {
         m_invalidRange = wxRICHTEXT_ALL;
@@ -1790,7 +1802,7 @@ void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange& invalidRang
     // Already invalidating everything
     if (m_invalidRange == wxRICHTEXT_ALL)
         return;
-    
+
     if ((invalidRange.GetStart() < m_invalidRange.GetStart()) || m_invalidRange.GetStart() == -1)
         m_invalidRange.SetStart(invalidRange.GetStart());
     if (invalidRange.GetEnd() > m_invalidRange.GetEnd())
@@ -1802,9 +1814,9 @@ wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagrap
 {
     if (m_invalidRange == wxRICHTEXT_ALL || m_invalidRange == wxRICHTEXT_NONE)
         return m_invalidRange;
-    
+
     wxRichTextRange range = m_invalidRange;
-    
+
     if (wholeParagraphs)
     {
         wxRichTextParagraph* para1 = GetParagraphAtPosition(range.GetStart());
@@ -1906,7 +1918,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range),
                     wxRichTextLine* line = m_cachedLines.GetFirst() ? (wxRichTextLine* ) m_cachedLines.GetFirst()->GetData() : (wxRichTextLine*) NULL;
 
                     wxPoint linePos;
-                    int lineHeight = 0;
+                    int lineHeight wxDUMMY_INITIALIZE(0);
                     if (line)
                     {
                         lineHeight = line->GetSize().y;
@@ -1958,7 +1970,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range),
 
                 wxSize objectSize;
                 int descent = 0;
-                child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED);
+                child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition);
 
                 // Use the child object's width, but the whole line's height
                 wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y));
@@ -2071,7 +2083,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
             childDescent = child->GetDescent();
         }
         else
-            GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED);
+            GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED,rect.GetPosition());
 
         if (childSize.x + currentWidth > availableSpaceForText)
         {
@@ -2101,7 +2113,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
 
             // Add a new line
             wxRichTextLine* line = AllocateLine(lineCount);
-            
+
             // Set relative range so we won't have to change line ranges when paragraphs are moved
             line->SetRange(wxRichTextRange(actualRange.GetStart() - GetRange().GetStart(), actualRange.GetEnd() - GetRange().GetStart()));
             line->SetPosition(currentPosition);
@@ -2227,7 +2239,7 @@ void wxRichTextParagraph::ApplyParagraphStyle(const wxRect& rect)
 bool wxRichTextParagraph::InsertText(long pos, const wxString& text)
 {
     wxRichTextObject* childToUse = NULL;
-    wxRichTextObjectList::compatibility_iterator nodeToUse = NULL;
+    wxRichTextObjectList::compatibility_iterator nodeToUse = wxRichTextObjectList::compatibility_iterator();
 
     wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
     while (node)
@@ -2254,7 +2266,7 @@ bool wxRichTextParagraph::InsertText(long pos, const wxString& text)
                                text + textObject->GetText().Mid(posInString);
             textObject->SetText(newText);
 
-            int textLength = text.Length();
+            int textLength = text.length();
 
             textObject->SetRange(wxRichTextRange(textObject->GetRange().GetStart(),
                                                  textObject->GetRange().GetEnd() + textLength));
@@ -2306,7 +2318,7 @@ void wxRichTextParagraph::ClearLines()
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const
+bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -2330,7 +2342,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
                 rangeToUse.LimitTo(child->GetRange());
                 int childDescent = 0;
 
-                if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags))
+                if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, position))
                 {
                     sz.y = wxMax(sz.y, childSize.y);
                     sz.x += childSize.x;
@@ -2375,7 +2387,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 
                         wxSize childSize;
                         int childDescent = 0;
-                        if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags))
+                        if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, position))
                         {
                             lineSize.y = wxMax(lineSize.y, childSize.y);
                             lineSize.x += childSize.x;
@@ -2476,7 +2488,7 @@ bool wxRichTextParagraph::FindPosition(wxDC& dc, long index, wxPoint& pt, int* h
             // then we can add this size to the line start position and
             // paragraph start position to find the actual position.
 
-            if (GetRangeSize(r, rangeSize, descent, dc, wxRICHTEXT_UNFORMATTED))
+            if (GetRangeSize(r, rangeSize, descent, dc, wxRICHTEXT_UNFORMATTED, line->GetPosition()+ GetPosition()))
             {
                 pt.x = line->GetPosition().x + GetPosition().x + rangeSize.x;
                 *height = line->GetSize().y;
@@ -2529,7 +2541,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition
 
                     wxRichTextRange rangeToUse(lineRange.GetStart(), i);
 
-                    GetRangeSize(rangeToUse, childSize, descent, dc, wxRICHTEXT_UNFORMATTED);
+                    GetRangeSize(rangeToUse, childSize, descent, dc, wxRICHTEXT_UNFORMATTED, linePos);
 
                     int nextX = childSize.x + linePos.x;
 
@@ -2638,7 +2650,7 @@ void wxRichTextParagraph::MoveToList(wxRichTextObject* obj, wxList& list)
 /// Add content back from list
 void wxRichTextParagraph::MoveFromList(wxList& list)
 {
-    for (wxNode* node = list.GetFirst(); node; node = node->GetNext())
+    for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
     {
         AppendChild((wxRichTextObject*) node->GetData());
     }
@@ -2748,7 +2760,7 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d
         int spacePos = plainText.Find(wxT(' '), true);
         if (spacePos != wxNOT_FOUND)
         {
-            int positionsFromEndOfString = plainText.Length() - spacePos - 1;
+            int positionsFromEndOfString = plainText.length() - spacePos - 1;
             breakPosition = breakPosition - positionsFromEndOfString;
         }
     }
@@ -2944,24 +2956,13 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
     // (a) All selected.
     if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
     {
-        // Draw all selected
-        dc.SetBrush(*wxBLACK_BRUSH);
-        dc.SetPen(*wxBLACK_PEN);
-        wxCoord w, h;
-        dc.GetTextExtent(stringChunk, & w, & h);
-        wxRect selRect(x, rect.y, w, rect.GetHeight());
-        dc.DrawRectangle(selRect);
-        dc.SetTextForeground(*wxWHITE);
-        dc.SetBackgroundMode(wxTRANSPARENT);
-        dc.DrawText(stringChunk, x, y);
+        DrawTabbedString(dc, rect,stringChunk, x, y, true);
     }
     // (b) None selected.
     else if (selectionRange.GetEnd() < range.GetStart() || selectionRange.GetStart() > range.GetEnd())
     {
         // Draw all unselected
-        dc.SetTextForeground(GetAttributes().GetTextColour());
-        dc.SetBackgroundMode(wxTRANSPARENT);
-        dc.DrawText(stringChunk, x, y);
+        DrawTabbedString(dc, rect,stringChunk, x, y, false);
     }
     else
     {
@@ -2980,12 +2981,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
                 wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen);
             wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen);
 
-            dc.SetTextForeground(GetAttributes().GetTextColour());
-            dc.DrawText(stringFragment, x, y);
-
-            wxCoord w, h;
-            dc.GetTextExtent(stringFragment, & w, & h);
-            x += w;
+            DrawTabbedString(dc, rect,stringFragment, x, y, false);
         }
 
         // 2. Selected chunk, if any.
@@ -2999,17 +2995,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen);
             wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen);
 
-            wxCoord w, h;
-            dc.GetTextExtent(stringFragment, & w, & h);
-            wxRect selRect(x, rect.y, w, rect.GetHeight());
-
-            dc.SetBrush(*wxBLACK_BRUSH);
-            dc.SetPen(*wxBLACK_PEN);
-            dc.DrawRectangle(selRect);
-            dc.SetTextForeground(*wxWHITE);
-            dc.DrawText(stringFragment, x, y);
-
-            x += w;
+            DrawTabbedString(dc, rect,stringFragment, x, y, true);
         }
 
         // 3. Remaining unselected chunk, if any
@@ -3023,14 +3009,88 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen);
             wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen);
 
-            dc.SetTextForeground(GetAttributes().GetTextColour());
-            dc.DrawText(stringFragment, x, y);
+            DrawTabbedString(dc, rect,stringFragment, x, y, false);
         }
     }
 
     return true;
 }
 
+bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected)
+{
+    wxArrayInt tab_array =  GetAttributes().GetTabs();
+    if (tab_array.IsEmpty())
+    {
+        // create a default tab list at 10 mm each.
+        for (int i = 0; i < 20; ++i)
+        {
+            tab_array.Add(i*100);
+        }
+    }
+    int map_mode = dc.GetMapMode();
+    dc.SetMapMode(wxMM_LOMETRIC );
+    int num_tabs = tab_array.GetCount();
+    for (int i = 0; i < num_tabs; ++i)
+    {
+       tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]);
+    }
+
+    dc.SetMapMode(map_mode );
+    int next_tab_pos = -1;
+    int tab_pos = -1;
+    wxCoord w, h;
+
+    if(selected)
+    {
+        dc.SetBrush(*wxBLACK_BRUSH);
+        dc.SetPen(*wxBLACK_PEN);
+        dc.SetTextForeground(*wxWHITE);
+        dc.SetBackgroundMode(wxTRANSPARENT);
+    }
+    else
+    {
+        dc.SetTextForeground(GetAttributes().GetTextColour());
+        dc.SetBackgroundMode(wxTRANSPARENT);
+    }
+
+    while (str.Find(wxT('\t')) >= 0)
+    {
+        // the string has a tab
+        // break up the string at the Tab
+        wxString stringChunk = str.BeforeFirst(wxT('\t'));
+        str = str.AfterFirst(wxT('\t'));
+        dc.GetTextExtent(stringChunk, & w, & h);
+        tab_pos = x + w;
+        bool not_found = true;
+        for (int i = 0; i < num_tabs && not_found; ++i)
+        {
+            next_tab_pos = tab_array.Item(i);
+            if (next_tab_pos > tab_pos)
+            {
+                not_found = false;
+                if (selected)
+                {
+                    w = next_tab_pos - x;
+                    wxRect selRect(x, rect.y, w, rect.GetHeight());
+                    dc.DrawRectangle(selRect);
+                }
+                dc.DrawText(stringChunk, x, y);
+                x = next_tab_pos;
+            }
+        }
+    }
+
+    dc.GetTextExtent(str, & w, & h);
+    if (selected)
+    {
+        wxRect selRect(x, rect.y, w, rect.GetHeight());
+        dc.DrawRectangle(selRect);
+    }
+    dc.DrawText(str, x, y);
+    x += w;
+    return true;
+
+}
 /// Lay the item out
 bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style))
 {
@@ -3054,7 +3114,7 @@ void wxRichTextPlainText::Copy(const wxRichTextPlainText& obj)
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags)) const
+bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -3070,8 +3130,55 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
     long len = range.GetLength();
     wxString stringChunk = m_text.Mid(startPos, (size_t) len);
     wxCoord w, h;
+    int width = 0;
+    if (stringChunk.Find(wxT('\t')) >= 0)
+    {
+        // the string has a tab
+        wxArrayInt tab_array =  GetAttributes().GetTabs();
+        if (tab_array.IsEmpty())
+        {
+            // create a default tab list at 10 mm each.
+            for (int i = 0; i < 20; ++i)
+            {
+                tab_array.Add(i*100);
+            }
+        }
+
+        int map_mode = dc.GetMapMode();
+        dc.SetMapMode(wxMM_LOMETRIC );
+        int num_tabs = tab_array.GetCount();
+
+        for (int i = 0; i < num_tabs; ++i)
+        {
+            tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]);
+        }
+        dc.SetMapMode(map_mode );
+        int next_tab_pos = -1;
+
+        while (stringChunk.Find(wxT('\t')) >= 0)
+        {
+            // the string has a tab
+            // break up the string at the Tab
+            wxString stringFragment = stringChunk.BeforeFirst(wxT('\t'));
+            stringChunk = stringChunk.AfterFirst(wxT('\t'));
+            dc.GetTextExtent(stringFragment, & w, & h);
+            width += w;
+            int absolute_width = width + position.x;
+            bool not_found = true;
+            for (int i = 0; i < num_tabs && not_found; ++i)
+            {
+                next_tab_pos = tab_array.Item(i);
+                if (next_tab_pos > absolute_width)
+                {
+                    not_found = false;
+                    width = next_tab_pos - position.x;
+                }
+            }
+        }
+    }
     dc.GetTextExtent(stringChunk, & w, & h, & descent);
-    size = wxSize(w, dc.GetCharHeight());
+    width += w;
+    size = wxSize(width, dc.GetCharHeight());
 
     return true;
 }
@@ -3081,7 +3188,7 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz
 wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
 {
     int index = pos - GetRange().GetStart();
-    if (index < 0 || index >= (int) m_text.Length())
+    if (index < 0 || index >= (int) m_text.length())
         return NULL;
 
     wxString firstPart = m_text.Mid(0, index);
@@ -3101,7 +3208,7 @@ wxRichTextObject* wxRichTextPlainText::DoSplit(long pos)
 /// Calculate range
 void wxRichTextPlainText::CalculateRange(long start, long& end)
 {
-    end = start + m_text.Length() - 1;
+    end = start + m_text.length() - 1;
     m_range.SetRange(start, end);
 }
 
@@ -3226,7 +3333,7 @@ bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRich
     action->SetPosition(pos);
 
     // Set the range we'll need to delete in Undo
-    action->SetRange(wxRichTextRange(pos, pos + text.Length() - 1));
+    action->SetRange(wxRichTextRange(pos, pos + text.length() - 1));
 
     SubmitAction(action);
 
@@ -3408,15 +3515,15 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttrEx& style)
 /// End the style
 bool wxRichTextBuffer::EndStyle()
 {
-    if (m_attributeStack.GetFirst() == NULL)
+    if (!m_attributeStack.GetFirst())
     {
         wxLogDebug(_("Too many EndStyle calls!"));
         return false;
     }
 
-    wxNode* node = m_attributeStack.GetLast();
+    wxList::compatibility_iterator node = m_attributeStack.GetLast();
     wxTextAttrEx* attr = (wxTextAttrEx*)node->GetData();
-    delete node;
+    m_attributeStack.Erase(node);
 
     SetDefaultStyle(*attr);
 
@@ -3435,7 +3542,7 @@ bool wxRichTextBuffer::EndAllStyles()
 /// Clear the style stack
 void wxRichTextBuffer::ClearStyleStack()
 {
-    for (wxNode* node = m_attributeStack.GetFirst(); node; node = node->GetNext())
+    for (wxList::compatibility_iterator node = m_attributeStack.GetFirst(); node; node = node->GetNext())
         delete (wxTextAttrEx*) node->GetData();
     m_attributeStack.Clear();
 }
@@ -3823,12 +3930,16 @@ bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, int type)
 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
 {
     bool success = false;
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
     wxString text = GetTextForRange(range);
-    if (wxTheClipboard->Open())
+    if (!wxTheClipboard->IsOpened() && wxTheClipboard->Open())
     {
         success = wxTheClipboard->SetData(new wxTextDataObject(text));
         wxTheClipboard->Close();
     }
+#else
+    wxUnusedVar(range);
+#endif
     return success;
 }
 
@@ -3836,6 +3947,7 @@ bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
 bool wxRichTextBuffer::PasteFromClipboard(long position)
 {
     bool success = false;
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
     if (CanPasteFromClipboard())
     {
         if (wxTheClipboard->Open())
@@ -3845,6 +3957,7 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
                 wxTextDataObject data;
                 wxTheClipboard->GetData(data);
                 wxString text(data.GetText());
+                text.Replace(_T("\r\n"), _T("\n"));
 
                 InsertTextWithUndo(position+1, text, GetRichTextCtrl());
 
@@ -3876,6 +3989,9 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
             wxTheClipboard->Close();
         }
     }
+#else
+    wxUnusedVar(position);
+#endif
     return success;
 }
 
@@ -3883,7 +3999,8 @@ bool wxRichTextBuffer::PasteFromClipboard(long position)
 bool wxRichTextBuffer::CanPasteFromClipboard() const
 {
     bool canPaste = false;
-    if (wxTheClipboard->Open())
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
+    if (!wxTheClipboard->IsOpened() && wxTheClipboard->Open())
     {
         if (wxTheClipboard->IsSupported(wxDF_TEXT) || wxTheClipboard->IsSupported(wxDF_BITMAP))
         {
@@ -3891,6 +4008,7 @@ bool wxRichTextBuffer::CanPasteFromClipboard() const
         }
         wxTheClipboard->Close();
     }
+#endif
     return canPaste;
 }
 
@@ -3952,7 +4070,7 @@ void wxRichTextCommand::AddAction(wxRichTextAction* action)
 
 bool wxRichTextCommand::Do()
 {
-    for (wxNode* node = m_actions.GetFirst(); node; node = node->GetNext())
+    for (wxList::compatibility_iterator node = m_actions.GetFirst(); node; node = node->GetNext())
     {
         wxRichTextAction* action = (wxRichTextAction*) node->GetData();
         action->Do();
@@ -3963,7 +4081,7 @@ bool wxRichTextCommand::Do()
 
 bool wxRichTextCommand::Undo()
 {
-    for (wxNode* node = m_actions.GetLast(); node; node = node->GetPrevious())
+    for (wxList::compatibility_iterator node = m_actions.GetLast(); node; node = node->GetPrevious())
     {
         wxRichTextAction* action = (wxRichTextAction*) node->GetData();
         action->Undo();
@@ -4101,9 +4219,9 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent
         m_ctrl->SetCaretPosition(caretPosition);
         if (!m_ctrl->IsFrozen())
         {
-            m_ctrl->Layout();
+            m_ctrl->LayoutContent();
             m_ctrl->PositionCaret();
-            m_ctrl->Refresh();
+            m_ctrl->Refresh(false);
 
             if (sendUpdateEvent)
                 m_ctrl->SendUpdateEvent();
@@ -4245,7 +4363,7 @@ bool wxRichTextImage::Layout(wxDC& WXUNUSED(dc), const wxRect& rect, int WXUNUSE
 
 /// Get/set the object size for the given range. Returns false if the range
 /// is invalid for this object.
-bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags)) const
+bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position)) const
 {
     if (!range.IsWithin(GetRange()))
         return false;
@@ -4776,6 +4894,9 @@ void wxRichTextAttr::CopyTo(wxTextAttrEx& attr) const
 wxFont wxRichTextAttr::CreateFont() const
 {
     wxFont font(m_fontSize, wxDEFAULT, m_fontStyle, m_fontWeight, m_fontUnderlined, m_fontFaceName);
+#ifdef __WXMAC__
+    font.SetNoAntiAliasing(true);
+#endif
     return font;
 }
 
@@ -4794,6 +4915,94 @@ bool wxRichTextAttr::GetFontAttributes(const wxFont& font)
     return true;
 }
 
+wxRichTextAttr wxRichTextAttr::Combine(const wxRichTextAttr& attr,
+                               const wxRichTextAttr& attrDef,
+                               const wxTextCtrlBase *text)
+{
+    wxColour colFg = attr.GetTextColour();
+    if ( !colFg.Ok() )
+    {
+        colFg = attrDef.GetTextColour();
+
+        if ( text && !colFg.Ok() )
+            colFg = text->GetForegroundColour();
+    }
+
+    wxColour colBg = attr.GetBackgroundColour();
+    if ( !colBg.Ok() )
+    {
+        colBg = attrDef.GetBackgroundColour();
+
+        if ( text && !colBg.Ok() )
+            colBg = text->GetBackgroundColour();
+    }
+
+    wxRichTextAttr newAttr(colFg, colBg);
+
+    if (attr.HasWeight())
+        newAttr.SetFontWeight(attr.GetFontWeight());
+
+    if (attr.HasSize())
+        newAttr.SetFontSize(attr.GetFontSize());
+
+    if (attr.HasItalic())
+        newAttr.SetFontStyle(attr.GetFontStyle());
+
+    if (attr.HasUnderlined())
+        newAttr.SetFontUnderlined(attr.GetFontUnderlined());
+
+    if (attr.HasFaceName())
+        newAttr.SetFontFaceName(attr.GetFontFaceName());
+
+    if (attr.HasAlignment())
+        newAttr.SetAlignment(attr.GetAlignment());
+    else if (attrDef.HasAlignment())
+        newAttr.SetAlignment(attrDef.GetAlignment());
+
+    if (attr.HasTabs())
+        newAttr.SetTabs(attr.GetTabs());
+    else if (attrDef.HasTabs())
+        newAttr.SetTabs(attrDef.GetTabs());
+
+    if (attr.HasLeftIndent())
+        newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent());
+    else if (attrDef.HasLeftIndent())
+        newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent());
+
+    if (attr.HasRightIndent())
+        newAttr.SetRightIndent(attr.GetRightIndent());
+    else if (attrDef.HasRightIndent())
+        newAttr.SetRightIndent(attrDef.GetRightIndent());
+
+    // NEW ATTRIBUTES
+
+    if (attr.HasParagraphSpacingAfter())
+        newAttr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter());
+
+    if (attr.HasParagraphSpacingBefore())
+        newAttr.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore());
+
+    if (attr.HasLineSpacing())
+        newAttr.SetLineSpacing(attr.GetLineSpacing());
+
+    if (attr.HasCharacterStyleName())
+        newAttr.SetCharacterStyleName(attr.GetCharacterStyleName());
+
+    if (attr.HasParagraphStyleName())
+        newAttr.SetParagraphStyleName(attr.GetParagraphStyleName());
+
+    if (attr.HasBulletStyle())
+        newAttr.SetBulletStyle(attr.GetBulletStyle());
+
+    if (attr.HasBulletNumber())
+        newAttr.SetBulletNumber(attr.GetBulletNumber());
+
+    if (attr.HasBulletSymbol())
+        newAttr.SetBulletSymbol(attr.GetBulletSymbol());
+
+    return newAttr;
+}
+
 /*!
  * wxTextAttrEx is an extended version of wxTextAttr with more paragraph attributes.
  */
@@ -4843,6 +5052,146 @@ void wxTextAttrEx::operator= (const wxTextAttr& attr)
     wxTextAttr::operator= (attr);
 }
 
+wxTextAttrEx wxTextAttrEx::CombineEx(const wxTextAttrEx& attr,
+                               const wxTextAttrEx& attrDef,
+                               const wxTextCtrlBase *text)
+{
+    wxTextAttrEx newAttr;
+
+    // If attr specifies the complete font, just use that font, overriding all
+    // default font attributes.
+    if ((attr.GetFlags() & wxTEXT_ATTR_FONT) == wxTEXT_ATTR_FONT)
+        newAttr.SetFont(attr.GetFont());
+    else
+    {
+        // First find the basic, default font
+        long flags = 0;
+
+        wxFont font;
+        if (attrDef.HasFont())
+        {
+            flags = (attrDef.GetFlags() & wxTEXT_ATTR_FONT);
+            font = attrDef.GetFont();
+        }
+        else
+        {
+            if (text)
+                font = text->GetFont();
+
+            // We leave flags at 0 because no font attributes have been specified yet
+        }
+        if (!font.Ok())
+            font = *wxNORMAL_FONT;
+
+        // Otherwise, if there are font attributes in attr, apply them
+        if (attr.HasFont())
+        {
+            if (attr.HasSize())
+            {
+                flags |= wxTEXT_ATTR_FONT_SIZE;
+                font.SetPointSize(attr.GetFont().GetPointSize());
+            }
+            if (attr.HasItalic())
+            {
+                flags |= wxTEXT_ATTR_FONT_ITALIC;;
+                font.SetStyle(attr.GetFont().GetStyle());
+            }
+            if (attr.HasWeight())
+            {
+                flags |= wxTEXT_ATTR_FONT_WEIGHT;
+                font.SetWeight(attr.GetFont().GetWeight());
+            }
+            if (attr.HasFaceName())
+            {
+                flags |= wxTEXT_ATTR_FONT_FACE;
+                font.SetFaceName(attr.GetFont().GetFaceName());
+            }
+            if (attr.HasUnderlined())
+            {
+                flags |= wxTEXT_ATTR_FONT_UNDERLINE;
+                font.SetUnderlined(attr.GetFont().GetUnderlined());
+            }
+            newAttr.SetFont(font);
+            newAttr.SetFlags(newAttr.GetFlags()|flags);
+        }
+    }
+
+    // TODO: should really check we are specifying these in the flags,
+    // before setting them, as per above; or we will set them willy-nilly.
+    // However, we should also check whether this is the intention
+    // as per wxTextAttr::Combine, i.e. always to have valid colours
+    // in the style.
+    wxColour colFg = attr.GetTextColour();
+    if ( !colFg.Ok() )
+    {
+        colFg = attrDef.GetTextColour();
+
+        if ( text && !colFg.Ok() )
+            colFg = text->GetForegroundColour();
+    }
+
+    wxColour colBg = attr.GetBackgroundColour();
+    if ( !colBg.Ok() )
+    {
+        colBg = attrDef.GetBackgroundColour();
+
+        if ( text && !colBg.Ok() )
+            colBg = text->GetBackgroundColour();
+    }
+
+    newAttr.SetTextColour(colFg);
+    newAttr.SetBackgroundColour(colBg);
+
+    if (attr.HasAlignment())
+        newAttr.SetAlignment(attr.GetAlignment());
+    else if (attrDef.HasAlignment())
+        newAttr.SetAlignment(attrDef.GetAlignment());
+
+    if (attr.HasTabs())
+        newAttr.SetTabs(attr.GetTabs());
+    else if (attrDef.HasTabs())
+        newAttr.SetTabs(attrDef.GetTabs());
+
+    if (attr.HasLeftIndent())
+        newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent());
+    else if (attrDef.HasLeftIndent())
+        newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent());
+
+    if (attr.HasRightIndent())
+        newAttr.SetRightIndent(attr.GetRightIndent());
+    else if (attrDef.HasRightIndent())
+        newAttr.SetRightIndent(attrDef.GetRightIndent());
+
+    // NEW ATTRIBUTES
+
+    if (attr.HasParagraphSpacingAfter())
+        newAttr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter());
+
+    if (attr.HasParagraphSpacingBefore())
+        newAttr.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore());
+
+    if (attr.HasLineSpacing())
+        newAttr.SetLineSpacing(attr.GetLineSpacing());
+
+    if (attr.HasCharacterStyleName())
+        newAttr.SetCharacterStyleName(attr.GetCharacterStyleName());
+
+    if (attr.HasParagraphStyleName())
+        newAttr.SetParagraphStyleName(attr.GetParagraphStyleName());
+
+    if (attr.HasBulletStyle())
+        newAttr.SetBulletStyle(attr.GetBulletStyle());
+
+    if (attr.HasBulletNumber())
+        newAttr.SetBulletNumber(attr.GetBulletNumber());
+
+    if (attr.HasBulletSymbol())
+        newAttr.SetBulletSymbol(attr.GetBulletSymbol());
+
+    return newAttr;
+}
+
+
 /*!
  * wxRichTextFileHandler
  * Base class for file handlers
@@ -4856,8 +5205,8 @@ bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer *buffer, const wxString& f
     wxFFileInputStream stream(filename);
     if (stream.Ok())
         return LoadFile(buffer, stream);
-    else
-        return false;
+
+    return false;
 }
 
 bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& filename)
@@ -4865,8 +5214,8 @@ bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& f
     wxFFileOutputStream stream(filename);
     if (stream.Ok())
         return SaveFile(buffer, stream);
-    else
-        return false;
+
+    return false;
 }
 #endif // wxUSE_STREAMS
 
@@ -4903,10 +5252,10 @@ bool wxRichTextPlainTextHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStr
         {
             if (ch == 10 && lastCh != 13)
                 str += wxT('\n');
-            
+
             if (ch > 0 && ch != 10)
                 str += wxChar(ch);
-            
+
             lastCh = ch;
         }
     }
@@ -4927,7 +5276,7 @@ bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputSt
     wxString text = buffer->GetText();
     wxCharBuffer buf = text.ToAscii();
 
-    stream.Write((const char*) buf, text.Length());
+    stream.Write((const char*) buf, text.length());
     return true;
 }
 #endif // wxUSE_STREAMS
@@ -4965,8 +5314,7 @@ void wxRichTextImageBlock::Init()
 
 void wxRichTextImageBlock::Clear()
 {
-    if (m_data)
-        delete m_data;
+    delete[] m_data;
     m_data = NULL;
     m_dataSize = 0;
     m_imageType = -1;
@@ -5127,7 +5475,7 @@ bool wxRichTextImageBlock::WriteHex(wxOutputStream& stream)
         hex = wxDecToHex(m_data[i]);
         wxCharBuffer buf = hex.ToAscii();
 
-        stream.Write((const char*) buf, hex.Length());
+        stream.Write((const char*) buf, hex.length());
     }
 
     return true;
@@ -5200,4 +5548,3 @@ bool wxRichTextImageBlock::WriteBlock(const wxString& filename, unsigned char* b
 
 #endif
     // wxUSE_RICHTEXT
-