]> git.saurik.com Git - wxWidgets.git/blobdiff - src/richtext/richtextbuffer.cpp
Better temporary fix.
[wxWidgets.git] / src / richtext / richtextbuffer.cpp
index dd30e8ce1a66e54f20919e2c902c6c788b5d77a8..13a67f7c692df42ba345a88cf7099e3822b6660f 100644 (file)
@@ -441,13 +441,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;
@@ -567,7 +567,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();
+            wxRichTextObjectList::compatibility_iterator previousNode;
+            if ( firstNode )
+                previousNode = firstNode->GetPrevious();
             if (firstNode && previousNode)
             {
                 wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
@@ -589,10 +591,13 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl
         // 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);
 
@@ -652,7 +657,7 @@ 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;
 
@@ -708,7 +713,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);
 
@@ -1406,7 +1411,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);
@@ -1666,7 +1671,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;
 }
@@ -1957,7 +1968,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));
@@ -2070,7 +2081,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)
         {
@@ -2305,7 +2316,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;
@@ -2329,7 +2340,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;
@@ -2374,7 +2385,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;
@@ -2475,7 +2486,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;
@@ -2528,7 +2539,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;
 
@@ -2942,7 +2953,7 @@ 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);
@@ -2952,15 +2963,18 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
         dc.DrawRectangle(selRect);
         dc.SetTextForeground(*wxWHITE);
         dc.SetBackgroundMode(wxTRANSPARENT);
-        dc.DrawText(stringChunk, x, y);
+        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);
+        dc.DrawText(stringChunk, x, y);*/
+        DrawTabbedString(dc, rect,stringChunk, x, y, false);
     }
     else
     {
@@ -2978,13 +2992,14 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
             if (fragmentLen < 0)
                 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;
+            x += w;*/
+            DrawTabbedString(dc, rect,stringFragment, x, y, false);
         }
 
         // 2. Selected chunk, if any.
@@ -2997,7 +3012,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
             if (fragmentLen < 0)
                 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());
@@ -3008,7 +3023,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
             dc.SetTextForeground(*wxWHITE);
             dc.DrawText(stringFragment, x, y);
 
-            x += w;
+            x += w;*/
+            DrawTabbedString(dc, rect,stringFragment, x, y, true);
         }
 
         // 3. Remaining unselected chunk, if any
@@ -3021,15 +3037,76 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR
             if (fragmentLen < 0)
                 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);
+            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))
 {
@@ -3053,7 +3130,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;
@@ -3069,9 +3146,44 @@ 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;
 }
 
@@ -3849,6 +3961,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());
 
@@ -4254,7 +4367,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;
@@ -4806,6 +4919,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.
  */
@@ -4855,6 +5056,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