1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        richtext/richtextbuffer.cpp 
   3 // Purpose:     Buffer for wxRichTextCtrl 
   4 // Author:      Julian Smart 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // For compilers that support precompilation, includes "wx.h". 
  13 #include "wx/wxprec.h" 
  21 #include "wx/richtext/richtextbuffer.h" 
  27 #include "wx/filename.h" 
  28 #include "wx/clipbrd.h" 
  29 #include "wx/dataobj.h" 
  30 #include "wx/wfstream.h" 
  31 #include "wx/module.h" 
  32 #include "wx/mstream.h" 
  33 #include "wx/sstream.h" 
  35 #include "wx/richtext/richtextctrl.h" 
  36 #include "wx/richtext/richtextstyles.h" 
  38 #include "wx/listimpl.cpp" 
  40 WX_DEFINE_LIST(wxRichTextObjectList
) 
  41 WX_DEFINE_LIST(wxRichTextLineList
) 
  45  * This is the base for drawable objects. 
  48 IMPLEMENT_CLASS(wxRichTextObject
, wxObject
) 
  50 wxRichTextObject::wxRichTextObject(wxRichTextObject
* parent
) 
  62 wxRichTextObject::~wxRichTextObject() 
  66 void wxRichTextObject::Dereference() 
  74 void wxRichTextObject::Copy(const wxRichTextObject
& obj
) 
  78     m_dirty 
= obj
.m_dirty
; 
  79     m_range 
= obj
.m_range
; 
  80     m_attributes 
= obj
.m_attributes
; 
  81     m_descent 
= obj
.m_descent
; 
  83     if (!m_attributes
.GetFont().Ok()) 
  84         wxLogDebug(wxT("No font!")); 
  85     if (!obj
.m_attributes
.GetFont().Ok()) 
  86         wxLogDebug(wxT("Parent has no font!")); 
  89 void wxRichTextObject::SetMargins(int margin
) 
  91     m_leftMargin 
= m_rightMargin 
= m_topMargin 
= m_bottomMargin 
= margin
; 
  94 void wxRichTextObject::SetMargins(int leftMargin
, int rightMargin
, int topMargin
, int bottomMargin
) 
  96     m_leftMargin 
= leftMargin
; 
  97     m_rightMargin 
= rightMargin
; 
  98     m_topMargin 
= topMargin
; 
  99     m_bottomMargin 
= bottomMargin
; 
 102 // Convert units in tends of a millimetre to device units 
 103 int wxRichTextObject::ConvertTenthsMMToPixels(wxDC
& dc
, int units
) 
 105     int ppi 
= dc
.GetPPI().x
; 
 107     // There are ppi pixels in 254.1 "1/10 mm" 
 109     double pixels 
= ((double) units 
* (double)ppi
) / 254.1; 
 114 /// Dump to output stream for debugging 
 115 void wxRichTextObject::Dump(wxTextOutputStream
& stream
) 
 117     stream 
<< GetClassInfo()->GetClassName() << wxT("\n"); 
 118     stream 
<< wxString::Format(wxT("Size: %d,%d. Position: %d,%d, Range: %ld,%ld"), m_size
.x
, m_size
.y
, m_pos
.x
, m_pos
.y
, m_range
.GetStart(), m_range
.GetEnd()) << wxT("\n"); 
 119     stream 
<< wxString::Format(wxT("Text colour: %d,%d,%d."), (int) m_attributes
.GetTextColour().Red(), (int) m_attributes
.GetTextColour().Green(), (int) m_attributes
.GetTextColour().Blue()) << wxT("\n"); 
 124  * wxRichTextCompositeObject 
 125  * This is the base for drawable objects. 
 128 IMPLEMENT_CLASS(wxRichTextCompositeObject
, wxRichTextObject
) 
 130 wxRichTextCompositeObject::wxRichTextCompositeObject(wxRichTextObject
* parent
): 
 131     wxRichTextObject(parent
) 
 135 wxRichTextCompositeObject::~wxRichTextCompositeObject() 
 140 /// Get the nth child 
 141 wxRichTextObject
* wxRichTextCompositeObject::GetChild(size_t n
) const 
 143     wxASSERT ( n 
< m_children
.GetCount() ); 
 145     return m_children
.Item(n
)->GetData(); 
 148 /// Append a child, returning the position 
 149 size_t wxRichTextCompositeObject::AppendChild(wxRichTextObject
* child
) 
 151     m_children
.Append(child
); 
 152     child
->SetParent(this); 
 153     return m_children
.GetCount() - 1; 
 156 /// Insert the child in front of the given object, or at the beginning 
 157 bool wxRichTextCompositeObject::InsertChild(wxRichTextObject
* child
, wxRichTextObject
* inFrontOf
) 
 161         wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(inFrontOf
); 
 162         m_children
.Insert(node
, child
); 
 165         m_children
.Insert(child
); 
 166     child
->SetParent(this); 
 172 bool wxRichTextCompositeObject::RemoveChild(wxRichTextObject
* child
, bool deleteChild
) 
 174     wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(child
); 
 177         wxRichTextObject
* obj 
= node
->GetData(); 
 178         m_children
.Erase(node
); 
 187 /// Delete all children 
 188 bool wxRichTextCompositeObject::DeleteChildren() 
 190     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 193         wxRichTextObjectList::compatibility_iterator oldNode 
= node
; 
 195         wxRichTextObject
* child 
= node
->GetData(); 
 196         child
->Dereference(); // Only delete if reference count is zero 
 198         node 
= node
->GetNext(); 
 199         m_children
.Erase(oldNode
); 
 205 /// Get the child count 
 206 size_t wxRichTextCompositeObject::GetChildCount() const 
 208     return m_children
.GetCount(); 
 212 void wxRichTextCompositeObject::Copy(const wxRichTextCompositeObject
& obj
) 
 214     wxRichTextObject::Copy(obj
); 
 218     wxRichTextObjectList::compatibility_iterator node 
= obj
.m_children
.GetFirst(); 
 221         wxRichTextObject
* child 
= node
->GetData(); 
 222         m_children
.Append(child
->Clone()); 
 224         node 
= node
->GetNext(); 
 228 /// Hit-testing: returns a flag indicating hit test details, plus 
 229 /// information about position 
 230 int wxRichTextCompositeObject::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
) 
 232     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 235         wxRichTextObject
* child 
= node
->GetData(); 
 237         int ret 
= child
->HitTest(dc
, pt
, textPosition
); 
 238         if (ret 
!= wxRICHTEXT_HITTEST_NONE
) 
 241         node 
= node
->GetNext(); 
 244     return wxRICHTEXT_HITTEST_NONE
; 
 247 /// Finds the absolute position and row height for the given character position 
 248 bool wxRichTextCompositeObject::FindPosition(wxDC
& dc
, long index
, wxPoint
& pt
, int* height
, bool forceLineStart
) 
 250     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 253         wxRichTextObject
* child 
= node
->GetData(); 
 255         if (child
->FindPosition(dc
, index
, pt
, height
, forceLineStart
)) 
 258         node 
= node
->GetNext(); 
 265 void wxRichTextCompositeObject::CalculateRange(long start
, long& end
) 
 267     long current 
= start
; 
 268     long lastEnd 
= current
; 
 270     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 273         wxRichTextObject
* child 
= node
->GetData(); 
 276         child
->CalculateRange(current
, childEnd
); 
 279         current 
= childEnd 
+ 1; 
 281         node 
= node
->GetNext(); 
 286     // An object with no children has zero length 
 287     if (m_children
.GetCount() == 0) 
 290     m_range
.SetRange(start
, end
); 
 293 /// Delete range from layout. 
 294 bool wxRichTextCompositeObject::DeleteRange(const wxRichTextRange
& range
) 
 296     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 300         wxRichTextObject
* obj 
= (wxRichTextObject
*) node
->GetData(); 
 301         wxRichTextObjectList::compatibility_iterator next 
= node
->GetNext(); 
 303         // Delete the range in each paragraph 
 305         // When a chunk has been deleted, internally the content does not 
 306         // now match the ranges. 
 307         // However, so long as deletion is not done on the same object twice this is OK. 
 308         // If you may delete content from the same object twice, recalculate 
 309         // the ranges inbetween DeleteRange calls by calling CalculateRanges, and 
 310         // adjust the range you're deleting accordingly. 
 312         if (!obj
->GetRange().IsOutside(range
)) 
 314             obj
->DeleteRange(range
); 
 316             // Delete an empty object, or paragraph within this range. 
 317             if (obj
->IsEmpty() || 
 318                 (range
.GetStart() <= obj
->GetRange().GetStart() && range
.GetEnd() >= obj
->GetRange().GetEnd())) 
 320                 // An empty paragraph has length 1, so won't be deleted unless the 
 321                 // whole range is deleted. 
 322                 RemoveChild(obj
, true); 
 332 /// Get any text in this object for the given range 
 333 wxString 
wxRichTextCompositeObject::GetTextForRange(const wxRichTextRange
& range
) const 
 336     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 339         wxRichTextObject
* child 
= node
->GetData(); 
 340         wxRichTextRange childRange 
= range
; 
 341         if (!child
->GetRange().IsOutside(range
)) 
 343             childRange
.LimitTo(child
->GetRange()); 
 345             wxString childText 
= child
->GetTextForRange(childRange
); 
 349         node 
= node
->GetNext(); 
 355 /// Recursively merge all pieces that can be merged. 
 356 bool wxRichTextCompositeObject::Defragment() 
 358     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 361         wxRichTextObject
* child 
= node
->GetData(); 
 362         wxRichTextCompositeObject
* composite 
= wxDynamicCast(child
, wxRichTextCompositeObject
); 
 364             composite
->Defragment(); 
 368             wxRichTextObject
* nextChild 
= node
->GetNext()->GetData(); 
 369             if (child
->CanMerge(nextChild
) && child
->Merge(nextChild
)) 
 371                 nextChild
->Dereference(); 
 372                 m_children
.Erase(node
->GetNext()); 
 374                 // Don't set node -- we'll see if we can merge again with the next 
 378                 node 
= node
->GetNext(); 
 381             node 
= node
->GetNext(); 
 387 /// Dump to output stream for debugging 
 388 void wxRichTextCompositeObject::Dump(wxTextOutputStream
& stream
) 
 390     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 393         wxRichTextObject
* child 
= node
->GetData(); 
 395         node 
= node
->GetNext(); 
 402  * This defines a 2D space to lay out objects 
 405 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBox
, wxRichTextCompositeObject
) 
 407 wxRichTextBox::wxRichTextBox(wxRichTextObject
* parent
): 
 408     wxRichTextCompositeObject(parent
) 
 413 bool wxRichTextBox::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextRange
& selectionRange
, const wxRect
& WXUNUSED(rect
), int descent
, int style
) 
 415     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 418         wxRichTextObject
* child 
= node
->GetData(); 
 420         wxRect childRect 
= wxRect(child
->GetPosition(), child
->GetCachedSize()); 
 421         child
->Draw(dc
, range
, selectionRange
, childRect
, descent
, style
); 
 423         node 
= node
->GetNext(); 
 429 bool wxRichTextBox::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
 431     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 434         wxRichTextObject
* child 
= node
->GetData(); 
 435         child
->Layout(dc
, rect
, style
); 
 437         node 
= node
->GetNext(); 
 443 /// Get/set the size for the given range. Assume only has one child. 
 444 bool wxRichTextBox::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
) const 
 446     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 449         wxRichTextObject
* child 
= node
->GetData(); 
 450         return child
->GetRangeSize(range
, size
, descent
, dc
, flags
); 
 457 void wxRichTextBox::Copy(const wxRichTextBox
& obj
) 
 459     wxRichTextCompositeObject::Copy(obj
); 
 464  * wxRichTextParagraphLayoutBox 
 465  * This box knows how to lay out paragraphs. 
 468 IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraphLayoutBox
, wxRichTextBox
) 
 470 wxRichTextParagraphLayoutBox::wxRichTextParagraphLayoutBox(wxRichTextObject
* parent
): 
 471     wxRichTextBox(parent
) 
 476 /// Initialize the object. 
 477 void wxRichTextParagraphLayoutBox::Init() 
 481     // For now, assume is the only box and has no initial size. 
 482     m_range 
= wxRichTextRange(0, -1); 
 484     m_invalidRange
.SetRange(-1, -1); 
 492 bool wxRichTextParagraphLayoutBox::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextRange
& selectionRange
, const wxRect
& rect
, int descent
, int style
) 
 494     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 497         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 498         wxASSERT (child 
!= NULL
); 
 500         if (child 
&& !child
->GetRange().IsOutside(range
)) 
 502             wxRect 
childRect(child
->GetPosition(), child
->GetCachedSize()); 
 504             if (childRect
.GetTop() > rect
.GetBottom() || childRect
.GetBottom() < rect
.GetTop()) 
 509                 child
->Draw(dc
, child
->GetRange(), selectionRange
, childRect
, descent
, style
); 
 512         node 
= node
->GetNext(); 
 518 bool wxRichTextParagraphLayoutBox::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
 520     wxRect availableSpace
; 
 521     bool formatRect 
= (style 
& wxRICHTEXT_LAYOUT_SPECIFIED_RECT
) == wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
 523     // If only laying out a specific area, the passed rect has a different meaning: 
 524     // the visible part of the buffer. 
 527         availableSpace 
= wxRect(0 + m_leftMargin
, 
 529                           rect
.width 
- m_leftMargin 
- m_rightMargin
, 
 532         // Invalidate the part of the buffer from the first visible line 
 533         // to the end. If other parts of the buffer are currently invalid, 
 534         // then they too will be taken into account if they are above 
 535         // the visible point. 
 537         wxRichTextLine
* line 
= GetLineAtYPosition(rect
.y
); 
 539             startPos 
= line
->GetAbsoluteRange().GetStart(); 
 541         Invalidate(wxRichTextRange(startPos
, GetRange().GetEnd())); 
 544         availableSpace 
= wxRect(rect
.x 
+ m_leftMargin
, 
 545                           rect
.y 
+ m_topMargin
, 
 546                           rect
.width 
- m_leftMargin 
- m_rightMargin
, 
 547                           rect
.height 
- m_topMargin 
- m_bottomMargin
); 
 551     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 553     bool layoutAll 
= true; 
 555     // Get invalid range, rounding to paragraph start/end. 
 556     wxRichTextRange invalidRange 
= GetInvalidRange(true); 
 558     if (invalidRange 
== wxRICHTEXT_NONE 
&& !formatRect
) 
 561     if (invalidRange 
== wxRICHTEXT_ALL
) 
 563     else    // If we know what range is affected, start laying out from that point on. 
 564         if (invalidRange
.GetStart() > GetRange().GetStart()) 
 566         wxRichTextParagraph
* firstParagraph 
= GetParagraphAtPosition(invalidRange
.GetStart()); 
 569             wxRichTextObjectList::compatibility_iterator firstNode 
= m_children
.Find(firstParagraph
); 
 570             wxRichTextObjectList::compatibility_iterator previousNode 
= firstNode 
? firstNode
->GetPrevious() : wxRichTextObjectList::compatibility_iterator(); 
 571             if (firstNode 
&& previousNode
) 
 573                 wxRichTextParagraph
* previousParagraph 
= wxDynamicCast(previousNode
->GetData(), wxRichTextParagraph
); 
 574                 availableSpace
.y 
= previousParagraph
->GetPosition().y 
+ previousParagraph
->GetCachedSize().y
; 
 576                 // Now we're going to start iterating from the first affected paragraph. 
 584     // A way to force speedy rest-of-buffer layout (the 'else' below) 
 585     bool forceQuickLayout 
= false; 
 589         // Assume this box only contains paragraphs 
 591         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 592         wxASSERT (child 
!= NULL
); 
 594         // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines 
 595         if (child 
&& !forceQuickLayout 
&& (layoutAll 
|| child
->GetLines().GetCount() == 0 || !child
->GetRange().IsOutside(invalidRange
))) 
 597             child
->Layout(dc
, availableSpace
, style
); 
 599             // Layout must set the cached size 
 600             availableSpace
.y 
+= child
->GetCachedSize().y
; 
 601             maxWidth 
= wxMax(maxWidth
, child
->GetCachedSize().x
); 
 603             // If we're just formatting the visible part of the buffer, 
 604             // and we're now past the bottom of the window, start quick 
 606             if (formatRect 
&& child
->GetPosition().y 
> rect
.GetBottom()) 
 607                 forceQuickLayout 
= true; 
 611             // We're outside the immediately affected range, so now let's just 
 612             // move everything up or down. This assumes that all the children have previously 
 613             // been laid out and have wrapped line lists associated with them. 
 614             // TODO: check all paragraphs before the affected range. 
 616             int inc 
= availableSpace
.y 
- child
->GetPosition().y
; 
 620                 wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 623                     if (child
->GetLines().GetCount() == 0) 
 624                         child
->Layout(dc
, availableSpace
, style
); 
 626                         child
->SetPosition(wxPoint(child
->GetPosition().x
, child
->GetPosition().y 
+ inc
)); 
 628                     availableSpace
.y 
+= child
->GetCachedSize().y
; 
 629                     maxWidth 
= wxMax(maxWidth
, child
->GetCachedSize().x
); 
 632                 node 
= node
->GetNext(); 
 637         node 
= node
->GetNext(); 
 640     SetCachedSize(wxSize(maxWidth
, availableSpace
.y
)); 
 643     m_invalidRange 
= wxRICHTEXT_NONE
; 
 649 void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox
& obj
) 
 651     wxRichTextBox::Copy(obj
); 
 654 /// Get/set the size for the given range. 
 655 bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
) const 
 659     wxRichTextObjectList::compatibility_iterator startPara 
= wxRichTextObjectList::compatibility_iterator(); 
 660     wxRichTextObjectList::compatibility_iterator endPara 
= wxRichTextObjectList::compatibility_iterator(); 
 662     // First find the first paragraph whose starting position is within the range. 
 663     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 666         // child is a paragraph 
 667         wxRichTextObject
* child 
= node
->GetData(); 
 668         const wxRichTextRange
& r 
= child
->GetRange(); 
 670         if (r
.GetStart() <= range
.GetStart() && r
.GetEnd() >= range
.GetStart()) 
 676         node 
= node
->GetNext(); 
 679     // Next find the last paragraph containing part of the range 
 680     node 
= m_children
.GetFirst(); 
 683         // child is a paragraph 
 684         wxRichTextObject
* child 
= node
->GetData(); 
 685         const wxRichTextRange
& r 
= child
->GetRange(); 
 687         if (r
.GetStart() <= range
.GetEnd() && r
.GetEnd() >= range
.GetEnd()) 
 693         node 
= node
->GetNext(); 
 696     if (!startPara 
|| !endPara
) 
 699     // Now we can add up the sizes 
 700     for (node 
= startPara
; node 
; node 
= node
->GetNext()) 
 702         // child is a paragraph 
 703         wxRichTextObject
* child 
= node
->GetData(); 
 704         const wxRichTextRange
& childRange 
= child
->GetRange(); 
 705         wxRichTextRange rangeToFind 
= range
; 
 706         rangeToFind
.LimitTo(childRange
); 
 710         int childDescent 
= 0; 
 711         child
->GetRangeSize(rangeToFind
, childSize
, childDescent
, dc
, flags
); 
 713         descent 
= wxMax(childDescent
, descent
); 
 715         sz
.x 
= wxMax(sz
.x
, childSize
.x
); 
 727 /// Get the paragraph at the given position 
 728 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphAtPosition(long pos
, bool caretPosition
) const 
 733     // First find the first paragraph whose starting position is within the range. 
 734     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 737         // child is a paragraph 
 738         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 739         wxASSERT (child 
!= NULL
); 
 741         // Return first child in buffer if position is -1 
 745         if (child
->GetRange().Contains(pos
)) 
 748         node 
= node
->GetNext(); 
 753 /// Get the line at the given position 
 754 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos
, bool caretPosition
) const 
 759     // First find the first paragraph whose starting position is within the range. 
 760     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 763         // child is a paragraph 
 764         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 765         wxASSERT (child 
!= NULL
); 
 767         wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
 770             wxRichTextLine
* line 
= node2
->GetData(); 
 772             wxRichTextRange range 
= line
->GetAbsoluteRange(); 
 774             if (range
.Contains(pos
) || 
 776                 // If the position is end-of-paragraph, then return the last line of 
 778                 (range
.GetEnd() == child
->GetRange().GetEnd()-1) && (pos 
== child
->GetRange().GetEnd())) 
 781             node2 
= node2
->GetNext(); 
 784         node 
= node
->GetNext(); 
 787     int lineCount 
= GetLineCount(); 
 789         return GetLineForVisibleLineNumber(lineCount
-1); 
 794 /// Get the line at the given y pixel position, or the last line. 
 795 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineAtYPosition(int y
) const 
 797     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 800         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 801         wxASSERT (child 
!= NULL
); 
 803         wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
 806             wxRichTextLine
* line 
= node2
->GetData(); 
 808             wxRect 
rect(line
->GetRect()); 
 810             if (y 
<= rect
.GetBottom()) 
 813             node2 
= node2
->GetNext(); 
 816         node 
= node
->GetNext(); 
 820     int lineCount 
= GetLineCount(); 
 822         return GetLineForVisibleLineNumber(lineCount
-1); 
 827 /// Get the number of visible lines 
 828 int wxRichTextParagraphLayoutBox::GetLineCount() const 
 832     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
 835         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
 836         wxASSERT (child 
!= NULL
); 
 838         count 
+= child
->GetLines().GetCount(); 
 839         node 
= node
->GetNext(); 
 845 /// Get the paragraph for a given line 
 846 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphForLine(wxRichTextLine
* line
) const 
 848     return GetParagraphAtPosition(line
->GetAbsoluteRange().GetStart()); 
 851 /// Get the line size at the given position 
 852 wxSize 
wxRichTextParagraphLayoutBox::GetLineSizeAtPosition(long pos
, bool caretPosition
) const 
 854     wxRichTextLine
* line 
= GetLineAtPosition(pos
, caretPosition
); 
 857         return line
->GetSize(); 
 864 /// Convenience function to add a paragraph of text 
 865 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddParagraph(const wxString
& text
) 
 867     wxTextAttrEx 
style(GetAttributes()); 
 869     // Apply default style. If the style has no attributes set, 
 870     // then the attributes will remain the 'basic style' (i.e. the 
 871     // layout box's style). 
 872     wxRichTextApplyStyle(style
, GetDefaultStyle()); 
 874     wxRichTextParagraph
* para 
= new wxRichTextParagraph(text
, this, & style
); 
 881     return para
->GetRange(); 
 884 /// Adds multiple paragraphs, based on newlines. 
 885 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddParagraphs(const wxString
& text
) 
 887     wxTextAttrEx 
style(GetAttributes()); 
 888     //wxLogDebug("Initial style = %s", style.GetFont().GetFaceName()); 
 889     //wxLogDebug("Initial size = %d", style.GetFont().GetPointSize()); 
 891     // Apply default style. If the style has no attributes set, 
 892     // then the attributes will remain the 'basic style' (i.e. the 
 893     // layout box's style). 
 894     wxRichTextApplyStyle(style
, GetDefaultStyle()); 
 896     //wxLogDebug("Style after applying default style = %s", style.GetFont().GetFaceName()); 
 897     //wxLogDebug("Size after applying default style = %d", style.GetFont().GetPointSize()); 
 899     wxRichTextParagraph
* firstPara 
= NULL
; 
 900     wxRichTextParagraph
* lastPara 
= NULL
; 
 902     wxRichTextRange 
range(-1, -1); 
 904     size_t len 
= text
.Length(); 
 909         if (ch 
== wxT('\n') || ch 
== wxT('\r')) 
 911             wxRichTextParagraph
* para 
= new wxRichTextParagraph(line
, this, & style
); 
 917             line 
= wxEmptyString
; 
 926         lastPara 
= new wxRichTextParagraph(line
, this, & style
); 
 927         //wxLogDebug("Para Face = %s", lastPara->GetAttributes().GetFont().GetFaceName()); 
 928         AppendChild(lastPara
); 
 932         range
.SetStart(firstPara
->GetRange().GetStart()); 
 934         range
.SetStart(lastPara
->GetRange().GetStart()); 
 937         range
.SetEnd(lastPara
->GetRange().GetEnd()); 
 939         range
.SetEnd(firstPara
->GetRange().GetEnd()); 
 947 /// Convenience function to add an image 
 948 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddImage(const wxImage
& image
) 
 950     wxTextAttrEx 
style(GetAttributes()); 
 952     // Apply default style. If the style has no attributes set, 
 953     // then the attributes will remain the 'basic style' (i.e. the 
 954     // layout box's style). 
 955     wxRichTextApplyStyle(style
, GetDefaultStyle()); 
 957     wxRichTextParagraph
* para 
= new wxRichTextParagraph(this, & style
); 
 959     para
->AppendChild(new wxRichTextImage(image
, this)); 
 964     return para
->GetRange(); 
 968 /// Insert fragment into this box at the given position. If partialParagraph is true, 
 969 /// it is assumed that the last (or only) paragraph is just a piece of data with no paragraph 
 971 /// TODO: if fragment is inserted inside styled fragment, must apply that style to 
 972 /// to the data (if it has a default style, anyway). 
 974 bool wxRichTextParagraphLayoutBox::InsertFragment(long position
, wxRichTextFragment
& fragment
) 
 978     // First, find the first paragraph whose starting position is within the range. 
 979     wxRichTextParagraph
* para 
= GetParagraphAtPosition(position
); 
 982         wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(para
); 
 984         // Now split at this position, returning the object to insert the new 
 986         wxRichTextObject
* nextObject 
= para
->SplitAt(position
); 
 988         // Special case: partial paragraph, just one paragraph. Might be a small amount of 
 989         // text, for example, so let's optimize. 
 991         if (fragment
.GetPartialParagraph() && fragment
.GetChildren().GetCount() == 1) 
 993             // Add the first para to this para... 
 994             wxRichTextObjectList::compatibility_iterator firstParaNode 
= fragment
.GetChildren().GetFirst(); 
 998             // Iterate through the fragment paragraph inserting the content into this paragraph. 
 999             wxRichTextParagraph
* firstPara 
= wxDynamicCast(firstParaNode
->GetData(), wxRichTextParagraph
); 
1000             wxASSERT (firstPara 
!= NULL
); 
1002             wxRichTextObjectList::compatibility_iterator objectNode 
= firstPara
->GetChildren().GetFirst(); 
1005                 wxRichTextObject
* newObj 
= objectNode
->GetData()->Clone(); 
1010                     para
->AppendChild(newObj
); 
1014                     // Insert before nextObject 
1015                     para
->InsertChild(newObj
, nextObject
); 
1018                 objectNode 
= objectNode
->GetNext(); 
1025             // Procedure for inserting a fragment consisting of a number of 
1028             // 1. Remove and save the content that's after the insertion point, for adding 
1029             //    back once we've added the fragment. 
1030             // 2. Add the content from the first fragment paragraph to the current 
1032             // 3. Add remaining fragment paragraphs after the current paragraph. 
1033             // 4. Add back the saved content from the first paragraph. If partialParagraph 
1034             //    is true, add it to the last paragraph added and not a new one. 
1036             // 1. Remove and save objects after split point. 
1037             wxList savedObjects
; 
1039                 para
->MoveToList(nextObject
, savedObjects
); 
1041             // 2. Add the content from the 1st fragment paragraph. 
1042             wxRichTextObjectList::compatibility_iterator firstParaNode 
= fragment
.GetChildren().GetFirst(); 
1046             wxRichTextParagraph
* firstPara 
= wxDynamicCast(firstParaNode
->GetData(), wxRichTextParagraph
); 
1047             wxASSERT(firstPara 
!= NULL
); 
1049             wxRichTextObjectList::compatibility_iterator objectNode 
= firstPara
->GetChildren().GetFirst(); 
1052                 wxRichTextObject
* newObj 
= objectNode
->GetData()->Clone(); 
1055                 para
->AppendChild(newObj
); 
1057                 objectNode 
= objectNode
->GetNext(); 
1060             // 3. Add remaining fragment paragraphs after the current paragraph. 
1061             wxRichTextObjectList::compatibility_iterator nextParagraphNode 
= node
->GetNext(); 
1062             wxRichTextObject
* nextParagraph 
= NULL
; 
1063             if (nextParagraphNode
) 
1064                 nextParagraph 
= nextParagraphNode
->GetData(); 
1066             wxRichTextObjectList::compatibility_iterator i 
= fragment
.GetChildren().GetFirst()->GetNext(); 
1067             wxRichTextParagraph
* finalPara 
= para
; 
1069             // If there was only one paragraph, we need to insert a new one. 
1072                 finalPara 
= new wxRichTextParagraph
; 
1074                 // TODO: These attributes should come from the subsequent paragraph 
1075                 // when originally deleted, since the subsequent para takes on 
1076                 // the previous para's attributes. 
1077                 finalPara
->SetAttributes(firstPara
->GetAttributes()); 
1080                     InsertChild(finalPara
, nextParagraph
); 
1082                     AppendChild(finalPara
); 
1086                 wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
1087                 wxASSERT( para 
!= NULL 
); 
1089                 finalPara 
= (wxRichTextParagraph
*) para
->Clone(); 
1092                     InsertChild(finalPara
, nextParagraph
); 
1094                     AppendChild(finalPara
); 
1099             // 4. Add back the remaining content. 
1102                 finalPara
->MoveFromList(savedObjects
); 
1104                 // Ensure there's at least one object 
1105                 if (finalPara
->GetChildCount() == 0) 
1107                     wxRichTextPlainText
* text 
= new wxRichTextPlainText(wxEmptyString
); 
1108                     text
->SetAttributes(finalPara
->GetAttributes()); 
1110                     finalPara
->AppendChild(text
); 
1120         wxRichTextObjectList::compatibility_iterator i 
= fragment
.GetChildren().GetFirst(); 
1123             wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
1124             wxASSERT( para 
!= NULL 
); 
1126             AppendChild(para
->Clone()); 
1137 /// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'. 
1138 /// If there was an incomplete paragraph at the end, partialParagraph is set to true. 
1139 bool wxRichTextParagraphLayoutBox::CopyFragment(const wxRichTextRange
& range
, wxRichTextFragment
& fragment
) 
1141     wxRichTextObjectList::compatibility_iterator i 
= GetChildren().GetFirst(); 
1144         wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
1145         wxASSERT( para 
!= NULL 
); 
1147         if (!para
->GetRange().IsOutside(range
)) 
1149             fragment
.AppendChild(para
->Clone()); 
1154     // Now top and tail the first and last paragraphs in our new fragment (which might be the same). 
1155     if (!fragment
.IsEmpty()) 
1157         wxRichTextRange 
topTailRange(range
); 
1159         wxRichTextParagraph
* firstPara 
= wxDynamicCast(fragment
.GetChildren().GetFirst()->GetData(), wxRichTextParagraph
); 
1160         wxASSERT( firstPara 
!= NULL 
); 
1162         // Chop off the start of the paragraph 
1163         if (topTailRange
.GetStart() > firstPara
->GetRange().GetStart()) 
1165             wxRichTextRange 
r(firstPara
->GetRange().GetStart(), topTailRange
.GetStart()-1); 
1166             firstPara
->DeleteRange(r
); 
1168             // Make sure the numbering is correct 
1170             fragment
.CalculateRange(firstPara
->GetRange().GetStart(), end
); 
1172             // Now, we've deleted some positions, so adjust the range 
1174             topTailRange
.SetEnd(topTailRange
.GetEnd() - r
.GetLength()); 
1177         wxRichTextParagraph
* lastPara 
= wxDynamicCast(fragment
.GetChildren().GetLast()->GetData(), wxRichTextParagraph
); 
1178         wxASSERT( lastPara 
!= NULL 
); 
1180         if (topTailRange
.GetEnd() < (lastPara
->GetRange().GetEnd()-1)) 
1182             wxRichTextRange 
r(topTailRange
.GetEnd()+1, lastPara
->GetRange().GetEnd()-1); /* -1 since actual text ends 1 position before end of para marker */ 
1183             lastPara
->DeleteRange(r
); 
1185             // Make sure the numbering is correct 
1187             fragment
.CalculateRange(firstPara
->GetRange().GetStart(), end
); 
1189             // We only have part of a paragraph at the end 
1190             fragment
.SetPartialParagraph(true); 
1194             if (topTailRange
.GetEnd() == (lastPara
->GetRange().GetEnd() - 1)) 
1195                 // We have a partial paragraph (don't save last new paragraph marker) 
1196                 fragment
.SetPartialParagraph(true); 
1198                 // We have a complete paragraph 
1199                 fragment
.SetPartialParagraph(false); 
1206 /// Given a position, get the number of the visible line (potentially many to a paragraph), 
1207 /// starting from zero at the start of the buffer. 
1208 long wxRichTextParagraphLayoutBox::GetVisibleLineNumber(long pos
, bool caretPosition
, bool startOfLine
) const 
1215     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1218         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1219         wxASSERT( child 
!= NULL 
); 
1221         if (child
->GetRange().Contains(pos
)) 
1223             wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
1226                 wxRichTextLine
* line 
= node2
->GetData(); 
1227                 wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1229                 if (lineRange
.Contains(pos
)) 
1231                     // If the caret is displayed at the end of the previous wrapped line, 
1232                     // we want to return the line it's _displayed_ at (not the actual line 
1233                     // containing the position). 
1234                     if (lineRange
.GetStart() == pos 
&& !startOfLine 
&& child
->GetRange().GetStart() != pos
) 
1235                         return lineCount 
- 1; 
1242                 node2 
= node2
->GetNext(); 
1244             // If we didn't find it in the lines, it must be 
1245             // the last position of the paragraph. So return the last line. 
1249             lineCount 
+= child
->GetLines().GetCount(); 
1251         node 
= node
->GetNext(); 
1258 /// Given a line number, get the corresponding wxRichTextLine object. 
1259 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineForVisibleLineNumber(long lineNumber
) const 
1263     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1266         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1267         wxASSERT(child 
!= NULL
); 
1269         if (lineNumber 
< (int) (child
->GetLines().GetCount() + lineCount
)) 
1271             wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
1274                 wxRichTextLine
* line 
= node2
->GetData(); 
1276                 if (lineCount 
== lineNumber
) 
1281                 node2 
= node2
->GetNext(); 
1285             lineCount 
+= child
->GetLines().GetCount(); 
1287         node 
= node
->GetNext(); 
1294 /// Delete range from layout. 
1295 bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange
& range
) 
1297     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1301         wxRichTextParagraph
* obj 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1302         wxASSERT (obj 
!= NULL
); 
1304         wxRichTextObjectList::compatibility_iterator next 
= node
->GetNext(); 
1306         // Delete the range in each paragraph 
1308         if (!obj
->GetRange().IsOutside(range
)) 
1310             // Deletes the content of this object within the given range 
1311             obj
->DeleteRange(range
); 
1313             // If the whole paragraph is within the range to delete, 
1314             // delete the whole thing. 
1315             if (range
.GetStart() <= obj
->GetRange().GetStart() && range
.GetEnd() >= obj
->GetRange().GetEnd()) 
1317                 // Delete the whole object 
1318                 RemoveChild(obj
, true); 
1320             // If the range includes the paragraph end, we need to join this 
1321             // and the next paragraph. 
1322             else if (range
.Contains(obj
->GetRange().GetEnd())) 
1324                 // We need to move the objects from the next paragraph 
1325                 // to this paragraph 
1329                     wxRichTextParagraph
* nextParagraph 
= wxDynamicCast(next
->GetData(), wxRichTextParagraph
); 
1330                     next 
= next
->GetNext(); 
1333                         // Delete the stuff we need to delete 
1334                         nextParagraph
->DeleteRange(range
); 
1336                         // Move the objects to the previous para 
1337                         wxRichTextObjectList::compatibility_iterator node1 
= nextParagraph
->GetChildren().GetFirst(); 
1341                             wxRichTextObject
* obj1 
= node1
->GetData(); 
1343                             // If the object is empty, optimise it out 
1344                             if (obj1
->IsEmpty()) 
1350                                 obj
->AppendChild(obj1
); 
1353                             wxRichTextObjectList::compatibility_iterator next1 
= node1
->GetNext(); 
1354                             nextParagraph
->GetChildren().Erase(node1
); 
1359                         // Delete the paragraph 
1360                         RemoveChild(nextParagraph
, true); 
1374 /// Get any text in this object for the given range 
1375 wxString 
wxRichTextParagraphLayoutBox::GetTextForRange(const wxRichTextRange
& range
) const 
1379     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1382         wxRichTextObject
* child 
= node
->GetData(); 
1383         if (!child
->GetRange().IsOutside(range
)) 
1387             wxRichTextRange childRange 
= range
; 
1388             childRange
.LimitTo(child
->GetRange()); 
1390             wxString childText 
= child
->GetTextForRange(childRange
); 
1396         node 
= node
->GetNext(); 
1402 /// Get all the text 
1403 wxString 
wxRichTextParagraphLayoutBox::GetText() const 
1405     return GetTextForRange(GetRange()); 
1408 /// Get the paragraph by number 
1409 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphAtLine(long paragraphNumber
) const 
1411     if ((size_t) paragraphNumber 
<= GetChildCount()) 
1414     return (wxRichTextParagraph
*) GetChild((size_t) paragraphNumber
); 
1417 /// Get the length of the paragraph 
1418 int wxRichTextParagraphLayoutBox::GetParagraphLength(long paragraphNumber
) const 
1420     wxRichTextParagraph
* para 
= GetParagraphAtLine(paragraphNumber
); 
1422         return para
->GetRange().GetLength() - 1; // don't include newline 
1427 /// Get the text of the paragraph 
1428 wxString 
wxRichTextParagraphLayoutBox::GetParagraphText(long paragraphNumber
) const 
1430     wxRichTextParagraph
* para 
= GetParagraphAtLine(paragraphNumber
); 
1432         return para
->GetTextForRange(para
->GetRange()); 
1434         return wxEmptyString
; 
1437 /// Convert zero-based line column and paragraph number to a position. 
1438 long wxRichTextParagraphLayoutBox::XYToPosition(long x
, long y
) const 
1440     wxRichTextParagraph
* para 
= GetParagraphAtLine(y
); 
1443         return para
->GetRange().GetStart() + x
; 
1449 /// Convert zero-based position to line column and paragraph number 
1450 bool wxRichTextParagraphLayoutBox::PositionToXY(long pos
, long* x
, long* y
) const 
1452     wxRichTextParagraph
* para 
= GetParagraphAtPosition(pos
); 
1456         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1459             wxRichTextObject
* child 
= node
->GetData(); 
1463             node 
= node
->GetNext(); 
1467         *x 
= pos 
- para
->GetRange().GetStart(); 
1475 /// Get the leaf object in a paragraph at this position. 
1476 /// Given a line number, get the corresponding wxRichTextLine object. 
1477 wxRichTextObject
* wxRichTextParagraphLayoutBox::GetLeafObjectAtPosition(long position
) const 
1479     wxRichTextParagraph
* para 
= GetParagraphAtPosition(position
); 
1482         wxRichTextObjectList::compatibility_iterator node 
= para
->GetChildren().GetFirst(); 
1486             wxRichTextObject
* child 
= node
->GetData(); 
1487             if (child
->GetRange().Contains(position
)) 
1490             node 
= node
->GetNext(); 
1492         if (position 
== para
->GetRange().GetEnd() && para
->GetChildCount() > 0) 
1493             return para
->GetChildren().GetLast()->GetData(); 
1498 /// Set character or paragraph text attributes: apply character styles only to immediate text nodes 
1499 bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange
& range
, const wxRichTextAttr
& style
, bool withUndo
) 
1501     bool characterStyle 
= false; 
1502     bool paragraphStyle 
= false; 
1504     if (style
.IsCharacterStyle()) 
1505         characterStyle 
= true; 
1506     if (style
.IsParagraphStyle()) 
1507         paragraphStyle 
= true; 
1509     // If we are associated with a control, make undoable; otherwise, apply immediately 
1512     bool haveControl 
= (GetRichTextCtrl() != NULL
); 
1514     wxRichTextAction
* action 
= NULL
; 
1516     if (haveControl 
&& withUndo
) 
1518         action 
= new wxRichTextAction(NULL
, _("Change Style"), wxRICHTEXT_CHANGE_STYLE
, & GetRichTextCtrl()->GetBuffer(), GetRichTextCtrl()); 
1519         action
->SetRange(range
); 
1520         action
->SetPosition(GetRichTextCtrl()->GetCaretPosition()); 
1523     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1526         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1527         wxASSERT (para 
!= NULL
); 
1529         if (para 
&& para
->GetChildCount() > 0) 
1531             // Stop searching if we're beyond the range of interest 
1532             if (para
->GetRange().GetStart() > range
.GetEnd()) 
1535             if (!para
->GetRange().IsOutside(range
)) 
1537                 // We'll be using a copy of the paragraph to make style changes, 
1538                 // not updating the buffer directly. 
1539                 wxRichTextParagraph
* newPara 
wxDUMMY_INITIALIZE(NULL
); 
1541                 if (haveControl 
&& withUndo
) 
1543                     newPara 
= new wxRichTextParagraph(*para
); 
1544                     action
->GetNewParagraphs().AppendChild(newPara
); 
1546                     // Also store the old ones for Undo 
1547                     action
->GetOldParagraphs().AppendChild(new wxRichTextParagraph(*para
)); 
1553                     wxRichTextApplyStyle(newPara
->GetAttributes(), style
); 
1555                 if (characterStyle 
&& range
.GetStart() != newPara
->GetRange().GetEnd()) 
1557                     wxRichTextRange 
childRange(range
); 
1558                     childRange
.LimitTo(newPara
->GetRange()); 
1560                     // Find the starting position and if necessary split it so 
1561                     // we can start applying a different style. 
1562                     // TODO: check that the style actually changes or is different 
1563                     // from style outside of range 
1564                     wxRichTextObject
* firstObject 
wxDUMMY_INITIALIZE(NULL
); 
1565                     wxRichTextObject
* lastObject 
wxDUMMY_INITIALIZE(NULL
); 
1567                     if (childRange
.GetStart() == newPara
->GetRange().GetStart()) 
1568                         firstObject 
= newPara
->GetChildren().GetFirst()->GetData(); 
1570                         firstObject 
= newPara
->SplitAt(range
.GetStart()); 
1572                     // Increment by 1 because we're apply the style one _after_ the split point 
1573                     long splitPoint 
= childRange
.GetEnd(); 
1574                     if (splitPoint 
!= newPara
->GetRange().GetEnd()) 
1578                     if (splitPoint 
== newPara
->GetRange().GetEnd() || splitPoint 
== (newPara
->GetRange().GetEnd() - 1)) 
1579                         lastObject 
= newPara
->GetChildren().GetLast()->GetData(); 
1581                         // lastObject is set as a side-effect of splitting. It's 
1582                         // returned as the object before the new object. 
1583                         (void) newPara
->SplitAt(splitPoint
, & lastObject
); 
1585                     wxASSERT(firstObject 
!= NULL
); 
1586                     wxASSERT(lastObject 
!= NULL
); 
1588                     if (!firstObject 
|| !lastObject
) 
1591                     wxRichTextObjectList::compatibility_iterator firstNode 
= newPara
->GetChildren().Find(firstObject
); 
1592                     wxRichTextObjectList::compatibility_iterator lastNode 
= newPara
->GetChildren().Find(lastObject
); 
1594                     wxASSERT(firstNode
); 
1597                     wxRichTextObjectList::compatibility_iterator node2 
= firstNode
; 
1601                         wxRichTextObject
* child 
= node2
->GetData(); 
1603                         wxRichTextApplyStyle(child
->GetAttributes(), style
); 
1604                         if (node2 
== lastNode
) 
1607                         node2 
= node2
->GetNext(); 
1613         node 
= node
->GetNext(); 
1616     // Do action, or delay it until end of batch. 
1617     if (haveControl 
&& withUndo
) 
1618         GetRichTextCtrl()->GetBuffer().SubmitAction(action
); 
1623 /// Set text attributes 
1624 bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange
& range
, const wxTextAttrEx
& style
, bool withUndo
) 
1626     wxRichTextAttr richStyle 
= style
; 
1627     return SetStyle(range
, richStyle
, withUndo
); 
1630 /// Get the text attributes for this position. 
1631 bool wxRichTextParagraphLayoutBox::GetStyle(long position
, wxTextAttrEx
& style
) const 
1633     wxRichTextObject
* obj 
wxDUMMY_INITIALIZE(NULL
); 
1635     if (style
.IsParagraphStyle()) 
1636         obj 
= GetParagraphAtPosition(position
); 
1638         obj 
= GetLeafObjectAtPosition(position
); 
1642         style 
= obj
->GetAttributes(); 
1649 /// Get the text attributes for this position. 
1650 bool wxRichTextParagraphLayoutBox::GetStyle(long position
, wxRichTextAttr
& style
) const 
1652     wxRichTextObject
* obj 
wxDUMMY_INITIALIZE(NULL
); 
1654     if (style
.IsParagraphStyle()) 
1655         obj 
= GetParagraphAtPosition(position
); 
1657         obj 
= GetLeafObjectAtPosition(position
); 
1661         style 
= obj
->GetAttributes(); 
1668 /// Set default style 
1669 bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxTextAttrEx
& style
) 
1671     m_defaultAttributes 
= style
; 
1676 /// Test if this whole range has character attributes of the specified kind. If any 
1677 /// of the attributes are different within the range, the test fails. You 
1678 /// can use this to implement, for example, bold button updating. style must have 
1679 /// flags indicating which attributes are of interest. 
1680 bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) const 
1683     int matchingCount 
= 0; 
1685     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1688         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1689         wxASSERT (para 
!= NULL
); 
1693             // Stop searching if we're beyond the range of interest 
1694             if (para
->GetRange().GetStart() > range
.GetEnd()) 
1695                 return foundCount 
== matchingCount
; 
1697             if (!para
->GetRange().IsOutside(range
)) 
1699                 wxRichTextObjectList::compatibility_iterator node2 
= para
->GetChildren().GetFirst(); 
1703                     wxRichTextObject
* child 
= node2
->GetData(); 
1704                     if (!child
->GetRange().IsOutside(range
) && child
->IsKindOf(CLASSINFO(wxRichTextPlainText
))) 
1707                         if (wxTextAttrEqPartial(child
->GetAttributes(), style
, style
.GetFlags())) 
1711                     node2 
= node2
->GetNext(); 
1716         node 
= node
->GetNext(); 
1719     return foundCount 
== matchingCount
; 
1722 bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange
& range
, const wxTextAttrEx
& style
) const 
1724     wxRichTextAttr richStyle 
= style
; 
1725     return HasCharacterAttributes(range
, richStyle
); 
1728 /// Test if this whole range has paragraph attributes of the specified kind. If any 
1729 /// of the attributes are different within the range, the test fails. You 
1730 /// can use this to implement, for example, centering button updating. style must have 
1731 /// flags indicating which attributes are of interest. 
1732 bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) const 
1735     int matchingCount 
= 0; 
1737     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1740         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1741         wxASSERT (para 
!= NULL
); 
1745             // Stop searching if we're beyond the range of interest 
1746             if (para
->GetRange().GetStart() > range
.GetEnd()) 
1747                 return foundCount 
== matchingCount
; 
1749             if (!para
->GetRange().IsOutside(range
)) 
1752                 if (wxTextAttrEqPartial(para
->GetAttributes(), style
, style
.GetFlags())) 
1757         node 
= node
->GetNext(); 
1759     return foundCount 
== matchingCount
; 
1762 bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange
& range
, const wxTextAttrEx
& style
) const 
1764     wxRichTextAttr richStyle 
= style
; 
1765     return HasParagraphAttributes(range
, richStyle
); 
1768 void wxRichTextParagraphLayoutBox::Clear() 
1773 void wxRichTextParagraphLayoutBox::Reset() 
1777     AddParagraph(wxEmptyString
); 
1780 /// Invalidate the buffer. With no argument, invalidates whole buffer. 
1781 void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange
& invalidRange
) 
1785     if (invalidRange 
== wxRICHTEXT_ALL
) 
1787         m_invalidRange 
= wxRICHTEXT_ALL
; 
1791     // Already invalidating everything 
1792     if (m_invalidRange 
== wxRICHTEXT_ALL
) 
1795     if ((invalidRange
.GetStart() < m_invalidRange
.GetStart()) || m_invalidRange
.GetStart() == -1) 
1796         m_invalidRange
.SetStart(invalidRange
.GetStart()); 
1797     if (invalidRange
.GetEnd() > m_invalidRange
.GetEnd()) 
1798         m_invalidRange
.SetEnd(invalidRange
.GetEnd()); 
1801 /// Get invalid range, rounding to entire paragraphs if argument is true. 
1802 wxRichTextRange 
wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagraphs
) const 
1804     if (m_invalidRange 
== wxRICHTEXT_ALL 
|| m_invalidRange 
== wxRICHTEXT_NONE
) 
1805         return m_invalidRange
; 
1807     wxRichTextRange range 
= m_invalidRange
; 
1809     if (wholeParagraphs
) 
1811         wxRichTextParagraph
* para1 
= GetParagraphAtPosition(range
.GetStart()); 
1812         wxRichTextParagraph
* para2 
= GetParagraphAtPosition(range
.GetEnd()); 
1814             range
.SetStart(para1
->GetRange().GetStart()); 
1816             range
.SetEnd(para2
->GetRange().GetEnd()); 
1822  * wxRichTextFragment class declaration 
1823  * This is a lind of paragraph layout box used for storing 
1824  * paragraphs for Undo/Redo, for example. 
1827 IMPLEMENT_DYNAMIC_CLASS(wxRichTextFragment
, wxRichTextParagraphLayoutBox
) 
1830 void wxRichTextFragment::Init() 
1832     m_partialParagraph 
= false; 
1836 void wxRichTextFragment::Copy(const wxRichTextFragment
& obj
) 
1838     wxRichTextParagraphLayoutBox::Copy(obj
); 
1840     m_partialParagraph 
= obj
.m_partialParagraph
; 
1844  * wxRichTextParagraph 
1845  * This object represents a single paragraph (or in a straight text editor, a line). 
1848 IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraph
, wxRichTextBox
) 
1850 wxRichTextParagraph::wxRichTextParagraph(wxRichTextObject
* parent
, wxTextAttrEx
* style
): 
1851     wxRichTextBox(parent
) 
1853     if (parent 
&& !style
) 
1854         SetAttributes(parent
->GetAttributes()); 
1856         SetAttributes(*style
); 
1859 wxRichTextParagraph::wxRichTextParagraph(const wxString
& text
, wxRichTextObject
* parent
, wxTextAttrEx
* style
): 
1860     wxRichTextBox(parent
) 
1862     if (parent 
&& !style
) 
1863         SetAttributes(parent
->GetAttributes()); 
1865         SetAttributes(*style
); 
1867     AppendChild(new wxRichTextPlainText(text
, this)); 
1870 wxRichTextParagraph::~wxRichTextParagraph() 
1876 bool wxRichTextParagraph::Draw(wxDC
& dc
, const wxRichTextRange
& WXUNUSED(range
), const wxRichTextRange
& selectionRange
, const wxRect
& WXUNUSED(rect
), int WXUNUSED(descent
), int style
) 
1878     // Draw the bullet, if any 
1879     if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE
) 
1881         if (GetAttributes().GetLeftSubIndent() != 0) 
1883             int spaceBeforePara 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetParagraphSpacingBefore()); 
1884             // int spaceAfterPara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingAfter()); 
1885             int leftIndent 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetLeftIndent()); 
1886             // int leftSubIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetLeftSubIndent()); 
1887             // int rightIndent = ConvertTenthsMMToPixels(dc, GetAttributes().GetRightIndent()); 
1889             if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP
) 
1895                 wxString bulletText 
= GetBulletText(); 
1896                 if (!bulletText
.empty()) 
1898                     if (GetAttributes().GetFont().Ok()) 
1899                         dc
.SetFont(GetAttributes().GetFont()); 
1901                     if (GetAttributes().GetTextColour().Ok()) 
1902                         dc
.SetTextForeground(GetAttributes().GetTextColour()); 
1904                     dc
.SetBackgroundMode(wxTRANSPARENT
); 
1906                     // Get line height from first line, if any 
1907                     wxRichTextLine
* line 
= m_cachedLines
.GetFirst() ? (wxRichTextLine
* ) m_cachedLines
.GetFirst()->GetData() : (wxRichTextLine
*) NULL
; 
1910                     int lineHeight 
wxDUMMY_INITIALIZE(0); 
1913                         lineHeight 
= line
->GetSize().y
; 
1914                         linePos 
= line
->GetPosition() + GetPosition(); 
1918                         lineHeight 
= dc
.GetCharHeight(); 
1919                         linePos 
= GetPosition(); 
1920                         linePos
.y 
+= spaceBeforePara
; 
1923                     int charHeight 
= dc
.GetCharHeight(); 
1925                     int x 
= GetPosition().x 
+ leftIndent
; 
1926                     int y 
= linePos
.y 
+ (lineHeight 
- charHeight
); 
1928                     dc
.DrawText(bulletText
, x
, y
); 
1934     // Draw the range for each line, one object at a time. 
1936     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
1939         wxRichTextLine
* line 
= node
->GetData(); 
1940         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
1942         int maxDescent 
= line
->GetDescent(); 
1944         // Lines are specified relative to the paragraph 
1946         wxPoint linePosition 
= line
->GetPosition() + GetPosition(); 
1947         wxPoint objectPosition 
= linePosition
; 
1949         // Loop through objects until we get to the one within range 
1950         wxRichTextObjectList::compatibility_iterator node2 
= m_children
.GetFirst(); 
1953             wxRichTextObject
* child 
= node2
->GetData(); 
1954             if (!child
->GetRange().IsOutside(lineRange
)) 
1956                 // Draw this part of the line at the correct position 
1957                 wxRichTextRange 
objectRange(child
->GetRange()); 
1958                 objectRange
.LimitTo(lineRange
); 
1962                 child
->GetRangeSize(objectRange
, objectSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
1964                 // Use the child object's width, but the whole line's height 
1965                 wxRect 
childRect(objectPosition
, wxSize(objectSize
.x
, line
->GetSize().y
)); 
1966                 child
->Draw(dc
, objectRange
, selectionRange
, childRect
, maxDescent
, style
); 
1968                 objectPosition
.x 
+= objectSize
.x
; 
1970             else if (child
->GetRange().GetStart() > lineRange
.GetEnd()) 
1971                 // Can break out of inner loop now since we've passed this line's range 
1974             node2 
= node2
->GetNext(); 
1977         node 
= node
->GetNext(); 
1983 /// Lay the item out 
1984 bool wxRichTextParagraph::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
1988     // Increase the size of the paragraph due to spacing 
1989     int spaceBeforePara 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetParagraphSpacingBefore()); 
1990     int spaceAfterPara 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetParagraphSpacingAfter()); 
1991     int leftIndent 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetLeftIndent()); 
1992     int leftSubIndent 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetLeftSubIndent()); 
1993     int rightIndent 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetRightIndent()); 
1995     int lineSpacing 
= 0; 
1997     // Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc. 
1998     if (GetAttributes().GetLineSpacing() > 10 && GetAttributes().GetFont().Ok()) 
2000         dc
.SetFont(GetAttributes().GetFont()); 
2001         lineSpacing 
= (ConvertTenthsMMToPixels(dc
, dc
.GetCharHeight()) * GetAttributes().GetLineSpacing())/10; 
2004     // Available space for text on each line differs. 
2005     int availableTextSpaceFirstLine 
= rect
.GetWidth() - leftIndent 
- rightIndent
; 
2007     // Bullets start the text at the same position as subsequent lines 
2008     if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE
) 
2009         availableTextSpaceFirstLine 
-= leftSubIndent
; 
2011     int availableTextSpaceSubsequentLines 
= rect
.GetWidth() - leftIndent 
- rightIndent 
- leftSubIndent
; 
2013     // Start position for each line relative to the paragraph 
2014     int startPositionFirstLine 
= leftIndent
; 
2015     int startPositionSubsequentLines 
= leftIndent 
+ leftSubIndent
; 
2017     // If we have a bullet in this paragraph, the start position for the first line's text 
2018     // is actually leftIndent + leftSubIndent. 
2019     if (GetAttributes().GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE
) 
2020         startPositionFirstLine 
= startPositionSubsequentLines
; 
2022     //bool restrictWidth = wxRichTextHasStyle(style, wxRICHTEXT_FIXED_WIDTH); 
2023     //bool restrictHeight = wxRichTextHasStyle(style, wxRICHTEXT_FIXED_HEIGHT); 
2025     long lastEndPos 
= GetRange().GetStart()-1; 
2026     long lastCompletedEndPos 
= lastEndPos
; 
2028     int currentWidth 
= 0; 
2029     SetPosition(rect
.GetPosition()); 
2031     wxPoint 
currentPosition(0, spaceBeforePara
); // We will calculate lines relative to paragraph 
2040     // We may need to go back to a previous child, in which case create the new line, 
2041     // find the child corresponding to the start position of the string, and 
2044     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2047         wxRichTextObject
* child 
= node
->GetData(); 
2049         // If this is e.g. a composite text box, it will need to be laid out itself. 
2050         // But if just a text fragment or image, for example, this will 
2051         // do nothing. NB: won't we need to set the position after layout? 
2052         // since for example if position is dependent on vertical line size, we 
2053         // can't tell the position until the size is determined. So possibly introduce 
2054         // another layout phase. 
2056         child
->Layout(dc
, rect
, style
); 
2058         // Available width depends on whether we're on the first or subsequent lines 
2059         int availableSpaceForText 
= (lineCount 
== 0 ? availableTextSpaceFirstLine 
: availableTextSpaceSubsequentLines
); 
2061         currentPosition
.x 
= (lineCount 
== 0 ? startPositionFirstLine 
: startPositionSubsequentLines
); 
2063         // We may only be looking at part of a child, if we searched back for wrapping 
2064         // and found a suitable point some way into the child. So get the size for the fragment 
2068         int childDescent 
= 0; 
2069         if (lastEndPos 
== child
->GetRange().GetStart() - 1) 
2071             childSize 
= child
->GetCachedSize(); 
2072             childDescent 
= child
->GetDescent(); 
2075             GetRangeSize(wxRichTextRange(lastEndPos
+1, child
->GetRange().GetEnd()), childSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
); 
2077         if (childSize
.x 
+ currentWidth 
> availableSpaceForText
) 
2079             long wrapPosition 
= 0; 
2081             // Find a place to wrap. This may walk back to previous children, 
2082             // for example if a word spans several objects. 
2083             if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos
+1, child
->GetRange().GetEnd()), dc
, availableSpaceForText
, wrapPosition
)) 
2085                 // If the function failed, just cut it off at the end of this child. 
2086                 wrapPosition 
= child
->GetRange().GetEnd(); 
2089             // FindWrapPosition can still return a value that will put us in an endless wrapping loop 
2090             if (wrapPosition 
<= lastCompletedEndPos
) 
2091                 wrapPosition 
= wxMax(lastCompletedEndPos
+1,child
->GetRange().GetEnd()); 
2093             // wxLogDebug(wxT("Split at %ld"), wrapPosition); 
2095             // Let's find the actual size of the current line now 
2097             wxRichTextRange 
actualRange(lastCompletedEndPos
+1, wrapPosition
); 
2098             GetRangeSize(actualRange
, actualSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
); 
2099             currentWidth 
= actualSize
.x
; 
2100             lineHeight 
= wxMax(lineHeight
, actualSize
.y
); 
2101             maxDescent 
= wxMax(childDescent
, maxDescent
); 
2104             wxRichTextLine
* line 
= AllocateLine(lineCount
); 
2106             // Set relative range so we won't have to change line ranges when paragraphs are moved 
2107             line
->SetRange(wxRichTextRange(actualRange
.GetStart() - GetRange().GetStart(), actualRange
.GetEnd() - GetRange().GetStart())); 
2108             line
->SetPosition(currentPosition
); 
2109             line
->SetSize(wxSize(currentWidth
, lineHeight
)); 
2110             line
->SetDescent(maxDescent
); 
2112             // Now move down a line. TODO: add margins, spacing 
2113             currentPosition
.y 
+= lineHeight
; 
2114             currentPosition
.y 
+= lineSpacing
; 
2117             maxWidth 
= wxMax(maxWidth
, currentWidth
); 
2121             // TODO: account for zero-length objects, such as fields 
2122             wxASSERT(wrapPosition 
> lastCompletedEndPos
); 
2124             lastEndPos 
= wrapPosition
; 
2125             lastCompletedEndPos 
= lastEndPos
; 
2129             // May need to set the node back to a previous one, due to searching back in wrapping 
2130             wxRichTextObject
* childAfterWrapPosition 
= FindObjectAtPosition(wrapPosition
+1); 
2131             if (childAfterWrapPosition
) 
2132                 node 
= m_children
.Find(childAfterWrapPosition
); 
2134                 node 
= node
->GetNext(); 
2138             // We still fit, so don't add a line, and keep going 
2139             currentWidth 
+= childSize
.x
; 
2140             lineHeight 
= wxMax(lineHeight
, childSize
.y
); 
2141             maxDescent 
= wxMax(childDescent
, maxDescent
); 
2143             maxWidth 
= wxMax(maxWidth
, currentWidth
); 
2144             lastEndPos 
= child
->GetRange().GetEnd(); 
2146             node 
= node
->GetNext(); 
2150     // Add the last line - it's the current pos -> last para pos 
2151     // Substract -1 because the last position is always the end-paragraph position. 
2152     if (lastCompletedEndPos 
<= GetRange().GetEnd()-1) 
2154         currentPosition
.x 
= (lineCount 
== 0 ? startPositionFirstLine 
: startPositionSubsequentLines
); 
2156         wxRichTextLine
* line 
= AllocateLine(lineCount
); 
2158         wxRichTextRange 
actualRange(lastCompletedEndPos
+1, GetRange().GetEnd()-1); 
2160         // Set relative range so we won't have to change line ranges when paragraphs are moved 
2161         line
->SetRange(wxRichTextRange(actualRange
.GetStart() - GetRange().GetStart(), actualRange
.GetEnd() - GetRange().GetStart())); 
2163         line
->SetPosition(currentPosition
); 
2165         if (lineHeight 
== 0) 
2167             if (GetAttributes().GetFont().Ok()) 
2168                 dc
.SetFont(GetAttributes().GetFont()); 
2169             lineHeight 
= dc
.GetCharHeight(); 
2171         if (maxDescent 
== 0) 
2174             dc
.GetTextExtent(wxT("X"), & w
, &h
, & maxDescent
); 
2177         line
->SetSize(wxSize(currentWidth
, lineHeight
)); 
2178         line
->SetDescent(maxDescent
); 
2179         currentPosition
.y 
+= lineHeight
; 
2180         currentPosition
.y 
+= lineSpacing
; 
2184     // Remove remaining unused line objects, if any 
2185     ClearUnusedLines(lineCount
); 
2187     // Apply styles to wrapped lines 
2188     ApplyParagraphStyle(rect
); 
2190     SetCachedSize(wxSize(maxWidth
, currentPosition
.y 
+ spaceBeforePara 
+ spaceAfterPara
)); 
2197 /// Apply paragraph styles, such as centering, to wrapped lines 
2198 void wxRichTextParagraph::ApplyParagraphStyle(const wxRect
& rect
) 
2200     if (!GetAttributes().HasAlignment()) 
2203     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
2206         wxRichTextLine
* line 
= node
->GetData(); 
2208         wxPoint pos 
= line
->GetPosition(); 
2209         wxSize size 
= line
->GetSize(); 
2211         // centering, right-justification 
2212         if (GetAttributes().HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
2214             pos
.x 
= (rect
.GetWidth() - size
.x
)/2 + pos
.x
; 
2215             line
->SetPosition(pos
); 
2217         else if (GetAttributes().HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
2219             pos
.x 
= rect
.GetRight() - size
.x
; 
2220             line
->SetPosition(pos
); 
2223         node 
= node
->GetNext(); 
2227 /// Insert text at the given position 
2228 bool wxRichTextParagraph::InsertText(long pos
, const wxString
& text
) 
2230     wxRichTextObject
* childToUse 
= NULL
; 
2231     wxRichTextObjectList::compatibility_iterator nodeToUse 
= wxRichTextObjectList::compatibility_iterator(); 
2233     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2236         wxRichTextObject
* child 
= node
->GetData(); 
2237         if (child
->GetRange().Contains(pos
) && child
->GetRange().GetLength() > 0) 
2244         node 
= node
->GetNext(); 
2249         wxRichTextPlainText
* textObject 
= wxDynamicCast(childToUse
, wxRichTextPlainText
); 
2252             int posInString 
= pos 
- textObject
->GetRange().GetStart(); 
2254             wxString newText 
= textObject
->GetText().Mid(0, posInString
) + 
2255                                text 
+ textObject
->GetText().Mid(posInString
); 
2256             textObject
->SetText(newText
); 
2258             int textLength 
= text
.Length(); 
2260             textObject
->SetRange(wxRichTextRange(textObject
->GetRange().GetStart(), 
2261                                                  textObject
->GetRange().GetEnd() + textLength
)); 
2263             // Increment the end range of subsequent fragments in this paragraph. 
2264             // We'll set the paragraph range itself at a higher level. 
2266             wxRichTextObjectList::compatibility_iterator node 
= nodeToUse
->GetNext(); 
2269                 wxRichTextObject
* child 
= node
->GetData(); 
2270                 child
->SetRange(wxRichTextRange(textObject
->GetRange().GetStart() + textLength
, 
2271                                                  textObject
->GetRange().GetEnd() + textLength
)); 
2273                 node 
= node
->GetNext(); 
2280             // TODO: if not a text object, insert at closest position, e.g. in front of it 
2286         // Don't pass parent initially to suppress auto-setting of parent range. 
2287         // We'll do that at a higher level. 
2288         wxRichTextPlainText
* textObject 
= new wxRichTextPlainText(text
, this); 
2290         AppendChild(textObject
); 
2297 void wxRichTextParagraph::Copy(const wxRichTextParagraph
& obj
) 
2299     wxRichTextBox::Copy(obj
); 
2302 /// Clear the cached lines 
2303 void wxRichTextParagraph::ClearLines() 
2305     WX_CLEAR_LIST(wxRichTextLineList
, m_cachedLines
); 
2308 /// Get/set the object size for the given range. Returns false if the range 
2309 /// is invalid for this object. 
2310 bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
) const 
2312     if (!range
.IsWithin(GetRange())) 
2315     if (flags 
& wxRICHTEXT_UNFORMATTED
) 
2317         // Just use unformatted data, assume no line breaks 
2318         // TODO: take into account line breaks 
2322         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2325             wxRichTextObject
* child 
= node
->GetData(); 
2326             if (!child
->GetRange().IsOutside(range
)) 
2330                 wxRichTextRange rangeToUse 
= range
; 
2331                 rangeToUse
.LimitTo(child
->GetRange()); 
2332                 int childDescent 
= 0; 
2334                 if (child
->GetRangeSize(rangeToUse
, childSize
, childDescent
, dc
, flags
)) 
2336                     sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
2337                     sz
.x 
+= childSize
.x
; 
2338                     descent 
= wxMax(descent
, childDescent
); 
2342             node 
= node
->GetNext(); 
2348         // Use formatted data, with line breaks 
2351         // We're going to loop through each line, and then for each line, 
2352         // call GetRangeSize for the fragment that comprises that line. 
2353         // Only we have to do that multiple times within the line, because 
2354         // the line may be broken into pieces. For now ignore line break commands 
2355         // (so we can assume that getting the unformatted size for a fragment 
2356         // within a line is the actual size) 
2358         wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
2361             wxRichTextLine
* line 
= node
->GetData(); 
2362             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2363             if (!lineRange
.IsOutside(range
)) 
2367                 wxRichTextObjectList::compatibility_iterator node2 
= m_children
.GetFirst(); 
2370                     wxRichTextObject
* child 
= node2
->GetData(); 
2372                     if (!child
->GetRange().IsOutside(lineRange
)) 
2374                         wxRichTextRange rangeToUse 
= lineRange
; 
2375                         rangeToUse
.LimitTo(child
->GetRange()); 
2378                         int childDescent 
= 0; 
2379                         if (child
->GetRangeSize(rangeToUse
, childSize
, childDescent
, dc
, flags
)) 
2381                             lineSize
.y 
= wxMax(lineSize
.y
, childSize
.y
); 
2382                             lineSize
.x 
+= childSize
.x
; 
2384                         descent 
= wxMax(descent
, childDescent
); 
2387                     node2 
= node2
->GetNext(); 
2390                 // Increase size by a line (TODO: paragraph spacing) 
2392                 sz
.x 
= wxMax(sz
.x
, lineSize
.x
); 
2394             node 
= node
->GetNext(); 
2401 /// Finds the absolute position and row height for the given character position 
2402 bool wxRichTextParagraph::FindPosition(wxDC
& dc
, long index
, wxPoint
& pt
, int* height
, bool forceLineStart
) 
2406         wxRichTextLine
* line 
= ((wxRichTextParagraphLayoutBox
*)GetParent())->GetLineAtPosition(0); 
2408             *height 
= line
->GetSize().y
; 
2410             *height 
= dc
.GetCharHeight(); 
2412         // -1 means 'the start of the buffer'. 
2415             pt 
= pt 
+ line
->GetPosition(); 
2417         *height 
= dc
.GetCharHeight(); 
2422     // The final position in a paragraph is taken to mean the position 
2423     // at the start of the next paragraph. 
2424     if (index 
== GetRange().GetEnd()) 
2426         wxRichTextParagraphLayoutBox
* parent 
= wxDynamicCast(GetParent(), wxRichTextParagraphLayoutBox
); 
2427         wxASSERT( parent 
!= NULL 
); 
2429         // Find the height at the next paragraph, if any 
2430         wxRichTextLine
* line 
= parent
->GetLineAtPosition(index 
+ 1); 
2433             *height 
= line
->GetSize().y
; 
2434             pt 
= line
->GetAbsolutePosition(); 
2438             *height 
= dc
.GetCharHeight(); 
2439             int indent 
= ConvertTenthsMMToPixels(dc
, m_attributes
.GetLeftIndent()); 
2440             pt 
= wxPoint(indent
, GetCachedSize().y
); 
2446     if (index 
< GetRange().GetStart() || index 
> GetRange().GetEnd()) 
2449     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
2452         wxRichTextLine
* line 
= node
->GetData(); 
2453         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2454         if (index 
>= lineRange
.GetStart() && index 
<= lineRange
.GetEnd()) 
2456             // If this is the last point in the line, and we're forcing the 
2457             // returned value to be the start of the next line, do the required 
2459             if (index 
== lineRange
.GetEnd() && forceLineStart
) 
2461                 if (node
->GetNext()) 
2463                     wxRichTextLine
* nextLine 
= node
->GetNext()->GetData(); 
2464                     *height 
= nextLine
->GetSize().y
; 
2465                     pt 
= nextLine
->GetAbsolutePosition(); 
2470             pt
.y 
= line
->GetPosition().y 
+ GetPosition().y
; 
2472             wxRichTextRange 
r(lineRange
.GetStart(), index
); 
2476             // We find the size of the line up to this point, 
2477             // then we can add this size to the line start position and 
2478             // paragraph start position to find the actual position. 
2480             if (GetRangeSize(r
, rangeSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
)) 
2482                 pt
.x 
= line
->GetPosition().x 
+ GetPosition().x 
+ rangeSize
.x
; 
2483                 *height 
= line
->GetSize().y
; 
2490         node 
= node
->GetNext(); 
2496 /// Hit-testing: returns a flag indicating hit test details, plus 
2497 /// information about position 
2498 int wxRichTextParagraph::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
) 
2500     wxPoint paraPos 
= GetPosition(); 
2502     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
2505         wxRichTextLine
* line 
= node
->GetData(); 
2506         wxPoint linePos 
= paraPos 
+ line
->GetPosition(); 
2507         wxSize lineSize 
= line
->GetSize(); 
2508         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2510         if (pt
.y 
>= linePos
.y 
&& pt
.y 
<= linePos
.y 
+ lineSize
.y
) 
2512             if (pt
.x 
< linePos
.x
) 
2514                 textPosition 
= lineRange
.GetStart(); 
2515                 return wxRICHTEXT_HITTEST_BEFORE
; 
2517             else if (pt
.x 
>= (linePos
.x 
+ lineSize
.x
)) 
2519                 textPosition 
= lineRange
.GetEnd(); 
2520                 return wxRICHTEXT_HITTEST_AFTER
; 
2525                 int lastX 
= linePos
.x
; 
2526                 for (i 
= lineRange
.GetStart(); i 
<= lineRange
.GetEnd(); i
++) 
2531                     wxRichTextRange 
rangeToUse(lineRange
.GetStart(), i
); 
2533                     GetRangeSize(rangeToUse
, childSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
2535                     int nextX 
= childSize
.x 
+ linePos
.x
; 
2537                     if (pt
.x 
>= lastX 
&& pt
.x 
<= nextX
) 
2541                         // So now we know it's between i-1 and i. 
2542                         // Let's see if we can be more precise about 
2543                         // which side of the position it's on. 
2545                         int midPoint 
= (nextX 
- lastX
)/2 + lastX
; 
2546                         if (pt
.x 
>= midPoint
) 
2547                             return wxRICHTEXT_HITTEST_AFTER
; 
2549                             return wxRICHTEXT_HITTEST_BEFORE
; 
2559         node 
= node
->GetNext(); 
2562     return wxRICHTEXT_HITTEST_NONE
; 
2565 /// Split an object at this position if necessary, and return 
2566 /// the previous object, or NULL if inserting at beginning. 
2567 wxRichTextObject
* wxRichTextParagraph::SplitAt(long pos
, wxRichTextObject
** previousObject
) 
2569     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2572         wxRichTextObject
* child 
= node
->GetData(); 
2574         if (pos 
== child
->GetRange().GetStart()) 
2578                 if (node
->GetPrevious()) 
2579                     *previousObject 
= node
->GetPrevious()->GetData(); 
2581                     *previousObject 
= NULL
; 
2587         if (child
->GetRange().Contains(pos
)) 
2589             // This should create a new object, transferring part of 
2590             // the content to the old object and the rest to the new object. 
2591             wxRichTextObject
* newObject 
= child
->DoSplit(pos
); 
2593             // If we couldn't split this object, just insert in front of it. 
2596                 // Maybe this is an empty string, try the next one 
2601                 // Insert the new object after 'child' 
2602                 if (node
->GetNext()) 
2603                     m_children
.Insert(node
->GetNext(), newObject
); 
2605                     m_children
.Append(newObject
); 
2606                 newObject
->SetParent(this); 
2609                     *previousObject 
= child
; 
2615         node 
= node
->GetNext(); 
2618         *previousObject 
= NULL
; 
2622 /// Move content to a list from obj on 
2623 void wxRichTextParagraph::MoveToList(wxRichTextObject
* obj
, wxList
& list
) 
2625     wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(obj
); 
2628         wxRichTextObject
* child 
= node
->GetData(); 
2631         wxRichTextObjectList::compatibility_iterator oldNode 
= node
; 
2633         node 
= node
->GetNext(); 
2635         m_children
.DeleteNode(oldNode
); 
2639 /// Add content back from list 
2640 void wxRichTextParagraph::MoveFromList(wxList
& list
) 
2642     for (wxList::compatibility_iterator node 
= list
.GetFirst(); node
; node 
= node
->GetNext()) 
2644         AppendChild((wxRichTextObject
*) node
->GetData()); 
2649 void wxRichTextParagraph::CalculateRange(long start
, long& end
) 
2651     wxRichTextCompositeObject::CalculateRange(start
, end
); 
2653     // Add one for end of paragraph 
2656     m_range
.SetRange(start
, end
); 
2659 /// Find the object at the given position 
2660 wxRichTextObject
* wxRichTextParagraph::FindObjectAtPosition(long position
) 
2662     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2665         wxRichTextObject
* obj 
= node
->GetData(); 
2666         if (obj
->GetRange().Contains(position
)) 
2669         node 
= node
->GetNext(); 
2674 /// Get the plain text searching from the start or end of the range. 
2675 /// The resulting string may be shorter than the range given. 
2676 bool wxRichTextParagraph::GetContiguousPlainText(wxString
& text
, const wxRichTextRange
& range
, bool fromStart
) 
2678     text 
= wxEmptyString
; 
2682         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2685             wxRichTextObject
* obj 
= node
->GetData(); 
2686             if (!obj
->GetRange().IsOutside(range
)) 
2688                 wxRichTextPlainText
* textObj 
= wxDynamicCast(obj
, wxRichTextPlainText
); 
2691                     text 
+= textObj
->GetTextForRange(range
); 
2697             node 
= node
->GetNext(); 
2702         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetLast(); 
2705             wxRichTextObject
* obj 
= node
->GetData(); 
2706             if (!obj
->GetRange().IsOutside(range
)) 
2708                 wxRichTextPlainText
* textObj 
= wxDynamicCast(obj
, wxRichTextPlainText
); 
2711                     text 
= textObj
->GetTextForRange(range
) + text
; 
2717             node 
= node
->GetPrevious(); 
2724 /// Find a suitable wrap position. 
2725 bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange
& range
, wxDC
& dc
, int availableSpace
, long& wrapPosition
) 
2727     // Find the first position where the line exceeds the available space. 
2730     long breakPosition 
= range
.GetEnd(); 
2731     for (i 
= range
.GetStart(); i 
<= range
.GetEnd(); i
++) 
2734         GetRangeSize(wxRichTextRange(range
.GetStart(), i
), sz
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
2736         if (sz
.x 
> availableSpace
) 
2738             breakPosition 
= i
-1; 
2743     // Now we know the last position on the line. 
2744     // Let's try to find a word break. 
2747     if (GetContiguousPlainText(plainText
, wxRichTextRange(range
.GetStart(), breakPosition
), false)) 
2749         int spacePos 
= plainText
.Find(wxT(' '), true); 
2750         if (spacePos 
!= wxNOT_FOUND
) 
2752             int positionsFromEndOfString 
= plainText
.Length() - spacePos 
- 1; 
2753             breakPosition 
= breakPosition 
- positionsFromEndOfString
; 
2757     wrapPosition 
= breakPosition
; 
2762 /// Get the bullet text for this paragraph. 
2763 wxString 
wxRichTextParagraph::GetBulletText() 
2765     if (GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE 
|| 
2766         (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP
)) 
2767         return wxEmptyString
; 
2769     int number 
= GetAttributes().GetBulletNumber(); 
2772     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ARABIC
) 
2774         text
.Printf(wxT("%d"), number
); 
2776     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER
) 
2778         // TODO: Unicode, and also check if number > 26 
2779         text
.Printf(wxT("%c"), (wxChar
) (number
+64)); 
2781     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER
) 
2783         // TODO: Unicode, and also check if number > 26 
2784         text
.Printf(wxT("%c"), (wxChar
) (number
+96)); 
2786     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER
) 
2788         // TODO: convert from number to roman numeral 
2791         else if (number 
== 2) 
2793         else if (number 
== 3) 
2795         else if (number 
== 4) 
2800     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER
) 
2802         // TODO: convert from number to roman numeral 
2805         else if (number 
== 2) 
2807         else if (number 
== 3) 
2809         else if (number 
== 4) 
2814     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
) 
2816         text 
= GetAttributes().GetBulletSymbol(); 
2819     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_PARENTHESES
) 
2821         text 
= wxT("(") + text 
+ wxT(")"); 
2823     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_PERIOD
) 
2831 /// Allocate or reuse a line object 
2832 wxRichTextLine
* wxRichTextParagraph::AllocateLine(int pos
) 
2834     if (pos 
< (int) m_cachedLines
.GetCount()) 
2836         wxRichTextLine
* line 
= m_cachedLines
.Item(pos
)->GetData(); 
2842         wxRichTextLine
* line 
= new wxRichTextLine(this); 
2843         m_cachedLines
.Append(line
); 
2848 /// Clear remaining unused line objects, if any 
2849 bool wxRichTextParagraph::ClearUnusedLines(int lineCount
) 
2851     int cachedLineCount 
= m_cachedLines
.GetCount(); 
2852     if ((int) cachedLineCount 
> lineCount
) 
2854         for (int i 
= 0; i 
< (int) (cachedLineCount 
- lineCount
); i 
++) 
2856             wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetLast(); 
2857             wxRichTextLine
* line 
= node
->GetData(); 
2858             m_cachedLines
.Erase(node
); 
2868  * This object represents a line in a paragraph, and stores 
2869  * offsets from the start of the paragraph representing the 
2870  * start and end positions of the line. 
2873 wxRichTextLine::wxRichTextLine(wxRichTextParagraph
* parent
) 
2879 void wxRichTextLine::Init(wxRichTextParagraph
* parent
) 
2882     m_range
.SetRange(-1, -1); 
2883     m_pos 
= wxPoint(0, 0); 
2884     m_size 
= wxSize(0, 0); 
2889 void wxRichTextLine::Copy(const wxRichTextLine
& obj
) 
2891     m_range 
= obj
.m_range
; 
2894 /// Get the absolute object position 
2895 wxPoint 
wxRichTextLine::GetAbsolutePosition() const 
2897     return m_parent
->GetPosition() + m_pos
; 
2900 /// Get the absolute range 
2901 wxRichTextRange 
wxRichTextLine::GetAbsoluteRange() const 
2903     wxRichTextRange 
range(m_range
.GetStart() + m_parent
->GetRange().GetStart(), 0); 
2904     range
.SetEnd(range
.GetStart() + m_range
.GetLength()-1); 
2909  * wxRichTextPlainText 
2910  * This object represents a single piece of text. 
2913 IMPLEMENT_DYNAMIC_CLASS(wxRichTextPlainText
, wxRichTextObject
) 
2915 wxRichTextPlainText::wxRichTextPlainText(const wxString
& text
, wxRichTextObject
* parent
, wxTextAttrEx
* style
): 
2916     wxRichTextObject(parent
) 
2918     if (parent 
&& !style
) 
2919         SetAttributes(parent
->GetAttributes()); 
2921         SetAttributes(*style
); 
2927 bool wxRichTextPlainText::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextRange
& selectionRange
, const wxRect
& rect
, int descent
, int WXUNUSED(style
)) 
2929     int offset 
= GetRange().GetStart(); 
2931     long len 
= range
.GetLength(); 
2932     wxString stringChunk 
= m_text
.Mid(range
.GetStart() - offset
, (size_t) len
); 
2934     int charHeight 
= dc
.GetCharHeight(); 
2937     int y 
= rect
.y 
+ (rect
.height 
- charHeight 
- (descent 
- m_descent
)); 
2939     // Test for the optimized situations where all is selected, or none 
2942     if (GetAttributes().GetFont().Ok()) 
2943         dc
.SetFont(GetAttributes().GetFont()); 
2945     // (a) All selected. 
2946     if (selectionRange
.GetStart() <= range
.GetStart() && selectionRange
.GetEnd() >= range
.GetEnd()) 
2948         // Draw all selected 
2949         dc
.SetBrush(*wxBLACK_BRUSH
); 
2950         dc
.SetPen(*wxBLACK_PEN
); 
2952         dc
.GetTextExtent(stringChunk
, & w
, & h
); 
2953         wxRect 
selRect(x
, rect
.y
, w
, rect
.GetHeight()); 
2954         dc
.DrawRectangle(selRect
); 
2955         dc
.SetTextForeground(*wxWHITE
); 
2956         dc
.SetBackgroundMode(wxTRANSPARENT
); 
2957         dc
.DrawText(stringChunk
, x
, y
); 
2959     // (b) None selected. 
2960     else if (selectionRange
.GetEnd() < range
.GetStart() || selectionRange
.GetStart() > range
.GetEnd()) 
2962         // Draw all unselected 
2963         dc
.SetTextForeground(GetAttributes().GetTextColour()); 
2964         dc
.SetBackgroundMode(wxTRANSPARENT
); 
2965         dc
.DrawText(stringChunk
, x
, y
); 
2969         // (c) Part selected, part not 
2970         // Let's draw unselected chunk, selected chunk, then unselected chunk. 
2972         dc
.SetBackgroundMode(wxTRANSPARENT
); 
2974         // 1. Initial unselected chunk, if any, up until start of selection. 
2975         if (selectionRange
.GetStart() > range
.GetStart() && selectionRange
.GetStart() <= range
.GetEnd()) 
2977             int r1 
= range
.GetStart(); 
2978             int s1 
= selectionRange
.GetStart()-1; 
2979             int fragmentLen 
= s1 
- r1 
+ 1; 
2980             if (fragmentLen 
< 0) 
2981                 wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 
- offset
), (int)fragmentLen
); 
2982             wxString stringFragment 
= m_text
.Mid(r1 
- offset
, fragmentLen
); 
2984             dc
.SetTextForeground(GetAttributes().GetTextColour()); 
2985             dc
.DrawText(stringFragment
, x
, y
); 
2988             dc
.GetTextExtent(stringFragment
, & w
, & h
); 
2992         // 2. Selected chunk, if any. 
2993         if (selectionRange
.GetEnd() >= range
.GetStart()) 
2995             int s1 
= wxMax(selectionRange
.GetStart(), range
.GetStart()); 
2996             int s2 
= wxMin(selectionRange
.GetEnd(), range
.GetEnd()); 
2998             int fragmentLen 
= s2 
- s1 
+ 1; 
2999             if (fragmentLen 
< 0) 
3000                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 
- offset
), (int)fragmentLen
); 
3001             wxString stringFragment 
= m_text
.Mid(s1 
- offset
, fragmentLen
); 
3004             dc
.GetTextExtent(stringFragment
, & w
, & h
); 
3005             wxRect 
selRect(x
, rect
.y
, w
, rect
.GetHeight()); 
3007             dc
.SetBrush(*wxBLACK_BRUSH
); 
3008             dc
.SetPen(*wxBLACK_PEN
); 
3009             dc
.DrawRectangle(selRect
); 
3010             dc
.SetTextForeground(*wxWHITE
); 
3011             dc
.DrawText(stringFragment
, x
, y
); 
3016         // 3. Remaining unselected chunk, if any 
3017         if (selectionRange
.GetEnd() < range
.GetEnd()) 
3019             int s2 
= wxMin(selectionRange
.GetEnd()+1, range
.GetEnd()); 
3020             int r2 
= range
.GetEnd(); 
3022             int fragmentLen 
= r2 
- s2 
+ 1; 
3023             if (fragmentLen 
< 0) 
3024                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 
- offset
), (int)fragmentLen
); 
3025             wxString stringFragment 
= m_text
.Mid(s2 
- offset
, fragmentLen
); 
3027             dc
.SetTextForeground(GetAttributes().GetTextColour()); 
3028             dc
.DrawText(stringFragment
, x
, y
); 
3035 /// Lay the item out 
3036 bool wxRichTextPlainText::Layout(wxDC
& dc
, const wxRect
& WXUNUSED(rect
), int WXUNUSED(style
)) 
3038     if (GetAttributes().GetFont().Ok()) 
3039         dc
.SetFont(GetAttributes().GetFont()); 
3042     dc
.GetTextExtent(m_text
, & w
, & h
, & m_descent
); 
3043     m_size 
= wxSize(w
, dc
.GetCharHeight()); 
3049 void wxRichTextPlainText::Copy(const wxRichTextPlainText
& obj
) 
3051     wxRichTextObject::Copy(obj
); 
3053     m_text 
= obj
.m_text
; 
3056 /// Get/set the object size for the given range. Returns false if the range 
3057 /// is invalid for this object. 
3058 bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int WXUNUSED(flags
)) const 
3060     if (!range
.IsWithin(GetRange())) 
3063     // Always assume unformatted text, since at this level we have no knowledge 
3064     // of line breaks - and we don't need it, since we'll calculate size within 
3065     // formatted text by doing it in chunks according to the line ranges 
3067     if (GetAttributes().GetFont().Ok()) 
3068         dc
.SetFont(GetAttributes().GetFont()); 
3070     int startPos 
= range
.GetStart() - GetRange().GetStart(); 
3071     long len 
= range
.GetLength(); 
3072     wxString stringChunk 
= m_text
.Mid(startPos
, (size_t) len
); 
3074     dc
.GetTextExtent(stringChunk
, & w
, & h
, & descent
); 
3075     size 
= wxSize(w
, dc
.GetCharHeight()); 
3080 /// Do a split, returning an object containing the second part, and setting 
3081 /// the first part in 'this'. 
3082 wxRichTextObject
* wxRichTextPlainText::DoSplit(long pos
) 
3084     int index 
= pos 
- GetRange().GetStart(); 
3085     if (index 
< 0 || index 
>= (int) m_text
.Length()) 
3088     wxString firstPart 
= m_text
.Mid(0, index
); 
3089     wxString secondPart 
= m_text
.Mid(index
); 
3093     wxRichTextPlainText
* newObject 
= new wxRichTextPlainText(secondPart
); 
3094     newObject
->SetAttributes(GetAttributes()); 
3096     newObject
->SetRange(wxRichTextRange(pos
, GetRange().GetEnd())); 
3097     GetRange().SetEnd(pos
-1); 
3103 void wxRichTextPlainText::CalculateRange(long start
, long& end
) 
3105     end 
= start 
+ m_text
.Length() - 1; 
3106     m_range
.SetRange(start
, end
); 
3110 bool wxRichTextPlainText::DeleteRange(const wxRichTextRange
& range
) 
3112     wxRichTextRange r 
= range
; 
3114     r
.LimitTo(GetRange()); 
3116     if (r
.GetStart() == GetRange().GetStart() && r
.GetEnd() == GetRange().GetEnd()) 
3122     long startIndex 
= r
.GetStart() - GetRange().GetStart(); 
3123     long len 
= r
.GetLength(); 
3125     m_text 
= m_text
.Mid(0, startIndex
) + m_text
.Mid(startIndex
+len
); 
3129 /// Get text for the given range. 
3130 wxString 
wxRichTextPlainText::GetTextForRange(const wxRichTextRange
& range
) const 
3132     wxRichTextRange r 
= range
; 
3134     r
.LimitTo(GetRange()); 
3136     long startIndex 
= r
.GetStart() - GetRange().GetStart(); 
3137     long len 
= r
.GetLength(); 
3139     return m_text
.Mid(startIndex
, len
); 
3142 /// Returns true if this object can merge itself with the given one. 
3143 bool wxRichTextPlainText::CanMerge(wxRichTextObject
* object
) const 
3145     return object
->GetClassInfo() == CLASSINFO(wxRichTextPlainText
) && 
3146         (m_text
.empty() || wxTextAttrEq(GetAttributes(), object
->GetAttributes())); 
3149 /// Returns true if this object merged itself with the given one. 
3150 /// The calling code will then delete the given object. 
3151 bool wxRichTextPlainText::Merge(wxRichTextObject
* object
) 
3153     wxRichTextPlainText
* textObject 
= wxDynamicCast(object
, wxRichTextPlainText
); 
3154     wxASSERT( textObject 
!= NULL 
); 
3158         m_text 
+= textObject
->GetText(); 
3165 /// Dump to output stream for debugging 
3166 void wxRichTextPlainText::Dump(wxTextOutputStream
& stream
) 
3168     wxRichTextObject::Dump(stream
); 
3169     stream 
<< m_text 
<< wxT("\n"); 
3174  * This is a kind of box, used to represent the whole buffer 
3177 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer
, wxRichTextParagraphLayoutBox
) 
3179 wxList 
wxRichTextBuffer::sm_handlers
; 
3182 void wxRichTextBuffer::Init() 
3184     m_commandProcessor 
= new wxCommandProcessor
; 
3185     m_styleSheet 
= NULL
; 
3187     m_batchedCommandDepth 
= 0; 
3188     m_batchedCommand 
= NULL
; 
3193 wxRichTextBuffer::~wxRichTextBuffer() 
3195     delete m_commandProcessor
; 
3196     delete m_batchedCommand
; 
3201 void wxRichTextBuffer::Clear() 
3204     GetCommandProcessor()->ClearCommands(); 
3206     Invalidate(wxRICHTEXT_ALL
); 
3209 void wxRichTextBuffer::Reset() 
3212     AddParagraph(wxEmptyString
); 
3213     GetCommandProcessor()->ClearCommands(); 
3215     Invalidate(wxRICHTEXT_ALL
); 
3218 /// Submit command to insert the given text 
3219 bool wxRichTextBuffer::InsertTextWithUndo(long pos
, const wxString
& text
, wxRichTextCtrl
* ctrl
) 
3221     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Text"), wxRICHTEXT_INSERT
, this, ctrl
, false); 
3223     action
->GetNewParagraphs().AddParagraphs(text
); 
3224     if (action
->GetNewParagraphs().GetChildCount() == 1) 
3225         action
->GetNewParagraphs().SetPartialParagraph(true); 
3227     action
->SetPosition(pos
); 
3229     // Set the range we'll need to delete in Undo 
3230     action
->SetRange(wxRichTextRange(pos
, pos 
+ text
.Length() - 1)); 
3232     SubmitAction(action
); 
3237 /// Submit command to insert the given text 
3238 bool wxRichTextBuffer::InsertNewlineWithUndo(long pos
, wxRichTextCtrl
* ctrl
) 
3240     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Text"), wxRICHTEXT_INSERT
, this, ctrl
, false); 
3242     wxTextAttrEx 
attr(GetBasicStyle()); 
3243     wxRichTextApplyStyle(attr
, GetDefaultStyle()); 
3245     wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(wxEmptyString
, this, & attr
); 
3246     action
->GetNewParagraphs().AppendChild(newPara
); 
3247     action
->GetNewParagraphs().UpdateRanges(); 
3248     action
->GetNewParagraphs().SetPartialParagraph(false); 
3249     action
->SetPosition(pos
); 
3251     // Set the range we'll need to delete in Undo 
3252     action
->SetRange(wxRichTextRange(pos
, pos
)); 
3254     SubmitAction(action
); 
3259 /// Submit command to insert the given image 
3260 bool wxRichTextBuffer::InsertImageWithUndo(long pos
, const wxRichTextImageBlock
& imageBlock
, wxRichTextCtrl
* ctrl
) 
3262     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Image"), wxRICHTEXT_INSERT
, this, ctrl
, false); 
3264     wxTextAttrEx 
attr(GetBasicStyle()); 
3265     wxRichTextApplyStyle(attr
, GetDefaultStyle()); 
3267     wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(this, & attr
); 
3268     wxRichTextImage
* imageObject 
= new wxRichTextImage(imageBlock
, newPara
); 
3269     newPara
->AppendChild(imageObject
); 
3270     action
->GetNewParagraphs().AppendChild(newPara
); 
3271     action
->GetNewParagraphs().UpdateRanges(); 
3273     action
->GetNewParagraphs().SetPartialParagraph(true); 
3275     action
->SetPosition(pos
); 
3277     // Set the range we'll need to delete in Undo 
3278     action
->SetRange(wxRichTextRange(pos
, pos
)); 
3280     SubmitAction(action
); 
3285 /// Submit command to delete this range 
3286 bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange
& range
, long initialCaretPosition
, long WXUNUSED(newCaretPositon
), wxRichTextCtrl
* ctrl
) 
3288     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Delete"), wxRICHTEXT_DELETE
, this, ctrl
); 
3290     action
->SetPosition(initialCaretPosition
); 
3292     // Set the range to delete 
3293     action
->SetRange(range
); 
3295     // Copy the fragment that we'll need to restore in Undo 
3296     CopyFragment(range
, action
->GetOldParagraphs()); 
3298     // Special case: if there is only one (non-partial) paragraph, 
3299     // we must save the *next* paragraph's style, because that 
3300     // is the style we must apply when inserting the content back 
3301     // when undoing the delete. (This is because we're merging the 
3302     // paragraph with the previous paragraph and throwing away 
3303     // the style, and we need to restore it.) 
3304     if (!action
->GetOldParagraphs().GetPartialParagraph() && action
->GetOldParagraphs().GetChildCount() == 1) 
3306         wxRichTextParagraph
* lastPara 
= GetParagraphAtPosition(range
.GetStart()); 
3309             wxRichTextParagraph
* nextPara 
= GetParagraphAtPosition(range
.GetEnd()+1); 
3312                 wxRichTextParagraph
* para 
= (wxRichTextParagraph
*) action
->GetOldParagraphs().GetChild(0); 
3313                 para
->SetAttributes(nextPara
->GetAttributes()); 
3318     SubmitAction(action
); 
3323 /// Collapse undo/redo commands 
3324 bool wxRichTextBuffer::BeginBatchUndo(const wxString
& cmdName
) 
3326     if (m_batchedCommandDepth 
== 0) 
3328         wxASSERT(m_batchedCommand 
== NULL
); 
3329         if (m_batchedCommand
) 
3331             GetCommandProcessor()->Submit(m_batchedCommand
); 
3333         m_batchedCommand 
= new wxRichTextCommand(cmdName
); 
3336     m_batchedCommandDepth 
++; 
3341 /// Collapse undo/redo commands 
3342 bool wxRichTextBuffer::EndBatchUndo() 
3344     m_batchedCommandDepth 
--; 
3346     wxASSERT(m_batchedCommandDepth 
>= 0); 
3347     wxASSERT(m_batchedCommand 
!= NULL
); 
3349     if (m_batchedCommandDepth 
== 0) 
3351         GetCommandProcessor()->Submit(m_batchedCommand
); 
3352         m_batchedCommand 
= NULL
; 
3358 /// Submit immediately, or delay according to whether collapsing is on 
3359 bool wxRichTextBuffer::SubmitAction(wxRichTextAction
* action
) 
3361     if (BatchingUndo() && m_batchedCommand 
&& !SuppressingUndo()) 
3362         m_batchedCommand
->AddAction(action
); 
3365         wxRichTextCommand
* cmd 
= new wxRichTextCommand(action
->GetName()); 
3366         cmd
->AddAction(action
); 
3368         // Only store it if we're not suppressing undo. 
3369         return GetCommandProcessor()->Submit(cmd
, !SuppressingUndo()); 
3375 /// Begin suppressing undo/redo commands. 
3376 bool wxRichTextBuffer::BeginSuppressUndo() 
3383 /// End suppressing undo/redo commands. 
3384 bool wxRichTextBuffer::EndSuppressUndo() 
3391 /// Begin using a style 
3392 bool wxRichTextBuffer::BeginStyle(const wxTextAttrEx
& style
) 
3394     wxTextAttrEx 
newStyle(GetDefaultStyle()); 
3396     // Save the old default style 
3397     m_attributeStack
.Append((wxObject
*) new wxTextAttrEx(GetDefaultStyle())); 
3399     wxRichTextApplyStyle(newStyle
, style
); 
3400     newStyle
.SetFlags(style
.GetFlags()|newStyle
.GetFlags()); 
3402     SetDefaultStyle(newStyle
); 
3404     // wxLogDebug("Default style size = %d", GetDefaultStyle().GetFont().GetPointSize()); 
3410 bool wxRichTextBuffer::EndStyle() 
3412     if (m_attributeStack
.GetFirst()) 
3414         wxLogDebug(_("Too many EndStyle calls!")); 
3418     wxList::compatibility_iterator node 
= m_attributeStack
.GetLast(); 
3419     wxTextAttrEx
* attr 
= (wxTextAttrEx
*)node
->GetData(); 
3420     m_attributeStack
.Erase(node
); 
3422     SetDefaultStyle(*attr
); 
3429 bool wxRichTextBuffer::EndAllStyles() 
3431     while (m_attributeStack
.GetCount() != 0) 
3436 /// Clear the style stack 
3437 void wxRichTextBuffer::ClearStyleStack() 
3439     for (wxList::compatibility_iterator node 
= m_attributeStack
.GetFirst(); node
; node 
= node
->GetNext()) 
3440         delete (wxTextAttrEx
*) node
->GetData(); 
3441     m_attributeStack
.Clear(); 
3444 /// Begin using bold 
3445 bool wxRichTextBuffer::BeginBold() 
3447     wxFont 
font(GetBasicStyle().GetFont()); 
3448     font
.SetWeight(wxBOLD
); 
3451     attr
.SetFont(font
,wxTEXT_ATTR_FONT_WEIGHT
); 
3453     return BeginStyle(attr
); 
3456 /// Begin using italic 
3457 bool wxRichTextBuffer::BeginItalic() 
3459     wxFont 
font(GetBasicStyle().GetFont()); 
3460     font
.SetStyle(wxITALIC
); 
3463     attr
.SetFont(font
, wxTEXT_ATTR_FONT_ITALIC
); 
3465     return BeginStyle(attr
); 
3468 /// Begin using underline 
3469 bool wxRichTextBuffer::BeginUnderline() 
3471     wxFont 
font(GetBasicStyle().GetFont()); 
3472     font
.SetUnderlined(true); 
3475     attr
.SetFont(font
, wxTEXT_ATTR_FONT_UNDERLINE
); 
3477     return BeginStyle(attr
); 
3480 /// Begin using point size 
3481 bool wxRichTextBuffer::BeginFontSize(int pointSize
) 
3483     wxFont 
font(GetBasicStyle().GetFont()); 
3484     font
.SetPointSize(pointSize
); 
3487     attr
.SetFont(font
, wxTEXT_ATTR_FONT_SIZE
); 
3489     return BeginStyle(attr
); 
3492 /// Begin using this font 
3493 bool wxRichTextBuffer::BeginFont(const wxFont
& font
) 
3496     attr
.SetFlags(wxTEXT_ATTR_FONT
); 
3499     return BeginStyle(attr
); 
3502 /// Begin using this colour 
3503 bool wxRichTextBuffer::BeginTextColour(const wxColour
& colour
) 
3506     attr
.SetFlags(wxTEXT_ATTR_TEXT_COLOUR
); 
3507     attr
.SetTextColour(colour
); 
3509     return BeginStyle(attr
); 
3512 /// Begin using alignment 
3513 bool wxRichTextBuffer::BeginAlignment(wxTextAttrAlignment alignment
) 
3516     attr
.SetFlags(wxTEXT_ATTR_ALIGNMENT
); 
3517     attr
.SetAlignment(alignment
); 
3519     return BeginStyle(attr
); 
3522 /// Begin left indent 
3523 bool wxRichTextBuffer::BeginLeftIndent(int leftIndent
, int leftSubIndent
) 
3526     attr
.SetFlags(wxTEXT_ATTR_LEFT_INDENT
); 
3527     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
3529     return BeginStyle(attr
); 
3532 /// Begin right indent 
3533 bool wxRichTextBuffer::BeginRightIndent(int rightIndent
) 
3536     attr
.SetFlags(wxTEXT_ATTR_RIGHT_INDENT
); 
3537     attr
.SetRightIndent(rightIndent
); 
3539     return BeginStyle(attr
); 
3542 /// Begin paragraph spacing 
3543 bool wxRichTextBuffer::BeginParagraphSpacing(int before
, int after
) 
3547         flags 
|= wxTEXT_ATTR_PARA_SPACING_BEFORE
; 
3549         flags 
|= wxTEXT_ATTR_PARA_SPACING_AFTER
; 
3552     attr
.SetFlags(flags
); 
3553     attr
.SetParagraphSpacingBefore(before
); 
3554     attr
.SetParagraphSpacingAfter(after
); 
3556     return BeginStyle(attr
); 
3559 /// Begin line spacing 
3560 bool wxRichTextBuffer::BeginLineSpacing(int lineSpacing
) 
3563     attr
.SetFlags(wxTEXT_ATTR_LINE_SPACING
); 
3564     attr
.SetLineSpacing(lineSpacing
); 
3566     return BeginStyle(attr
); 
3569 /// Begin numbered bullet 
3570 bool wxRichTextBuffer::BeginNumberedBullet(int bulletNumber
, int leftIndent
, int leftSubIndent
, int bulletStyle
) 
3573     attr
.SetFlags(wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_BULLET_NUMBER
|wxTEXT_ATTR_LEFT_INDENT
); 
3574     attr
.SetBulletStyle(bulletStyle
); 
3575     attr
.SetBulletNumber(bulletNumber
); 
3576     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
3578     return BeginStyle(attr
); 
3581 /// Begin symbol bullet 
3582 bool wxRichTextBuffer::BeginSymbolBullet(wxChar symbol
, int leftIndent
, int leftSubIndent
, int bulletStyle
) 
3585     attr
.SetFlags(wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_BULLET_SYMBOL
|wxTEXT_ATTR_LEFT_INDENT
); 
3586     attr
.SetBulletStyle(bulletStyle
); 
3587     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
3588     attr
.SetBulletSymbol(symbol
); 
3590     return BeginStyle(attr
); 
3593 /// Begin named character style 
3594 bool wxRichTextBuffer::BeginCharacterStyle(const wxString
& characterStyle
) 
3596     if (GetStyleSheet()) 
3598         wxRichTextCharacterStyleDefinition
* def 
= GetStyleSheet()->FindCharacterStyle(characterStyle
); 
3602             def
->GetStyle().CopyTo(attr
); 
3603             return BeginStyle(attr
); 
3609 /// Begin named paragraph style 
3610 bool wxRichTextBuffer::BeginParagraphStyle(const wxString
& paragraphStyle
) 
3612     if (GetStyleSheet()) 
3614         wxRichTextParagraphStyleDefinition
* def 
= GetStyleSheet()->FindParagraphStyle(paragraphStyle
); 
3618             def
->GetStyle().CopyTo(attr
); 
3619             return BeginStyle(attr
); 
3625 /// Adds a handler to the end 
3626 void wxRichTextBuffer::AddHandler(wxRichTextFileHandler 
*handler
) 
3628     sm_handlers
.Append(handler
); 
3631 /// Inserts a handler at the front 
3632 void wxRichTextBuffer::InsertHandler(wxRichTextFileHandler 
*handler
) 
3634     sm_handlers
.Insert( handler 
); 
3637 /// Removes a handler 
3638 bool wxRichTextBuffer::RemoveHandler(const wxString
& name
) 
3640     wxRichTextFileHandler 
*handler 
= FindHandler(name
); 
3643         sm_handlers
.DeleteObject(handler
); 
3651 /// Finds a handler by filename or, if supplied, type 
3652 wxRichTextFileHandler 
*wxRichTextBuffer::FindHandlerFilenameOrType(const wxString
& filename
, int imageType
) 
3654     if (imageType 
!= wxRICHTEXT_TYPE_ANY
) 
3655         return FindHandler(imageType
); 
3658         wxString path
, file
, ext
; 
3659         wxSplitPath(filename
, & path
, & file
, & ext
); 
3660         return FindHandler(ext
, imageType
); 
3665 /// Finds a handler by name 
3666 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(const wxString
& name
) 
3668     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
3671         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
3672         if (handler
->GetName().Lower() == name
.Lower()) return handler
; 
3674         node 
= node
->GetNext(); 
3679 /// Finds a handler by extension and type 
3680 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(const wxString
& extension
, int type
) 
3682     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
3685         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
3686         if ( handler
->GetExtension().Lower() == extension
.Lower() && 
3687             (type 
== wxRICHTEXT_TYPE_ANY 
|| handler
->GetType() == type
) ) 
3689         node 
= node
->GetNext(); 
3694 /// Finds a handler by type 
3695 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(int type
) 
3697     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
3700         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler 
*)node
->GetData(); 
3701         if (handler
->GetType() == type
) return handler
; 
3702         node 
= node
->GetNext(); 
3707 void wxRichTextBuffer::InitStandardHandlers() 
3709     if (!FindHandler(wxRICHTEXT_TYPE_TEXT
)) 
3710         AddHandler(new wxRichTextPlainTextHandler
); 
3713 void wxRichTextBuffer::CleanUpHandlers() 
3715     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
3718         wxRichTextFileHandler
* handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
3719         wxList::compatibility_iterator next 
= node
->GetNext(); 
3724     sm_handlers
.Clear(); 
3727 wxString 
wxRichTextBuffer::GetExtWildcard(bool combine
, bool save
, wxArrayInt
* types
) 
3734     wxList::compatibility_iterator node 
= GetHandlers().GetFirst(); 
3738         wxRichTextFileHandler
* handler 
= (wxRichTextFileHandler
*) node
->GetData(); 
3739         if (handler
->IsVisible() && ((save 
&& handler
->CanSave()) || !save 
&& handler
->CanLoad())) 
3744                     wildcard 
+= wxT(";"); 
3745                 wildcard 
+= wxT("*.") + handler
->GetExtension(); 
3750                     wildcard 
+= wxT("|"); 
3751                 wildcard 
+= handler
->GetName(); 
3752                 wildcard 
+= wxT(" "); 
3753                 wildcard 
+= _("files"); 
3754                 wildcard 
+= wxT(" (*."); 
3755                 wildcard 
+= handler
->GetExtension(); 
3756                 wildcard 
+= wxT(")|*."); 
3757                 wildcard 
+= handler
->GetExtension(); 
3759                     types
->Add(handler
->GetType()); 
3764         node 
= node
->GetNext(); 
3768         wildcard 
= wxT("(") + wildcard 
+ wxT(")|") + wildcard
; 
3773 bool wxRichTextBuffer::LoadFile(const wxString
& filename
, int type
) 
3775     wxRichTextFileHandler
* handler 
= FindHandlerFilenameOrType(filename
, type
); 
3778         SetDefaultStyle(wxTextAttrEx()); 
3780         bool success 
= handler
->LoadFile(this, filename
); 
3781         Invalidate(wxRICHTEXT_ALL
); 
3789 bool wxRichTextBuffer::SaveFile(const wxString
& filename
, int type
) 
3791     wxRichTextFileHandler
* handler 
= FindHandlerFilenameOrType(filename
, type
); 
3793         return handler
->SaveFile(this, filename
); 
3798 /// Load from a stream 
3799 bool wxRichTextBuffer::LoadFile(wxInputStream
& stream
, int type
) 
3801     wxRichTextFileHandler
* handler 
= FindHandler(type
); 
3804         SetDefaultStyle(wxTextAttrEx()); 
3805         bool success 
= handler
->LoadFile(this, stream
); 
3806         Invalidate(wxRICHTEXT_ALL
); 
3813 /// Save to a stream 
3814 bool wxRichTextBuffer::SaveFile(wxOutputStream
& stream
, int type
) 
3816     wxRichTextFileHandler
* handler 
= FindHandler(type
); 
3818         return handler
->SaveFile(this, stream
); 
3823 /// Copy the range to the clipboard 
3824 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange
& range
) 
3826     bool success 
= false; 
3827 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
3828     wxString text 
= GetTextForRange(range
); 
3829     if (!wxTheClipboard
->IsOpened() && wxTheClipboard
->Open()) 
3831         success 
= wxTheClipboard
->SetData(new wxTextDataObject(text
)); 
3832         wxTheClipboard
->Close(); 
3840 /// Paste the clipboard content to the buffer 
3841 bool wxRichTextBuffer::PasteFromClipboard(long position
) 
3843     bool success 
= false; 
3844 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
3845     if (CanPasteFromClipboard()) 
3847         if (wxTheClipboard
->Open()) 
3849             if (wxTheClipboard
->IsSupported(wxDF_TEXT
)) 
3851                 wxTextDataObject data
; 
3852                 wxTheClipboard
->GetData(data
); 
3853                 wxString 
text(data
.GetText()); 
3855                 InsertTextWithUndo(position
+1, text
, GetRichTextCtrl()); 
3859             else if (wxTheClipboard
->IsSupported(wxDF_BITMAP
)) 
3861                 wxBitmapDataObject data
; 
3862                 wxTheClipboard
->GetData(data
); 
3863                 wxBitmap 
bitmap(data
.GetBitmap()); 
3864                 wxImage 
image(bitmap
.ConvertToImage()); 
3866                 wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Image"), wxRICHTEXT_INSERT
, this, GetRichTextCtrl(), false); 
3868                 action
->GetNewParagraphs().AddImage(image
); 
3870                 if (action
->GetNewParagraphs().GetChildCount() == 1) 
3871                     action
->GetNewParagraphs().SetPartialParagraph(true); 
3873                 action
->SetPosition(position
); 
3875                 // Set the range we'll need to delete in Undo 
3876                 action
->SetRange(wxRichTextRange(position
, position
)); 
3878                 SubmitAction(action
); 
3882             wxTheClipboard
->Close(); 
3886     wxUnusedVar(position
); 
3891 /// Can we paste from the clipboard? 
3892 bool wxRichTextBuffer::CanPasteFromClipboard() const 
3894     bool canPaste 
= false; 
3895 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
3896     if (!wxTheClipboard
->IsOpened() && wxTheClipboard
->Open()) 
3898         if (wxTheClipboard
->IsSupported(wxDF_TEXT
) || wxTheClipboard
->IsSupported(wxDF_BITMAP
)) 
3902         wxTheClipboard
->Close(); 
3908 /// Dumps contents of buffer for debugging purposes 
3909 void wxRichTextBuffer::Dump() 
3913         wxStringOutputStream 
stream(& text
); 
3914         wxTextOutputStream 
textStream(stream
); 
3923  * Module to initialise and clean up handlers 
3926 class wxRichTextModule
: public wxModule
 
3928 DECLARE_DYNAMIC_CLASS(wxRichTextModule
) 
3930     wxRichTextModule() {} 
3931     bool OnInit() { wxRichTextBuffer::InitStandardHandlers(); return true; }; 
3932     void OnExit() { wxRichTextBuffer::CleanUpHandlers(); }; 
3935 IMPLEMENT_DYNAMIC_CLASS(wxRichTextModule
, wxModule
) 
3939  * Commands for undo/redo 
3943 wxRichTextCommand::wxRichTextCommand(const wxString
& name
, wxRichTextCommandId id
, wxRichTextBuffer
* buffer
, 
3944                                      wxRichTextCtrl
* ctrl
, bool ignoreFirstTime
): wxCommand(true, name
) 
3946     /* wxRichTextAction* action = */ new wxRichTextAction(this, name
, id
, buffer
, ctrl
, ignoreFirstTime
); 
3949 wxRichTextCommand::wxRichTextCommand(const wxString
& name
): wxCommand(true, name
) 
3953 wxRichTextCommand::~wxRichTextCommand() 
3958 void wxRichTextCommand::AddAction(wxRichTextAction
* action
) 
3960     if (!m_actions
.Member(action
)) 
3961         m_actions
.Append(action
); 
3964 bool wxRichTextCommand::Do() 
3966     for (wxList::compatibility_iterator node 
= m_actions
.GetFirst(); node
; node 
= node
->GetNext()) 
3968         wxRichTextAction
* action 
= (wxRichTextAction
*) node
->GetData(); 
3975 bool wxRichTextCommand::Undo() 
3977     for (wxList::compatibility_iterator node 
= m_actions
.GetLast(); node
; node 
= node
->GetPrevious()) 
3979         wxRichTextAction
* action 
= (wxRichTextAction
*) node
->GetData(); 
3986 void wxRichTextCommand::ClearActions() 
3988     WX_CLEAR_LIST(wxList
, m_actions
); 
3996 wxRichTextAction::wxRichTextAction(wxRichTextCommand
* cmd
, const wxString
& name
, wxRichTextCommandId id
, wxRichTextBuffer
* buffer
, 
3997                                      wxRichTextCtrl
* ctrl
, bool ignoreFirstTime
) 
4000     m_ignoreThis 
= ignoreFirstTime
; 
4005     m_newParagraphs
.SetDefaultStyle(buffer
->GetDefaultStyle()); 
4006     m_newParagraphs
.SetBasicStyle(buffer
->GetBasicStyle()); 
4008         cmd
->AddAction(this); 
4011 wxRichTextAction::~wxRichTextAction() 
4015 bool wxRichTextAction::Do() 
4017     m_buffer
->Modify(true); 
4021     case wxRICHTEXT_INSERT
: 
4023             m_buffer
->InsertFragment(GetPosition(), m_newParagraphs
); 
4024             m_buffer
->UpdateRanges(); 
4025             m_buffer
->Invalidate(GetRange()); 
4027             long newCaretPosition 
= GetPosition() + m_newParagraphs
.GetRange().GetLength() - 1; 
4028             if (m_newParagraphs
.GetPartialParagraph()) 
4029                 newCaretPosition 
--; 
4031             UpdateAppearance(newCaretPosition
, true /* send update event */); 
4035     case wxRICHTEXT_DELETE
: 
4037             m_buffer
->DeleteRange(GetRange()); 
4038             m_buffer
->UpdateRanges(); 
4039             m_buffer
->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); 
4041             UpdateAppearance(GetRange().GetStart()-1, true /* send update event */); 
4045     case wxRICHTEXT_CHANGE_STYLE
: 
4047             ApplyParagraphs(GetNewParagraphs()); 
4048             m_buffer
->Invalidate(GetRange()); 
4050             UpdateAppearance(GetPosition()); 
4061 bool wxRichTextAction::Undo() 
4063     m_buffer
->Modify(true); 
4067     case wxRICHTEXT_INSERT
: 
4069             m_buffer
->DeleteRange(GetRange()); 
4070             m_buffer
->UpdateRanges(); 
4071             m_buffer
->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); 
4073             long newCaretPosition 
= GetPosition() - 1; 
4074             // if (m_newParagraphs.GetPartialParagraph()) 
4075             //    newCaretPosition --; 
4077             UpdateAppearance(newCaretPosition
, true /* send update event */); 
4081     case wxRICHTEXT_DELETE
: 
4083             m_buffer
->InsertFragment(GetRange().GetStart(), m_oldParagraphs
); 
4084             m_buffer
->UpdateRanges(); 
4085             m_buffer
->Invalidate(GetRange()); 
4087             UpdateAppearance(GetPosition(), true /* send update event */); 
4091     case wxRICHTEXT_CHANGE_STYLE
: 
4093             ApplyParagraphs(GetOldParagraphs()); 
4094             m_buffer
->Invalidate(GetRange()); 
4096             UpdateAppearance(GetPosition()); 
4107 /// Update the control appearance 
4108 void wxRichTextAction::UpdateAppearance(long caretPosition
, bool sendUpdateEvent
) 
4112         m_ctrl
->SetCaretPosition(caretPosition
); 
4113         if (!m_ctrl
->IsFrozen()) 
4115             m_ctrl
->LayoutContent(); 
4116             m_ctrl
->PositionCaret(); 
4117             m_ctrl
->Refresh(false); 
4119             if (sendUpdateEvent
) 
4120                 m_ctrl
->SendUpdateEvent(); 
4125 /// Replace the buffer paragraphs with the new ones. 
4126 void wxRichTextAction::ApplyParagraphs(const wxRichTextFragment
& fragment
) 
4128     wxRichTextObjectList::compatibility_iterator node 
= fragment
.GetChildren().GetFirst(); 
4131         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
4132         wxASSERT (para 
!= NULL
); 
4134         // We'll replace the existing paragraph by finding the paragraph at this position, 
4135         // delete its node data, and setting a copy as the new node data. 
4136         // TODO: make more efficient by simply swapping old and new paragraph objects. 
4138         wxRichTextParagraph
* existingPara 
= m_buffer
->GetParagraphAtPosition(para
->GetRange().GetStart()); 
4141             wxRichTextObjectList::compatibility_iterator bufferParaNode 
= m_buffer
->GetChildren().Find(existingPara
); 
4144                 wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(*para
); 
4145                 newPara
->SetParent(m_buffer
); 
4147                 bufferParaNode
->SetData(newPara
); 
4149                 delete existingPara
; 
4153         node 
= node
->GetNext(); 
4160  * This stores beginning and end positions for a range of data. 
4163 /// Limit this range to be within 'range' 
4164 bool wxRichTextRange::LimitTo(const wxRichTextRange
& range
) 
4166     if (m_start 
< range
.m_start
) 
4167         m_start 
= range
.m_start
; 
4169     if (m_end 
> range
.m_end
) 
4170         m_end 
= range
.m_end
; 
4176  * wxRichTextImage implementation 
4177  * This object represents an image. 
4180 IMPLEMENT_DYNAMIC_CLASS(wxRichTextImage
, wxRichTextObject
) 
4182 wxRichTextImage::wxRichTextImage(const wxImage
& image
, wxRichTextObject
* parent
): 
4183     wxRichTextObject(parent
) 
4188 wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock
& imageBlock
, wxRichTextObject
* parent
): 
4189     wxRichTextObject(parent
) 
4191     m_imageBlock 
= imageBlock
; 
4192     m_imageBlock
.Load(m_image
); 
4195 /// Load wxImage from the block 
4196 bool wxRichTextImage::LoadFromBlock() 
4198     m_imageBlock
.Load(m_image
); 
4199     return m_imageBlock
.Ok(); 
4202 /// Make block from the wxImage 
4203 bool wxRichTextImage::MakeBlock() 
4205     if (m_imageBlock
.GetImageType() == wxBITMAP_TYPE_ANY 
|| m_imageBlock
.GetImageType() == -1) 
4206         m_imageBlock
.SetImageType(wxBITMAP_TYPE_PNG
); 
4208     m_imageBlock
.MakeImageBlock(m_image
, m_imageBlock
.GetImageType()); 
4209     return m_imageBlock
.Ok(); 
4214 bool wxRichTextImage::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextRange
& selectionRange
, const wxRect
& rect
, int WXUNUSED(descent
), int WXUNUSED(style
)) 
4216     if (!m_image
.Ok() && m_imageBlock
.Ok()) 
4222     if (m_image
.Ok() && !m_bitmap
.Ok()) 
4223         m_bitmap 
= wxBitmap(m_image
); 
4225     int y 
= rect
.y 
+ (rect
.height 
- m_image
.GetHeight()); 
4228         dc
.DrawBitmap(m_bitmap
, rect
.x
, y
, true); 
4230     if (selectionRange
.Contains(range
.GetStart())) 
4232         dc
.SetBrush(*wxBLACK_BRUSH
); 
4233         dc
.SetPen(*wxBLACK_PEN
); 
4234         dc
.SetLogicalFunction(wxINVERT
); 
4235         dc
.DrawRectangle(rect
); 
4236         dc
.SetLogicalFunction(wxCOPY
); 
4242 /// Lay the item out 
4243 bool wxRichTextImage::Layout(wxDC
& WXUNUSED(dc
), const wxRect
& rect
, int WXUNUSED(style
)) 
4250         SetCachedSize(wxSize(m_image
.GetWidth(), m_image
.GetHeight())); 
4251         SetPosition(rect
.GetPosition()); 
4257 /// Get/set the object size for the given range. Returns false if the range 
4258 /// is invalid for this object. 
4259 bool wxRichTextImage::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& WXUNUSED(descent
), wxDC
& WXUNUSED(dc
), int WXUNUSED(flags
)) const 
4261     if (!range
.IsWithin(GetRange())) 
4267     size
.x 
= m_image
.GetWidth(); 
4268     size
.y 
= m_image
.GetHeight(); 
4274 void wxRichTextImage::Copy(const wxRichTextImage
& obj
) 
4276     m_image 
= obj
.m_image
; 
4277     m_imageBlock 
= obj
.m_imageBlock
; 
4285 /// Compare two attribute objects 
4286 bool wxTextAttrEq(const wxTextAttrEx
& attr1
, const wxTextAttrEx
& attr2
) 
4289         attr1
.GetTextColour() == attr2
.GetTextColour() && 
4290         attr1
.GetBackgroundColour() == attr2
.GetBackgroundColour() && 
4291         attr1
.GetFont() == attr2
.GetFont() && 
4292         attr1
.GetAlignment() == attr2
.GetAlignment() && 
4293         attr1
.GetLeftIndent() == attr2
.GetLeftIndent() && 
4294         attr1
.GetRightIndent() == attr2
.GetRightIndent() && 
4295         attr1
.GetLeftSubIndent() == attr2
.GetLeftSubIndent() && 
4296         attr1
.GetTabs().GetCount() == attr2
.GetTabs().GetCount() && // heuristic 
4297         attr1
.GetLineSpacing() == attr2
.GetLineSpacing() && 
4298         attr1
.GetParagraphSpacingAfter() == attr2
.GetParagraphSpacingAfter() && 
4299         attr1
.GetParagraphSpacingBefore() == attr2
.GetParagraphSpacingBefore() && 
4300         attr1
.GetBulletStyle() == attr2
.GetBulletStyle() && 
4301         attr1
.GetBulletNumber() == attr2
.GetBulletNumber() && 
4302         attr1
.GetBulletSymbol() == attr2
.GetBulletSymbol() && 
4303         attr1
.GetCharacterStyleName() == attr2
.GetCharacterStyleName() && 
4304         attr1
.GetParagraphStyleName() == attr2
.GetParagraphStyleName()); 
4307 bool wxTextAttrEq(const wxTextAttrEx
& attr1
, const wxRichTextAttr
& attr2
) 
4310         attr1
.GetTextColour() == attr2
.GetTextColour() && 
4311         attr1
.GetBackgroundColour() == attr2
.GetBackgroundColour() && 
4312         attr1
.GetFont().GetPointSize() == attr2
.GetFontSize() && 
4313         attr1
.GetFont().GetStyle() == attr2
.GetFontStyle() && 
4314         attr1
.GetFont().GetWeight() == attr2
.GetFontWeight() && 
4315         attr1
.GetFont().GetFaceName() == attr2
.GetFontFaceName() && 
4316         attr1
.GetFont().GetUnderlined() == attr2
.GetFontUnderlined() && 
4317         attr1
.GetAlignment() == attr2
.GetAlignment() && 
4318         attr1
.GetLeftIndent() == attr2
.GetLeftIndent() && 
4319         attr1
.GetRightIndent() == attr2
.GetRightIndent() && 
4320         attr1
.GetLeftSubIndent() == attr2
.GetLeftSubIndent() && 
4321         attr1
.GetTabs().GetCount() == attr2
.GetTabs().GetCount() && // heuristic 
4322         attr1
.GetLineSpacing() == attr2
.GetLineSpacing() && 
4323         attr1
.GetParagraphSpacingAfter() == attr2
.GetParagraphSpacingAfter() && 
4324         attr1
.GetParagraphSpacingBefore() == attr2
.GetParagraphSpacingBefore() && 
4325         attr1
.GetBulletStyle() == attr2
.GetBulletStyle() && 
4326         attr1
.GetBulletNumber() == attr2
.GetBulletNumber() && 
4327         attr1
.GetBulletSymbol() == attr2
.GetBulletSymbol() && 
4328         attr1
.GetCharacterStyleName() == attr2
.GetCharacterStyleName() && 
4329         attr1
.GetParagraphStyleName() == attr2
.GetParagraphStyleName()); 
4332 /// Compare two attribute objects, but take into account the flags 
4333 /// specifying attributes of interest. 
4334 bool wxTextAttrEqPartial(const wxTextAttrEx
& attr1
, const wxTextAttrEx
& attr2
, int flags
) 
4336     if ((flags 
& wxTEXT_ATTR_TEXT_COLOUR
) && attr1
.GetTextColour() != attr2
.GetTextColour()) 
4339     if ((flags 
& wxTEXT_ATTR_BACKGROUND_COLOUR
) && attr1
.GetBackgroundColour() != attr2
.GetBackgroundColour()) 
4342     if ((flags 
& wxTEXT_ATTR_FONT_FACE
) && attr1
.GetFont().Ok() && attr2
.GetFont().Ok() && 
4343         attr1
.GetFont().GetFaceName() != attr2
.GetFont().GetFaceName()) 
4346     if ((flags 
& wxTEXT_ATTR_FONT_SIZE
) && attr1
.GetFont().Ok() && attr2
.GetFont().Ok() && 
4347         attr1
.GetFont().GetPointSize() != attr2
.GetFont().GetPointSize()) 
4350     if ((flags 
& wxTEXT_ATTR_FONT_WEIGHT
) && attr1
.GetFont().Ok() && attr2
.GetFont().Ok() && 
4351         attr1
.GetFont().GetWeight() != attr2
.GetFont().GetWeight()) 
4354     if ((flags 
& wxTEXT_ATTR_FONT_ITALIC
) && attr1
.GetFont().Ok() && attr2
.GetFont().Ok() && 
4355         attr1
.GetFont().GetStyle() != attr2
.GetFont().GetStyle()) 
4358     if ((flags 
& wxTEXT_ATTR_FONT_UNDERLINE
) && attr1
.GetFont().Ok() && attr2
.GetFont().Ok() && 
4359         attr1
.GetFont().GetUnderlined() != attr2
.GetFont().GetUnderlined()) 
4362     if ((flags 
& wxTEXT_ATTR_ALIGNMENT
) && attr1
.GetAlignment() != attr2
.GetAlignment()) 
4365     if ((flags 
& wxTEXT_ATTR_LEFT_INDENT
) && 
4366         ((attr1
.GetLeftIndent() != attr2
.GetLeftIndent()) || (attr1
.GetLeftSubIndent() != attr2
.GetLeftSubIndent()))) 
4369     if ((flags 
& wxTEXT_ATTR_RIGHT_INDENT
) && 
4370         (attr1
.GetRightIndent() != attr2
.GetRightIndent())) 
4373     if ((flags 
& wxTEXT_ATTR_PARA_SPACING_AFTER
) && 
4374         (attr1
.GetParagraphSpacingAfter() != attr2
.GetParagraphSpacingAfter())) 
4377     if ((flags 
& wxTEXT_ATTR_PARA_SPACING_BEFORE
) && 
4378         (attr1
.GetParagraphSpacingBefore() != attr2
.GetParagraphSpacingBefore())) 
4381     if ((flags 
& wxTEXT_ATTR_LINE_SPACING
) && 
4382         (attr1
.GetLineSpacing() != attr2
.GetLineSpacing())) 
4385     if ((flags 
& wxTEXT_ATTR_CHARACTER_STYLE_NAME
) && 
4386         (attr1
.GetCharacterStyleName() != attr2
.GetCharacterStyleName())) 
4389     if ((flags 
& wxTEXT_ATTR_PARAGRAPH_STYLE_NAME
) && 
4390         (attr1
.GetParagraphStyleName() != attr2
.GetParagraphStyleName())) 
4393     if ((flags 
& wxTEXT_ATTR_BULLET_STYLE
) && 
4394         (attr1
.GetBulletStyle() != attr2
.GetBulletStyle())) 
4397     if ((flags 
& wxTEXT_ATTR_BULLET_NUMBER
) && 
4398         (attr1
.GetBulletNumber() != attr2
.GetBulletNumber())) 
4401     if ((flags 
& wxTEXT_ATTR_BULLET_SYMBOL
) && 
4402         (attr1
.GetBulletSymbol() != attr2
.GetBulletSymbol())) 
4406     if ((flags & wxTEXT_ATTR_TABS) && 
4413 bool wxTextAttrEqPartial(const wxTextAttrEx
& attr1
, const wxRichTextAttr
& attr2
, int flags
) 
4415     if ((flags 
& wxTEXT_ATTR_TEXT_COLOUR
) && attr1
.GetTextColour() != attr2
.GetTextColour()) 
4418     if ((flags 
& wxTEXT_ATTR_BACKGROUND_COLOUR
) && attr1
.GetBackgroundColour() != attr2
.GetBackgroundColour()) 
4421     if ((flags 
& (wxTEXT_ATTR_FONT
)) && !attr1
.GetFont().Ok()) 
4424     if ((flags 
& wxTEXT_ATTR_FONT_FACE
) && attr1
.GetFont().Ok() && 
4425         attr1
.GetFont().GetFaceName() != attr2
.GetFontFaceName()) 
4428     if ((flags 
& wxTEXT_ATTR_FONT_SIZE
) && attr1
.GetFont().Ok() && 
4429         attr1
.GetFont().GetPointSize() != attr2
.GetFontSize()) 
4432     if ((flags 
& wxTEXT_ATTR_FONT_WEIGHT
) && attr1
.GetFont().Ok() && 
4433         attr1
.GetFont().GetWeight() != attr2
.GetFontWeight()) 
4436     if ((flags 
& wxTEXT_ATTR_FONT_ITALIC
) && attr1
.GetFont().Ok() && 
4437         attr1
.GetFont().GetStyle() != attr2
.GetFontStyle()) 
4440     if ((flags 
& wxTEXT_ATTR_FONT_UNDERLINE
) && attr1
.GetFont().Ok() && 
4441         attr1
.GetFont().GetUnderlined() != attr2
.GetFontUnderlined()) 
4444     if ((flags 
& wxTEXT_ATTR_ALIGNMENT
) && attr1
.GetAlignment() != attr2
.GetAlignment()) 
4447     if ((flags 
& wxTEXT_ATTR_LEFT_INDENT
) && 
4448         ((attr1
.GetLeftIndent() != attr2
.GetLeftIndent()) || (attr1
.GetLeftSubIndent() != attr2
.GetLeftSubIndent()))) 
4451     if ((flags 
& wxTEXT_ATTR_RIGHT_INDENT
) && 
4452         (attr1
.GetRightIndent() != attr2
.GetRightIndent())) 
4455     if ((flags 
& wxTEXT_ATTR_PARA_SPACING_AFTER
) && 
4456         (attr1
.GetParagraphSpacingAfter() != attr2
.GetParagraphSpacingAfter())) 
4459     if ((flags 
& wxTEXT_ATTR_PARA_SPACING_BEFORE
) && 
4460         (attr1
.GetParagraphSpacingBefore() != attr2
.GetParagraphSpacingBefore())) 
4463     if ((flags 
& wxTEXT_ATTR_LINE_SPACING
) && 
4464         (attr1
.GetLineSpacing() != attr2
.GetLineSpacing())) 
4467     if ((flags 
& wxTEXT_ATTR_CHARACTER_STYLE_NAME
) && 
4468         (attr1
.GetCharacterStyleName() != attr2
.GetCharacterStyleName())) 
4471     if ((flags 
& wxTEXT_ATTR_PARAGRAPH_STYLE_NAME
) && 
4472         (attr1
.GetParagraphStyleName() != attr2
.GetParagraphStyleName())) 
4475     if ((flags 
& wxTEXT_ATTR_BULLET_STYLE
) && 
4476         (attr1
.GetBulletStyle() != attr2
.GetBulletStyle())) 
4479     if ((flags 
& wxTEXT_ATTR_BULLET_NUMBER
) && 
4480         (attr1
.GetBulletNumber() != attr2
.GetBulletNumber())) 
4483     if ((flags 
& wxTEXT_ATTR_BULLET_SYMBOL
) && 
4484         (attr1
.GetBulletSymbol() != attr2
.GetBulletSymbol())) 
4488     if ((flags & wxTEXT_ATTR_TABS) && 
4496 /// Apply one style to another 
4497 bool wxRichTextApplyStyle(wxTextAttrEx
& destStyle
, const wxTextAttrEx
& style
) 
4500     if (style
.GetFont().Ok() && ((style
.GetFlags() & (wxTEXT_ATTR_FONT
)) == (wxTEXT_ATTR_FONT
))) 
4501         destStyle
.SetFont(style
.GetFont()); 
4502     else if (style
.GetFont().Ok()) 
4504         wxFont font 
= destStyle
.GetFont(); 
4506         if (style
.GetFlags() & wxTEXT_ATTR_FONT_FACE
) 
4507             font
.SetFaceName(style
.GetFont().GetFaceName()); 
4509         if (style
.GetFlags() & wxTEXT_ATTR_FONT_SIZE
) 
4510             font
.SetPointSize(style
.GetFont().GetPointSize()); 
4512         if (style
.GetFlags() & wxTEXT_ATTR_FONT_ITALIC
) 
4513             font
.SetStyle(style
.GetFont().GetStyle()); 
4515         if (style
.GetFlags() & wxTEXT_ATTR_FONT_WEIGHT
) 
4516             font
.SetWeight(style
.GetFont().GetWeight()); 
4518         if (style
.GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE
) 
4519             font
.SetUnderlined(style
.GetFont().GetUnderlined()); 
4521         if (font 
!= destStyle
.GetFont()) 
4522             destStyle
.SetFont(font
); 
4525     if ( style
.GetTextColour().Ok() && style
.HasTextColour()) 
4526         destStyle
.SetTextColour(style
.GetTextColour()); 
4528     if ( style
.GetBackgroundColour().Ok() && style
.HasBackgroundColour()) 
4529         destStyle
.SetBackgroundColour(style
.GetBackgroundColour()); 
4531     if (style
.HasAlignment()) 
4532         destStyle
.SetAlignment(style
.GetAlignment()); 
4534     if (style
.HasTabs()) 
4535         destStyle
.SetTabs(style
.GetTabs()); 
4537     if (style
.HasLeftIndent()) 
4538         destStyle
.SetLeftIndent(style
.GetLeftIndent(), style
.GetLeftSubIndent()); 
4540     if (style
.HasRightIndent()) 
4541         destStyle
.SetRightIndent(style
.GetRightIndent()); 
4543     if (style
.HasParagraphSpacingAfter()) 
4544         destStyle
.SetParagraphSpacingAfter(style
.GetParagraphSpacingAfter()); 
4546     if (style
.HasParagraphSpacingBefore()) 
4547         destStyle
.SetParagraphSpacingBefore(style
.GetParagraphSpacingBefore()); 
4549     if (style
.HasLineSpacing()) 
4550         destStyle
.SetLineSpacing(style
.GetLineSpacing()); 
4552     if (style
.HasCharacterStyleName()) 
4553         destStyle
.SetCharacterStyleName(style
.GetCharacterStyleName()); 
4555     if (style
.HasParagraphStyleName()) 
4556         destStyle
.SetParagraphStyleName(style
.GetParagraphStyleName()); 
4558     if (style
.HasBulletStyle()) 
4560         destStyle
.SetBulletStyle(style
.GetBulletStyle()); 
4561         destStyle
.SetBulletSymbol(style
.GetBulletSymbol()); 
4564     if (style
.HasBulletNumber()) 
4565         destStyle
.SetBulletNumber(style
.GetBulletNumber()); 
4570 bool wxRichTextApplyStyle(wxRichTextAttr
& destStyle
, const wxTextAttrEx
& style
) 
4572     wxTextAttrEx destStyle2
; 
4573     destStyle
.CopyTo(destStyle2
); 
4574     wxRichTextApplyStyle(destStyle2
, style
); 
4575     destStyle 
= destStyle2
; 
4579 bool wxRichTextApplyStyle(wxTextAttrEx
& destStyle
, const wxRichTextAttr
& style
) 
4582     // Whole font. Avoiding setting individual attributes if possible, since 
4583     // it recreates the font each time. 
4584     if ((style
.GetFlags() & (wxTEXT_ATTR_FONT
)) == (wxTEXT_ATTR_FONT
)) 
4586         destStyle
.SetFont(wxFont(style
.GetFontSize(), destStyle
.GetFont().Ok() ? destStyle
.GetFont().GetFamily() : wxDEFAULT
, 
4587             style
.GetFontStyle(), style
.GetFontWeight(), style
.GetFontUnderlined(), style
.GetFontFaceName())); 
4589     else if (style
.GetFlags() & (wxTEXT_ATTR_FONT
)) 
4591         wxFont font 
= destStyle
.GetFont(); 
4593         if (style
.GetFlags() & wxTEXT_ATTR_FONT_FACE
) 
4594             font
.SetFaceName(style
.GetFontFaceName()); 
4596         if (style
.GetFlags() & wxTEXT_ATTR_FONT_SIZE
) 
4597             font
.SetPointSize(style
.GetFontSize()); 
4599         if (style
.GetFlags() & wxTEXT_ATTR_FONT_ITALIC
) 
4600             font
.SetStyle(style
.GetFontStyle()); 
4602         if (style
.GetFlags() & wxTEXT_ATTR_FONT_WEIGHT
) 
4603             font
.SetWeight(style
.GetFontWeight()); 
4605         if (style
.GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE
) 
4606             font
.SetUnderlined(style
.GetFontUnderlined()); 
4608         if (font 
!= destStyle
.GetFont()) 
4609             destStyle
.SetFont(font
); 
4612     if ( style
.GetTextColour().Ok() && style
.HasTextColour()) 
4613         destStyle
.SetTextColour(style
.GetTextColour()); 
4615     if ( style
.GetBackgroundColour().Ok() && style
.HasBackgroundColour()) 
4616         destStyle
.SetBackgroundColour(style
.GetBackgroundColour()); 
4618     if (style
.HasAlignment()) 
4619         destStyle
.SetAlignment(style
.GetAlignment()); 
4621     if (style
.HasTabs()) 
4622         destStyle
.SetTabs(style
.GetTabs()); 
4624     if (style
.HasLeftIndent()) 
4625         destStyle
.SetLeftIndent(style
.GetLeftIndent(), style
.GetLeftSubIndent()); 
4627     if (style
.HasRightIndent()) 
4628         destStyle
.SetRightIndent(style
.GetRightIndent()); 
4630     if (style
.HasParagraphSpacingAfter()) 
4631         destStyle
.SetParagraphSpacingAfter(style
.GetParagraphSpacingAfter()); 
4633     if (style
.HasParagraphSpacingBefore()) 
4634         destStyle
.SetParagraphSpacingBefore(style
.GetParagraphSpacingBefore()); 
4636     if (style
.HasLineSpacing()) 
4637         destStyle
.SetLineSpacing(style
.GetLineSpacing()); 
4639     if (style
.HasCharacterStyleName()) 
4640         destStyle
.SetCharacterStyleName(style
.GetCharacterStyleName()); 
4642     if (style
.HasParagraphStyleName()) 
4643         destStyle
.SetParagraphStyleName(style
.GetParagraphStyleName()); 
4645     if (style
.HasBulletStyle()) 
4647         destStyle
.SetBulletStyle(style
.GetBulletStyle()); 
4648         destStyle
.SetBulletSymbol(style
.GetBulletSymbol()); 
4651     if (style
.HasBulletNumber()) 
4652         destStyle
.SetBulletNumber(style
.GetBulletNumber()); 
4659  * wxRichTextAttr stores attributes without a wxFont object, so is a much more 
4660  * efficient way to query styles. 
4664 wxRichTextAttr::wxRichTextAttr(const wxColour
& colText
, 
4665                const wxColour
& colBack
, 
4666                wxTextAttrAlignment alignment
): m_textAlignment(alignment
), m_colText(colText
), m_colBack(colBack
) 
4670     if (m_colText
.Ok()) m_flags 
|= wxTEXT_ATTR_TEXT_COLOUR
; 
4671     if (m_colBack
.Ok()) m_flags 
|= wxTEXT_ATTR_BACKGROUND_COLOUR
; 
4672     if (alignment 
!= wxTEXT_ALIGNMENT_DEFAULT
) 
4673         m_flags 
|= wxTEXT_ATTR_ALIGNMENT
; 
4676 wxRichTextAttr::wxRichTextAttr(const wxTextAttrEx
& attr
) 
4684 void wxRichTextAttr::Init() 
4686     m_textAlignment 
= wxTEXT_ALIGNMENT_DEFAULT
; 
4689     m_leftSubIndent 
= 0; 
4693     m_fontStyle 
= wxNORMAL
; 
4694     m_fontWeight 
= wxNORMAL
; 
4695     m_fontUnderlined 
= false; 
4697     m_paragraphSpacingAfter 
= 0; 
4698     m_paragraphSpacingBefore 
= 0; 
4700     m_bulletStyle 
= wxTEXT_ATTR_BULLET_STYLE_NONE
; 
4702     m_bulletSymbol 
= wxT('*'); 
4706 void wxRichTextAttr::operator= (const wxRichTextAttr
& attr
) 
4708     m_colText 
= attr
.m_colText
; 
4709     m_colBack 
= attr
.m_colBack
; 
4710     m_textAlignment 
= attr
.m_textAlignment
; 
4711     m_leftIndent 
= attr
.m_leftIndent
; 
4712     m_leftSubIndent 
= attr
.m_leftSubIndent
; 
4713     m_rightIndent 
= attr
.m_rightIndent
; 
4714     m_tabs 
= attr
.m_tabs
; 
4715     m_flags 
= attr
.m_flags
; 
4717     m_fontSize 
= attr
.m_fontSize
; 
4718     m_fontStyle 
= attr
.m_fontStyle
; 
4719     m_fontWeight 
= attr
.m_fontWeight
; 
4720     m_fontUnderlined 
= attr
.m_fontUnderlined
; 
4721     m_fontFaceName 
= attr
.m_fontFaceName
; 
4723     m_paragraphSpacingAfter 
= attr
.m_paragraphSpacingAfter
; 
4724     m_paragraphSpacingBefore 
= attr
.m_paragraphSpacingBefore
; 
4725     m_lineSpacing 
= attr
.m_lineSpacing
; 
4726     m_characterStyleName 
= attr
.m_characterStyleName
; 
4727     m_paragraphStyleName 
= attr
.m_paragraphStyleName
; 
4728     m_bulletStyle 
= attr
.m_bulletStyle
; 
4729     m_bulletNumber 
= attr
.m_bulletNumber
; 
4730     m_bulletSymbol 
= attr
.m_bulletSymbol
; 
4734 void wxRichTextAttr::operator= (const wxTextAttrEx
& attr
) 
4736     m_colText 
= attr
.GetTextColour(); 
4737     m_colBack 
= attr
.GetBackgroundColour(); 
4738     m_textAlignment 
= attr
.GetAlignment(); 
4739     m_leftIndent 
= attr
.GetLeftIndent(); 
4740     m_leftSubIndent 
= attr
.GetLeftSubIndent(); 
4741     m_rightIndent 
= attr
.GetRightIndent(); 
4742     m_tabs 
= attr
.GetTabs(); 
4743     m_flags 
= attr
.GetFlags(); 
4745     m_paragraphSpacingAfter 
= attr
.GetParagraphSpacingAfter(); 
4746     m_paragraphSpacingBefore 
= attr
.GetParagraphSpacingBefore(); 
4747     m_lineSpacing 
= attr
.GetLineSpacing(); 
4748     m_characterStyleName 
= attr
.GetCharacterStyleName(); 
4749     m_paragraphStyleName 
= attr
.GetParagraphStyleName(); 
4751     if (attr
.GetFont().Ok()) 
4752         GetFontAttributes(attr
.GetFont()); 
4755 // Making a wxTextAttrEx object. 
4756 wxRichTextAttr::operator wxTextAttrEx () const 
4763 // Copy to a wxTextAttr 
4764 void wxRichTextAttr::CopyTo(wxTextAttrEx
& attr
) const 
4766     attr
.SetTextColour(GetTextColour()); 
4767     attr
.SetBackgroundColour(GetBackgroundColour()); 
4768     attr
.SetAlignment(GetAlignment()); 
4769     attr
.SetTabs(GetTabs()); 
4770     attr
.SetLeftIndent(GetLeftIndent(), GetLeftSubIndent()); 
4771     attr
.SetRightIndent(GetRightIndent()); 
4772     attr
.SetFont(CreateFont()); 
4773     attr
.SetFlags(GetFlags()); // Important: set after SetFont, since SetFont sets flags 
4775     attr
.SetParagraphSpacingAfter(m_paragraphSpacingAfter
); 
4776     attr
.SetParagraphSpacingBefore(m_paragraphSpacingBefore
); 
4777     attr
.SetLineSpacing(m_lineSpacing
); 
4778     attr
.SetBulletStyle(m_bulletStyle
); 
4779     attr
.SetBulletNumber(m_bulletNumber
); 
4780     attr
.SetBulletSymbol(m_bulletSymbol
); 
4781     attr
.SetCharacterStyleName(m_characterStyleName
); 
4782     attr
.SetParagraphStyleName(m_paragraphStyleName
); 
4786 // Create font from font attributes. 
4787 wxFont 
wxRichTextAttr::CreateFont() const 
4789     wxFont 
font(m_fontSize
, wxDEFAULT
, m_fontStyle
, m_fontWeight
, m_fontUnderlined
, m_fontFaceName
); 
4791     font
.SetNoAntiAliasing(true); 
4796 // Get attributes from font. 
4797 bool wxRichTextAttr::GetFontAttributes(const wxFont
& font
) 
4802     m_fontSize 
= font
.GetPointSize(); 
4803     m_fontStyle 
= font
.GetStyle(); 
4804     m_fontWeight 
= font
.GetWeight(); 
4805     m_fontUnderlined 
= font
.GetUnderlined(); 
4806     m_fontFaceName 
= font
.GetFaceName(); 
4812  * wxTextAttrEx is an extended version of wxTextAttr with more paragraph attributes. 
4815 wxTextAttrEx::wxTextAttrEx(const wxTextAttrEx
& attr
): wxTextAttr(attr
) 
4817     m_paragraphSpacingAfter 
= attr
.m_paragraphSpacingAfter
; 
4818     m_paragraphSpacingBefore 
= attr
.m_paragraphSpacingBefore
; 
4819     m_lineSpacing 
= attr
.m_lineSpacing
; 
4820     m_paragraphStyleName 
= attr
.m_paragraphStyleName
; 
4821     m_characterStyleName 
= attr
.m_characterStyleName
; 
4822     m_bulletStyle 
= attr
.m_bulletStyle
; 
4823     m_bulletNumber 
= attr
.m_bulletNumber
; 
4824     m_bulletSymbol 
= attr
.m_bulletSymbol
; 
4827 // Initialise this object. 
4828 void wxTextAttrEx::Init() 
4830     m_paragraphSpacingAfter 
= 0; 
4831     m_paragraphSpacingBefore 
= 0; 
4833     m_bulletStyle 
= wxTEXT_ATTR_BULLET_STYLE_NONE
; 
4836     m_bulletSymbol 
= wxT('*'); 
4839 // Assignment from a wxTextAttrEx object 
4840 void wxTextAttrEx::operator= (const wxTextAttrEx
& attr
) 
4842     wxTextAttr::operator= (attr
); 
4844     m_paragraphSpacingAfter 
= attr
.m_paragraphSpacingAfter
; 
4845     m_paragraphSpacingBefore 
= attr
.m_paragraphSpacingBefore
; 
4846     m_lineSpacing 
= attr
.m_lineSpacing
; 
4847     m_characterStyleName 
= attr
.m_characterStyleName
; 
4848     m_paragraphStyleName 
= attr
.m_paragraphStyleName
; 
4849     m_bulletStyle 
= attr
.m_bulletStyle
; 
4850     m_bulletNumber 
= attr
.m_bulletNumber
; 
4851     m_bulletSymbol 
= attr
.m_bulletSymbol
; 
4854 // Assignment from a wxTextAttr object. 
4855 void wxTextAttrEx::operator= (const wxTextAttr
& attr
) 
4857     wxTextAttr::operator= (attr
); 
4861  * wxRichTextFileHandler 
4862  * Base class for file handlers 
4865 IMPLEMENT_CLASS(wxRichTextFileHandler
, wxObject
) 
4868 bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer 
*buffer
, const wxString
& filename
) 
4870     wxFFileInputStream 
stream(filename
); 
4872         return LoadFile(buffer
, stream
); 
4877 bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer 
*buffer
, const wxString
& filename
) 
4879     wxFFileOutputStream 
stream(filename
); 
4881         return SaveFile(buffer
, stream
); 
4885 #endif // wxUSE_STREAMS 
4887 /// Can we handle this filename (if using files)? By default, checks the extension. 
4888 bool wxRichTextFileHandler::CanHandle(const wxString
& filename
) const 
4890     wxString path
, file
, ext
; 
4891     wxSplitPath(filename
, & path
, & file
, & ext
); 
4893     return (ext
.Lower() == GetExtension()); 
4897  * wxRichTextTextHandler 
4898  * Plain text handler 
4901 IMPLEMENT_CLASS(wxRichTextPlainTextHandler
, wxRichTextFileHandler
) 
4904 bool wxRichTextPlainTextHandler::DoLoadFile(wxRichTextBuffer 
*buffer
, wxInputStream
& stream
) 
4912     while (!stream
.Eof()) 
4914         int ch 
= stream
.GetC(); 
4918             if (ch 
== 10 && lastCh 
!= 13) 
4921             if (ch 
> 0 && ch 
!= 10) 
4929     buffer
->AddParagraphs(str
); 
4930     buffer
->UpdateRanges(); 
4936 bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer 
*buffer
, wxOutputStream
& stream
) 
4941     wxString text 
= buffer
->GetText(); 
4942     wxCharBuffer buf 
= text
.ToAscii(); 
4944     stream
.Write((const char*) buf
, text
.Length()); 
4947 #endif // wxUSE_STREAMS 
4950  * Stores information about an image, in binary in-memory form 
4953 wxRichTextImageBlock::wxRichTextImageBlock() 
4958 wxRichTextImageBlock::wxRichTextImageBlock(const wxRichTextImageBlock
& block
):wxObject() 
4964 wxRichTextImageBlock::~wxRichTextImageBlock() 
4973 void wxRichTextImageBlock::Init() 
4980 void wxRichTextImageBlock::Clear() 
4989 // Load the original image into a memory block. 
4990 // If the image is not a JPEG, we must convert it into a JPEG 
4991 // to conserve space. 
4992 // If it's not a JPEG we can make use of 'image', already scaled, so we don't have to 
4993 // load the image a 2nd time. 
4995 bool wxRichTextImageBlock::MakeImageBlock(const wxString
& filename
, int imageType
, wxImage
& image
, bool convertToJPEG
) 
4997     m_imageType 
= imageType
; 
4999     wxString 
filenameToRead(filename
); 
5000     bool removeFile 
= false; 
5002     if (imageType 
== -1) 
5003         return false; // Could not determine image type 
5005     if ((imageType 
!= wxBITMAP_TYPE_JPEG
) && convertToJPEG
) 
5008         bool success 
= wxGetTempFileName(_("image"), tempFile
) ; 
5012         wxUnusedVar(success
); 
5014         image
.SaveFile(tempFile
, wxBITMAP_TYPE_JPEG
); 
5015         filenameToRead 
= tempFile
; 
5018         m_imageType 
= wxBITMAP_TYPE_JPEG
; 
5021     if (!file
.Open(filenameToRead
)) 
5024     m_dataSize 
= (size_t) file
.Length(); 
5029     m_data 
= ReadBlock(filenameToRead
, m_dataSize
); 
5032         wxRemoveFile(filenameToRead
); 
5034     return (m_data 
!= NULL
); 
5037 // Make an image block from the wxImage in the given 
5039 bool wxRichTextImageBlock::MakeImageBlock(wxImage
& image
, int imageType
, int quality
) 
5041     m_imageType 
= imageType
; 
5042     image
.SetOption(wxT("quality"), quality
); 
5044     if (imageType 
== -1) 
5045         return false; // Could not determine image type 
5048     bool success 
= wxGetTempFileName(_("image"), tempFile
) ; 
5051     wxUnusedVar(success
); 
5053     if (!image
.SaveFile(tempFile
, m_imageType
)) 
5055         if (wxFileExists(tempFile
)) 
5056             wxRemoveFile(tempFile
); 
5061     if (!file
.Open(tempFile
)) 
5064     m_dataSize 
= (size_t) file
.Length(); 
5069     m_data 
= ReadBlock(tempFile
, m_dataSize
); 
5071     wxRemoveFile(tempFile
); 
5073     return (m_data 
!= NULL
); 
5078 bool wxRichTextImageBlock::Write(const wxString
& filename
) 
5080     return WriteBlock(filename
, m_data
, m_dataSize
); 
5083 void wxRichTextImageBlock::Copy(const wxRichTextImageBlock
& block
) 
5085     m_imageType 
= block
.m_imageType
; 
5091     m_dataSize 
= block
.m_dataSize
; 
5092     if (m_dataSize 
== 0) 
5095     m_data 
= new unsigned char[m_dataSize
]; 
5097     for (i 
= 0; i 
< m_dataSize
; i
++) 
5098         m_data
[i
] = block
.m_data
[i
]; 
5102 void wxRichTextImageBlock::operator=(const wxRichTextImageBlock
& block
) 
5107 // Load a wxImage from the block 
5108 bool wxRichTextImageBlock::Load(wxImage
& image
) 
5113     // Read in the image. 
5115     wxMemoryInputStream 
mstream(m_data
, m_dataSize
); 
5116     bool success 
= image
.LoadFile(mstream
, GetImageType()); 
5119     bool success 
= wxGetTempFileName(_("image"), tempFile
) ; 
5122     if (!WriteBlock(tempFile
, m_data
, m_dataSize
)) 
5126     success 
= image
.LoadFile(tempFile
, GetImageType()); 
5127     wxRemoveFile(tempFile
); 
5133 // Write data in hex to a stream 
5134 bool wxRichTextImageBlock::WriteHex(wxOutputStream
& stream
) 
5138     for (i 
= 0; i 
< (int) m_dataSize
; i
++) 
5140         hex 
= wxDecToHex(m_data
[i
]); 
5141         wxCharBuffer buf 
= hex
.ToAscii(); 
5143         stream
.Write((const char*) buf
, hex
.Length()); 
5149 // Read data in hex from a stream 
5150 bool wxRichTextImageBlock::ReadHex(wxInputStream
& stream
, int length
, int imageType
) 
5152     int dataSize 
= length
/2; 
5157     wxString 
str(wxT("  ")); 
5158     m_data 
= new unsigned char[dataSize
]; 
5160     for (i 
= 0; i 
< dataSize
; i 
++) 
5162         str
[0] = stream
.GetC(); 
5163         str
[1] = stream
.GetC(); 
5165         m_data
[i
] = (unsigned char)wxHexToDec(str
); 
5168     m_dataSize 
= dataSize
; 
5169     m_imageType 
= imageType
; 
5175 // Allocate and read from stream as a block of memory 
5176 unsigned char* wxRichTextImageBlock::ReadBlock(wxInputStream
& stream
, size_t size
) 
5178     unsigned char* block 
= new unsigned char[size
]; 
5182     stream
.Read(block
, size
); 
5187 unsigned char* wxRichTextImageBlock::ReadBlock(const wxString
& filename
, size_t size
) 
5189     wxFileInputStream 
stream(filename
); 
5193     return ReadBlock(stream
, size
); 
5196 // Write memory block to stream 
5197 bool wxRichTextImageBlock::WriteBlock(wxOutputStream
& stream
, unsigned char* block
, size_t size
) 
5199     stream
.Write((void*) block
, size
); 
5200     return stream
.IsOk(); 
5204 // Write memory block to file 
5205 bool wxRichTextImageBlock::WriteBlock(const wxString
& filename
, unsigned char* block
, size_t size
) 
5207     wxFileOutputStream 
outStream(filename
); 
5208     if (!outStream
.Ok()) 
5211     return WriteBlock(outStream
, block
, size
);