1 ///////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/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/dataobj.h" 
  28     #include "wx/module.h" 
  31 #include "wx/settings.h" 
  32 #include "wx/filename.h" 
  33 #include "wx/clipbrd.h" 
  34 #include "wx/wfstream.h" 
  35 #include "wx/mstream.h" 
  36 #include "wx/sstream.h" 
  37 #include "wx/textfile.h" 
  38 #include "wx/hashmap.h" 
  39 #include "wx/dynarray.h" 
  41 #include "wx/richtext/richtextctrl.h" 
  42 #include "wx/richtext/richtextstyles.h" 
  43 #include "wx/richtext/richtextimagedlg.h" 
  44 #include "wx/richtext/richtextsizepage.h" 
  46 #include "wx/listimpl.cpp" 
  47 #include "wx/arrimpl.cpp" 
  49 WX_DEFINE_LIST(wxRichTextObjectList
) 
  50 WX_DEFINE_LIST(wxRichTextLineList
) 
  52 // Switch off if the platform doesn't like it for some reason 
  53 #define wxRICHTEXT_USE_OPTIMIZED_DRAWING 1 
  55 // Use GetPartialTextExtents for platforms that support it natively 
  56 #define wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 1 
  58 const wxChar wxRichTextLineBreakChar 
= (wxChar
) 29; 
  60 // Helper classes for floating layout 
  61 struct wxRichTextFloatRectMap
 
  63     wxRichTextFloatRectMap(int sY
, int eY
, int w
, wxRichTextObject
* obj
) 
  73     wxRichTextObject
* anchor
; 
  76 WX_DEFINE_SORTED_ARRAY(wxRichTextFloatRectMap
*, wxRichTextFloatRectMapArray
); 
  78 int wxRichTextFloatRectMapCmp(wxRichTextFloatRectMap
* r1
, wxRichTextFloatRectMap
* r2
) 
  80     return r1
->startY 
- r2
->startY
; 
  83 class wxRichTextFloatCollector
 
  86     wxRichTextFloatCollector(const wxRect
& availableRect
); 
  87     ~wxRichTextFloatCollector(); 
  89     // Collect the floating objects info in the given paragraph 
  90     void CollectFloat(wxRichTextParagraph
* para
); 
  91     void CollectFloat(wxRichTextParagraph
* para
, wxRichTextObject
* floating
); 
  93     // Return the last paragraph we collected 
  94     wxRichTextParagraph
* LastParagraph(); 
  96     // Given the start y position and the height of the line, 
  97     // find out how wide the line can be 
  98     wxRect 
GetAvailableRect(int startY
, int endY
); 
 100     // Given a floating box, find its fit position 
 101     int GetFitPosition(int direction
, int start
, int height
) const; 
 102     int GetFitPosition(const wxRichTextFloatRectMapArray
& array
, int start
, int height
) const; 
 104     // Find the last y position 
 105     int GetLastRectBottom(); 
 107     // Draw the floats inside a rect 
 108     void Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
); 
 110     // HitTest the floats 
 111     int HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, int flags
); 
 113     // Get floating object count 
 114     int GetFloatingObjectCount() const { return m_left
.GetCount() + m_right
.GetCount(); } 
 116     // Get floating objects 
 117     bool GetFloatingObjects(wxRichTextObjectList
& objects
) const; 
 120     bool DeleteFloat(wxRichTextObject
* obj
); 
 122     // Do we have this float already? 
 123     bool HasFloat(wxRichTextObject
* obj
); 
 125     bool HasFloats() const { return m_left
.GetCount() >0 || m_right
.GetCount() > 0; } 
 127     static int SearchAdjacentRect(const wxRichTextFloatRectMapArray
& array
, int point
); 
 129     static int GetWidthFromFloatRect(const wxRichTextFloatRectMapArray
& array
, int index
, int startY
, int endY
); 
 131     static void FreeFloatRectMapArray(wxRichTextFloatRectMapArray
& array
); 
 133     static void DrawFloat(const wxRichTextFloatRectMapArray
& array
, wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
); 
 135     static int HitTestFloat(const wxRichTextFloatRectMapArray
& array
, wxDC
& WXUNUSED(dc
), const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, int flags
); 
 138     wxRichTextFloatRectMapArray m_left
; 
 139     wxRichTextFloatRectMapArray m_right
; 
 141     wxRect               m_availableRect
; 
 142     wxRichTextParagraph
* m_para
; 
 146 bool wxRichTextFloatCollector::DeleteFloat(wxRichTextObject
* obj
) 
 149     for (i 
= 0; i 
< m_left
.GetCount(); i
++) 
 151         if (m_left
[i
]->anchor 
== obj
) 
 157     for (i 
= 0; i 
< m_right
.GetCount(); i
++) 
 159         if (m_right
[i
]->anchor 
== obj
) 
 168 // Do we have this float already? 
 169 bool wxRichTextFloatCollector::HasFloat(wxRichTextObject
* obj
) 
 172     for (i 
= 0; i 
< m_left
.GetCount(); i
++) 
 174         if (m_left
[i
]->anchor 
== obj
) 
 179     for (i 
= 0; i 
< m_right
.GetCount(); i
++) 
 181         if (m_right
[i
]->anchor 
== obj
) 
 189 // Get floating objects 
 190 bool wxRichTextFloatCollector::GetFloatingObjects(wxRichTextObjectList
& objects
) const 
 193     for (i 
= 0; i 
< m_left
.GetCount(); i
++) 
 194         objects
.Append(m_left
[i
]->anchor
); 
 195     for (i 
= 0; i 
< m_right
.GetCount(); i
++) 
 196         objects
.Append(m_right
[i
]->anchor
); 
 202  * Binary search helper function 
 203  * The argument point is the Y coordinate, and this fuction 
 204  * always return the floating rect that contain this coordinate 
 205  * or under this coordinate. 
 207 int wxRichTextFloatCollector::SearchAdjacentRect(const wxRichTextFloatRectMapArray
& array
, int point
) 
 209     int end 
= array
.GetCount() - 1; 
 222         int mid 
= (start 
+ end
) / 2; 
 223         if (array
[mid
]->startY 
<= point 
&& array
[mid
]->endY 
>= point
) 
 225         else if (array
[mid
]->startY 
> point
) 
 230         else if (array
[mid
]->endY 
< point
) 
 240 int wxRichTextFloatCollector::GetWidthFromFloatRect(const wxRichTextFloatRectMapArray
& array
, int index
, int startY
, int endY
) 
 243     int len 
= array
.GetCount(); 
 245     wxASSERT(index 
>= 0 && index 
< len
); 
 247     if (array
[index
]->startY 
< startY 
&& array
[index
]->endY 
> startY
) 
 248         ret 
= ret 
< array
[index
]->width 
? array
[index
]->width 
: ret
; 
 249     while (index 
< len 
&& array
[index
]->startY 
<= endY
) 
 251         ret 
= ret 
< array
[index
]->width 
? array
[index
]->width 
: ret
; 
 258 wxRichTextFloatCollector::wxRichTextFloatCollector(const wxRect
& rect
) : m_left(wxRichTextFloatRectMapCmp
), m_right(wxRichTextFloatRectMapCmp
) 
 260     m_availableRect 
= rect
; 
 264 void wxRichTextFloatCollector::FreeFloatRectMapArray(wxRichTextFloatRectMapArray
& array
) 
 266     int len 
= array
.GetCount(); 
 267     for (int i 
= 0; i 
< len
; i
++) 
 271 wxRichTextFloatCollector::~wxRichTextFloatCollector() 
 273     FreeFloatRectMapArray(m_left
); 
 274     FreeFloatRectMapArray(m_right
); 
 277 int wxRichTextFloatCollector::GetFitPosition(const wxRichTextFloatRectMapArray
& array
, int start
, int height
) const 
 279     if (array
.GetCount() == 0) 
 282     int i 
= SearchAdjacentRect(array
, start
); 
 284     while (i 
< (int) array
.GetCount()) 
 286         if (array
[i
]->startY 
- last 
>= height
) 
 288         last 
= array
[i
]->endY
; 
 295 int wxRichTextFloatCollector::GetFitPosition(int direction
, int start
, int height
) const 
 297     if (direction 
== wxTEXT_BOX_ATTR_FLOAT_LEFT
) 
 298         return GetFitPosition(m_left
, start
, height
); 
 299     else if (direction 
== wxTEXT_BOX_ATTR_FLOAT_RIGHT
) 
 300         return GetFitPosition(m_right
, start
, height
); 
 303         wxASSERT("Never should be here"); 
 308 // Adds a floating image to the float collector. 
 309 // The actual positioning is done by wxRichTextParagraph::LayoutFloat. 
 310 void wxRichTextFloatCollector::CollectFloat(wxRichTextParagraph
* para
, wxRichTextObject
* floating
) 
 312     int direction 
= floating
->GetFloatDirection(); 
 314     wxPoint pos 
= floating
->GetPosition(); 
 315     wxSize size 
= floating
->GetCachedSize(); 
 316     wxRichTextFloatRectMap 
*map 
= new wxRichTextFloatRectMap(pos
.y
, pos
.y 
+ size
.y
, size
.x
, floating
); 
 319         case wxTEXT_BOX_ATTR_FLOAT_NONE
: 
 322         case wxTEXT_BOX_ATTR_FLOAT_LEFT
: 
 323             // Just a not-enough simple assertion 
 324             wxASSERT (m_left
.Index(map
) == wxNOT_FOUND
); 
 327         case wxTEXT_BOX_ATTR_FLOAT_RIGHT
: 
 328             wxASSERT (m_right
.Index(map
) == wxNOT_FOUND
); 
 333             wxASSERT("Unrecognised float attribute."); 
 339 void wxRichTextFloatCollector::CollectFloat(wxRichTextParagraph
* para
) 
 341     wxRichTextObjectList::compatibility_iterator node 
= para
->GetChildren().GetFirst(); 
 344         wxRichTextObject
* floating 
= node
->GetData(); 
 346         if (floating
->IsFloating()) 
 348             CollectFloat(para
, floating
); 
 351         node 
= node
->GetNext(); 
 357 wxRichTextParagraph
* wxRichTextFloatCollector::LastParagraph() 
 362 wxRect 
wxRichTextFloatCollector::GetAvailableRect(int startY
, int endY
) 
 364     int widthLeft 
= 0, widthRight 
= 0; 
 365     if (m_left
.GetCount() != 0) 
 367         int i 
= SearchAdjacentRect(m_left
, startY
); 
 368         if (i 
< (int) m_left
.GetCount()) 
 369             widthLeft 
= GetWidthFromFloatRect(m_left
, i
, startY
, endY
); 
 371     if (m_right
.GetCount() != 0) 
 373         int j 
= SearchAdjacentRect(m_right
, startY
); 
 374         if (j 
< (int) m_right
.GetCount()) 
 375             widthRight 
= GetWidthFromFloatRect(m_right
, j
, startY
, endY
); 
 378     // TODO: actually we want to use the actual image positions to find the 
 379     // available remaining space, since the image might not be right up against 
 380     // the left or right edge of the container. 
 381     return wxRect(widthLeft 
+ m_availableRect
.x
, 0, m_availableRect
.width 
- widthLeft 
- widthRight
, 0); 
 384 int wxRichTextFloatCollector::GetLastRectBottom() 
 387     int len 
= m_left
.GetCount(); 
 389         ret 
= ret 
> m_left
[len
-1]->endY 
? ret 
: m_left
[len
-1]->endY
; 
 391     len 
= m_right
.GetCount(); 
 393         ret 
= ret 
> m_right
[len
-1]->endY 
? ret 
: m_right
[len
-1]->endY
; 
 399 void wxRichTextFloatCollector::DrawFloat(const wxRichTextFloatRectMapArray
& array
, wxDC
& dc
, const wxRichTextRange
& WXUNUSED(range
), const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
 402     int end 
= rect
.y 
+ rect
.height
; 
 404     i 
= SearchAdjacentRect(array
, start
); 
 405     if (i 
< 0 || i 
>= (int) array
.GetCount()) 
 407     j 
= SearchAdjacentRect(array
, end
); 
 408     if (j 
< 0 || j 
>= (int) array
.GetCount()) 
 409         j 
= array
.GetCount() - 1; 
 412         wxRichTextObject
* obj 
= array
[i
]->anchor
; 
 413         wxRichTextRange r 
= obj
->GetRange(); 
 414         obj
->Draw(dc
, r
, selection
, wxRect(obj
->GetPosition(), obj
->GetCachedSize()), descent
, style
); 
 419 void wxRichTextFloatCollector::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
 421     if (m_left
.GetCount() > 0) 
 422         DrawFloat(m_left
, dc
, range
, selection
, rect
, descent
, style
); 
 423     if (m_right
.GetCount() > 0) 
 424         DrawFloat(m_right
, dc
, range
, selection
, rect
, descent
, style
); 
 427 int wxRichTextFloatCollector::HitTestFloat(const wxRichTextFloatRectMapArray
& array
, wxDC
& WXUNUSED(dc
), const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, int WXUNUSED(flags
)) 
 430     if (array
.GetCount() == 0) 
 431         return wxRICHTEXT_HITTEST_NONE
; 
 432     i 
= SearchAdjacentRect(array
, pt
.y
); 
 433     if (i 
< 0 || i 
>= (int) array
.GetCount()) 
 434         return wxRICHTEXT_HITTEST_NONE
; 
 435     if (!array
[i
]->anchor
->IsShown()) 
 436         return wxRICHTEXT_HITTEST_NONE
; 
 438     wxPoint point 
= array
[i
]->anchor
->GetPosition(); 
 439     wxSize size 
= array
[i
]->anchor
->GetCachedSize(); 
 440     if (point
.x 
<= pt
.x 
&& point
.x 
+ size
.x 
>= pt
.x
 
 441         && point
.y 
<= pt
.y 
&& point
.y 
+ size
.y 
>= pt
.y
) 
 443         textPosition 
= array
[i
]->anchor
->GetRange().GetStart(); 
 444         * obj 
= array
[i
]->anchor
; 
 445         if (pt
.x 
> (pt
.x 
+ pt
.x 
+ size
.x
) / 2) 
 446             return wxRICHTEXT_HITTEST_BEFORE
; 
 448             return wxRICHTEXT_HITTEST_AFTER
; 
 451     return wxRICHTEXT_HITTEST_NONE
; 
 454 int wxRichTextFloatCollector::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, int flags
) 
 456     int ret 
= HitTestFloat(m_left
, dc
, pt
, textPosition
, obj
, flags
); 
 457     if (ret 
== wxRICHTEXT_HITTEST_NONE
) 
 459         ret 
= HitTestFloat(m_right
, dc
, pt
, textPosition
, obj
, flags
); 
 464 // Helpers for efficiency 
 465 inline void wxCheckSetFont(wxDC
& dc
, const wxFont
& font
) 
 467     // JACS: did I do this some time ago when testing? Should we re-enable it? 
 469     const wxFont
& font1 
= dc
.GetFont(); 
 470     if (font1
.IsOk() && font
.IsOk()) 
 472         if (font1
.GetPointSize() == font
.GetPointSize() && 
 473             font1
.GetFamily() == font
.GetFamily() && 
 474             font1
.GetStyle() == font
.GetStyle() && 
 475             font1
.GetWeight() == font
.GetWeight() && 
 476             font1
.GetUnderlined() == font
.GetUnderlined() && 
 477             font1
.GetFamily() == font
.GetFamily() && 
 478             font1
.GetFaceName() == font
.GetFaceName()) 
 485 inline void wxCheckSetPen(wxDC
& dc
, const wxPen
& pen
) 
 487     const wxPen
& pen1 
= dc
.GetPen(); 
 488     if (pen1
.IsOk() && pen
.IsOk()) 
 490         if (pen1
.GetWidth() == pen
.GetWidth() && 
 491             pen1
.GetStyle() == pen
.GetStyle() && 
 492             pen1
.GetColour() == pen
.GetColour()) 
 498 inline void wxCheckSetBrush(wxDC
& dc
, const wxBrush
& brush
) 
 500     const wxBrush
& brush1 
= dc
.GetBrush(); 
 501     if (brush1
.IsOk() && brush
.IsOk()) 
 503         if (brush1
.GetStyle() == brush
.GetStyle() && 
 504             brush1
.GetColour() == brush
.GetColour()) 
 512  * This is the base for drawable objects. 
 515 IMPLEMENT_CLASS(wxRichTextObject
, wxObject
) 
 517 wxRichTextObject::wxRichTextObject(wxRichTextObject
* parent
) 
 525 wxRichTextObject::~wxRichTextObject() 
 529 void wxRichTextObject::Dereference() 
 537 void wxRichTextObject::Copy(const wxRichTextObject
& obj
) 
 540     m_maxSize 
= obj
.m_maxSize
; 
 541     m_minSize 
= obj
.m_minSize
; 
 543     m_range 
= obj
.m_range
; 
 544     m_ownRange 
= obj
.m_ownRange
; 
 545     m_attributes 
= obj
.m_attributes
; 
 546     m_properties 
= obj
.m_properties
; 
 547     m_descent 
= obj
.m_descent
; 
 551 // Get/set the top-level container of this object. 
 552 wxRichTextParagraphLayoutBox
* wxRichTextObject::GetContainer() const 
 554     const wxRichTextObject
* p 
= this; 
 559             return wxDynamicCast(p
, wxRichTextParagraphLayoutBox
); 
 566 void wxRichTextObject::SetMargins(int margin
) 
 568     SetMargins(margin
, margin
, margin
, margin
); 
 571 void wxRichTextObject::SetMargins(int leftMargin
, int rightMargin
, int topMargin
, int bottomMargin
) 
 573     GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().SetValue(leftMargin
, wxTEXT_ATTR_UNITS_PIXELS
); 
 574     GetAttributes().GetTextBoxAttr().GetMargins().GetRight().SetValue(rightMargin
, wxTEXT_ATTR_UNITS_PIXELS
); 
 575     GetAttributes().GetTextBoxAttr().GetMargins().GetTop().SetValue(topMargin
, wxTEXT_ATTR_UNITS_PIXELS
); 
 576     GetAttributes().GetTextBoxAttr().GetMargins().GetBottom().SetValue(bottomMargin
, wxTEXT_ATTR_UNITS_PIXELS
); 
 579 int wxRichTextObject::GetLeftMargin() const 
 581     return GetAttributes().GetTextBoxAttr().GetMargins().GetLeft().GetValue(); 
 584 int wxRichTextObject::GetRightMargin() const 
 586     return GetAttributes().GetTextBoxAttr().GetMargins().GetRight().GetValue(); 
 589 int wxRichTextObject::GetTopMargin() const 
 591     return GetAttributes().GetTextBoxAttr().GetMargins().GetTop().GetValue(); 
 594 int wxRichTextObject::GetBottomMargin() const 
 596     return GetAttributes().GetTextBoxAttr().GetMargins().GetBottom().GetValue(); 
 599 // Calculate the available content space in the given rectangle, given the 
 600 // margins, border and padding specified in the object's attributes. 
 601 wxRect 
wxRichTextObject::GetAvailableContentArea(wxDC
& dc
, const wxRect
& outerRect
) const 
 603     wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
 604     marginRect 
= outerRect
; 
 605     GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
 609 // Invalidate the buffer. With no argument, invalidates whole buffer. 
 610 void wxRichTextObject::Invalidate(const wxRichTextRange
& invalidRange
) 
 612     if (invalidRange 
!= wxRICHTEXT_NONE
) 
 614         SetCachedSize(wxDefaultSize
); 
 615         SetMaxSize(wxDefaultSize
); 
 616         SetMinSize(wxDefaultSize
); 
 620 // Convert units in tenths of a millimetre to device units 
 621 int wxRichTextObject::ConvertTenthsMMToPixels(wxDC
& dc
, int units
) const 
 626         scale 
= GetBuffer()->GetScale(); 
 627     int p 
= ConvertTenthsMMToPixels(dc
.GetPPI().x
, units
, scale
); 
 632 // Convert units in tenths of a millimetre to device units 
 633 int wxRichTextObject::ConvertTenthsMMToPixels(int ppi
, int units
, double scale
) 
 635     // There are ppi pixels in 254.1 "1/10 mm" 
 637     double pixels 
= ((double) units 
* (double)ppi
) / 254.1; 
 641     // If the result is very small, make it at least one pixel in size. 
 642     if (pixels 
== 0 && units 
> 0) 
 648 // Convert units in pixels to tenths of a millimetre 
 649 int wxRichTextObject::ConvertPixelsToTenthsMM(wxDC
& dc
, int pixels
) const 
 654         scale 
= GetBuffer()->GetScale(); 
 656     return ConvertPixelsToTenthsMM(dc
.GetPPI().x
, p
, scale
); 
 659 int wxRichTextObject::ConvertPixelsToTenthsMM(int ppi
, int pixels
, double scale
) 
 661     // There are ppi pixels in 254.1 "1/10 mm" 
 663     double p 
= double(pixels
); 
 668     int units 
= int( p 
* 254.1 / (double) ppi 
); 
 672 // Draw the borders and background for the given rectangle and attributes. 
 673 // Width and height are taken to be the outer margin size, not the content. 
 674 bool wxRichTextObject::DrawBoxAttributes(wxDC
& dc
, wxRichTextBuffer
* buffer
, const wxRichTextAttr
& attr
, const wxRect
& boxRect
, int flags
) 
 676     // Assume boxRect is the area around the content 
 677     wxRect marginRect 
= boxRect
; 
 678     wxRect contentRect
, borderRect
, paddingRect
, outlineRect
; 
 680     GetBoxRects(dc
, buffer
, attr
, marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
 682     // Margin is transparent. Draw background from margin. 
 683     if (attr
.HasBackgroundColour() || (flags 
& wxRICHTEXT_DRAW_SELECTED
)) 
 686         if (flags 
& wxRICHTEXT_DRAW_SELECTED
) 
 688             // TODO: get selection colour from control? 
 689             colour 
= wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
); 
 692             colour 
= attr
.GetBackgroundColour(); 
 695         wxBrush 
brush(colour
); 
 699         dc
.DrawRectangle(marginRect
); 
 702     if (flags 
& wxRICHTEXT_DRAW_GUIDELINES
) 
 704         wxRichTextAttr editBorderAttr 
= attr
; 
 705         // TODO: make guideline colour configurable 
 706         editBorderAttr
.GetTextBoxAttr().GetBorder().SetColour(*wxLIGHT_GREY
); 
 707         editBorderAttr
.GetTextBoxAttr().GetBorder().SetWidth(1, wxTEXT_ATTR_UNITS_PIXELS
); 
 708         editBorderAttr
.GetTextBoxAttr().GetBorder().SetStyle(wxTEXT_BOX_ATTR_BORDER_SOLID
); 
 710         DrawBorder(dc
, buffer
, editBorderAttr
.GetTextBoxAttr().GetBorder(), borderRect
, flags
); 
 713     if (attr
.GetTextBoxAttr().GetBorder().IsValid()) 
 714         DrawBorder(dc
, buffer
, attr
.GetTextBoxAttr().GetBorder(), borderRect
); 
 716     if (attr
.GetTextBoxAttr().GetOutline().IsValid()) 
 717         DrawBorder(dc
, buffer
, attr
.GetTextBoxAttr().GetOutline(), outlineRect
); 
 723 bool wxRichTextObject::DrawBorder(wxDC
& dc
, wxRichTextBuffer
* buffer
, const wxTextAttrBorders
& attr
, const wxRect
& rect
, int WXUNUSED(flags
)) 
 725     int borderLeft 
= 0, borderRight 
= 0, borderTop 
= 0, borderBottom 
= 0; 
 726     wxTextAttrDimensionConverter 
converter(dc
, buffer 
? buffer
->GetScale() : 1.0); 
 728     if (attr
.GetLeft().IsValid() && attr
.GetLeft().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE
) 
 730         borderLeft 
= converter
.GetPixels(attr
.GetLeft().GetWidth()); 
 731         wxColour 
col(attr
.GetLeft().GetColour()); 
 733         // If pen width is > 1, resorts to a solid rectangle. 
 736             int penStyle 
= wxSOLID
; 
 737             if (attr
.GetLeft().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED
) 
 739             else if (attr
.GetLeft().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED
) 
 740                 penStyle 
= wxLONG_DASH
; 
 741             wxPen 
pen(col
, 1, penStyle
); 
 743             dc
.DrawLine(rect
.x
, rect
.y
, rect
.x
, rect
.y 
+ rect
.height
); 
 746         else if (borderLeft 
> 1) 
 752             dc
.DrawRectangle(rect
.x
, rect
.y
, borderLeft
, rect
.height
); 
 756     if (attr
.GetRight().IsValid() && attr
.GetRight().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE
) 
 758         borderRight 
= converter
.GetPixels(attr
.GetRight().GetWidth()); 
 760         wxColour 
col(attr
.GetRight().GetColour()); 
 762         // If pen width is > 1, resorts to a solid rectangle. 
 763         if (borderRight 
== 1) 
 765             int penStyle 
= wxSOLID
; 
 766             if (attr
.GetRight().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED
) 
 768             else if (attr
.GetRight().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED
) 
 769                 penStyle 
= wxLONG_DASH
; 
 770             wxPen 
pen(col
, 1, penStyle
); 
 772             dc
.DrawLine(rect
.x 
+ rect
.width
, rect
.y
, rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height 
+ 1); 
 775         else if (borderRight 
> 1) 
 781             dc
.DrawRectangle(rect
.x 
- borderRight
, rect
.y
, borderRight
, rect
.height
); 
 785     if (attr
.GetTop().IsValid() && attr
.GetTop().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE
) 
 787         borderTop 
= converter
.GetPixels(attr
.GetTop().GetWidth()); 
 789         wxColour 
col(attr
.GetTop().GetColour()); 
 791         // If pen width is > 1, resorts to a solid rectangle. 
 794             int penStyle 
= wxSOLID
; 
 795             if (attr
.GetTop().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED
) 
 797             else if (attr
.GetTop().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED
) 
 798                 penStyle 
= wxLONG_DASH
; 
 799             wxPen 
pen(col
, 1, penStyle
); 
 801             dc
.DrawLine(rect
.x
, rect
.y
, rect
.x 
+ rect
.width
, rect
.y
); 
 804         else if (borderTop 
> 1) 
 810             dc
.DrawRectangle(rect
.x
, rect
.y
, rect
.width
, borderTop
); 
 814     if (attr
.GetBottom().IsValid() && attr
.GetBottom().GetStyle() != wxTEXT_BOX_ATTR_BORDER_NONE
) 
 816         borderBottom 
= converter
.GetPixels(attr
.GetBottom().GetWidth()); 
 817         wxColour 
col(attr
.GetTop().GetColour()); 
 819         // If pen width is > 1, resorts to a solid rectangle. 
 820         if (borderBottom 
== 1) 
 822             int penStyle 
= wxSOLID
; 
 823             if (attr
.GetBottom().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DOTTED
) 
 825             else if (attr
.GetBottom().GetStyle() == wxTEXT_BOX_ATTR_BORDER_DASHED
) 
 826                 penStyle 
= wxLONG_DASH
; 
 827             wxPen 
pen(col
, 1, penStyle
); 
 829             dc
.DrawLine(rect
.x
, rect
.y 
+ rect
.height
, rect
.x 
+ rect
.width
, rect
.y 
+ rect
.height
); 
 832         else if (borderBottom 
> 1) 
 838             dc
.DrawRectangle(rect
.x
, rect
.y 
- rect
.height 
- borderBottom
, rect
.width
, borderBottom
); 
 845 // Get the various rectangles of the box model in pixels. You can either specify contentRect (inner) 
 846 // or marginRect (outer), and the other must be the default rectangle (no width or height). 
 847 // Note that the outline doesn't affect the position of the rectangle, it's drawn in whatever space 
 850 // | Margin | Border | Padding | CONTENT | Padding | Border | Margin | 
 852 bool wxRichTextObject::GetBoxRects(wxDC
& dc
, wxRichTextBuffer
* buffer
, const wxRichTextAttr
& attr
, wxRect
& marginRect
, wxRect
& borderRect
, wxRect
& contentRect
, wxRect
& paddingRect
, wxRect
& outlineRect
) 
 854     int borderLeft 
= 0, borderRight 
= 0, borderTop 
= 0, borderBottom 
= 0; 
 855     int outlineLeft 
= 0, outlineRight 
= 0, outlineTop 
= 0, outlineBottom 
= 0; 
 856     int paddingLeft 
= 0, paddingRight 
= 0, paddingTop 
= 0, paddingBottom 
= 0; 
 857     int marginLeft 
= 0, marginRight 
= 0, marginTop 
= 0, marginBottom 
= 0; 
 859     wxTextAttrDimensionConverter 
converter(dc
, buffer 
? buffer
->GetScale() : 1.0); 
 861     if (attr
.GetTextBoxAttr().GetMargins().GetLeft().IsValid()) 
 862         marginLeft 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetMargins().GetLeft()); 
 863     if (attr
.GetTextBoxAttr().GetMargins().GetRight().IsValid()) 
 864         marginRight 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetMargins().GetRight()); 
 865     if (attr
.GetTextBoxAttr().GetMargins().GetTop().IsValid()) 
 866         marginTop 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetMargins().GetTop()); 
 867     if (attr
.GetTextBoxAttr().GetMargins().GetLeft().IsValid()) 
 868         marginBottom 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetMargins().GetBottom()); 
 870     if (attr
.GetTextBoxAttr().GetBorder().GetLeft().GetWidth().IsValid()) 
 871         borderLeft 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetBorder().GetLeft().GetWidth()); 
 872     if (attr
.GetTextBoxAttr().GetBorder().GetRight().GetWidth().IsValid()) 
 873         borderRight 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetBorder().GetRight().GetWidth()); 
 874     if (attr
.GetTextBoxAttr().GetBorder().GetTop().GetWidth().IsValid()) 
 875         borderTop 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetBorder().GetTop().GetWidth()); 
 876     if (attr
.GetTextBoxAttr().GetBorder().GetLeft().GetWidth().IsValid()) 
 877         borderBottom 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetBorder().GetBottom().GetWidth()); 
 879     if (attr
.GetTextBoxAttr().GetPadding().GetLeft().IsValid()) 
 880         paddingLeft 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetPadding().GetLeft()); 
 881     if (attr
.GetTextBoxAttr().GetPadding().GetRight().IsValid()) 
 882         paddingRight 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetPadding().GetRight()); 
 883     if (attr
.GetTextBoxAttr().GetPadding().GetTop().IsValid()) 
 884         paddingTop 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetPadding().GetTop()); 
 885     if (attr
.GetTextBoxAttr().GetPadding().GetBottom().IsValid()) 
 886         paddingBottom 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetPadding().GetBottom()); 
 888     if (attr
.GetTextBoxAttr().GetOutline().GetLeft().GetWidth().IsValid()) 
 889         outlineLeft 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetOutline().GetLeft().GetWidth()); 
 890     if (attr
.GetTextBoxAttr().GetOutline().GetRight().GetWidth().IsValid()) 
 891         outlineRight 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetOutline().GetRight().GetWidth()); 
 892     if (attr
.GetTextBoxAttr().GetOutline().GetTop().GetWidth().IsValid()) 
 893         outlineTop 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetOutline().GetTop().GetWidth()); 
 894     if (attr
.GetTextBoxAttr().GetOutline().GetBottom().GetWidth().IsValid()) 
 895         outlineBottom 
= converter
.GetPixels(attr
.GetTextBoxAttr().GetOutline().GetBottom().GetWidth()); 
 897     int leftTotal 
= marginLeft 
+ borderLeft 
+ paddingLeft
; 
 898     int rightTotal 
= marginRight 
+ borderRight 
+ paddingRight
; 
 899     int topTotal 
= marginTop 
+ borderTop 
+ paddingTop
; 
 900     int bottomTotal 
= marginBottom 
+ borderBottom 
+ paddingBottom
; 
 902     if (marginRect 
!= wxRect()) 
 904         contentRect
.x 
= marginRect
.x 
+ leftTotal
; 
 905         contentRect
.y 
= marginRect
.y 
+ topTotal
; 
 906         contentRect
.width 
= marginRect
.width 
- (leftTotal 
+ rightTotal
); 
 907         contentRect
.height 
= marginRect
.height 
- (topTotal 
+ bottomTotal
); 
 911         marginRect
.x 
= contentRect
.x 
- leftTotal
; 
 912         marginRect
.y 
= contentRect
.y 
- topTotal
; 
 913         marginRect
.width 
= contentRect
.width 
+ (leftTotal 
+ rightTotal
); 
 914         marginRect
.height 
= contentRect
.height 
+ (topTotal 
+ bottomTotal
); 
 917     borderRect
.x 
= marginRect
.x 
+ marginLeft
; 
 918     borderRect
.y 
= marginRect
.y 
+ marginTop
; 
 919     borderRect
.width 
= marginRect
.width 
- (marginLeft 
+ marginRight
); 
 920     borderRect
.height 
= marginRect
.height 
- (marginTop 
+ marginBottom
); 
 922     paddingRect
.x 
= marginRect
.x 
+ marginLeft 
+ borderLeft
; 
 923     paddingRect
.y 
= marginRect
.y 
+ marginTop 
+ borderTop
; 
 924     paddingRect
.width 
= marginRect
.width 
- (marginLeft 
+ marginRight 
+ borderLeft 
+ borderRight
); 
 925     paddingRect
.height 
= marginRect
.height 
- (marginTop 
+ marginBottom 
+ borderTop 
+ borderBottom
); 
 927     // The outline is outside the margin and doesn't influence the overall box position or content size. 
 928     outlineRect
.x 
= marginRect
.x 
- outlineLeft
; 
 929     outlineRect
.y 
= marginRect
.y 
- outlineTop
; 
 930     outlineRect
.width 
= marginRect
.width 
+ (outlineLeft 
+ outlineRight
); 
 931     outlineRect
.height 
= marginRect
.height 
+ (outlineTop 
+ outlineBottom
); 
 936 // Get the total margin for the object in pixels, taking into account margin, padding and border size 
 937 bool wxRichTextObject::GetTotalMargin(wxDC
& dc
, wxRichTextBuffer
* buffer
, const wxRichTextAttr
& attr
, int& leftMargin
, int& rightMargin
, 
 938         int& topMargin
, int& bottomMargin
) 
 940     // Assume boxRect is the area around the content 
 941     wxRect contentRect
, marginRect
, borderRect
, paddingRect
, outlineRect
; 
 942     marginRect 
= wxRect(0, 0, 1000, 1000); 
 944     GetBoxRects(dc
, buffer
, attr
, marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
 946     leftMargin 
= contentRect
.GetLeft() - marginRect
.GetLeft(); 
 947     rightMargin 
= marginRect
.GetRight() - contentRect
.GetRight(); 
 948     topMargin 
= contentRect
.GetTop() - marginRect
.GetTop(); 
 949     bottomMargin 
= marginRect
.GetBottom() - contentRect
.GetBottom(); 
 954 // Returns the rectangle which the child has available to it given restrictions specified in the 
 955 // child attribute, e.g. 50% width of the parent, 400 pixels, x position 20% of the parent, etc. 
 956 wxRect 
wxRichTextObject::AdjustAvailableSpace(wxDC
& dc
, wxRichTextBuffer
* buffer
, const wxRichTextAttr
& WXUNUSED(parentAttr
), const wxRichTextAttr
& childAttr
, const wxRect
& availableParentSpace
) 
 958     wxRect rect 
= availableParentSpace
; 
 961         scale 
= buffer
->GetScale(); 
 963     wxTextAttrDimensionConverter 
converter(dc
, scale
, availableParentSpace
.GetSize()); 
 965     if (childAttr
.GetTextBoxAttr().GetWidth().IsValid()) 
 966         rect
.width 
= converter
.GetPixels(childAttr
.GetTextBoxAttr().GetWidth()); 
 968     if (childAttr
.GetTextBoxAttr().GetHeight().IsValid()) 
 969         rect
.height 
= converter
.GetPixels(childAttr
.GetTextBoxAttr().GetHeight()); 
 971     // Can specify either left or right for the position (we're assuming we can't 
 972     // set the left and right edges to effectively set the size. Would we want to do that?) 
 973     if (childAttr
.GetTextBoxAttr().GetPosition().GetLeft().IsValid()) 
 975         rect
.x 
= rect
.x 
+ converter
.GetPixels(childAttr
.GetTextBoxAttr().GetPosition().GetLeft()); 
 977     else if (childAttr
.GetTextBoxAttr().GetPosition().GetRight().IsValid()) 
 979         int x 
= converter
.GetPixels(childAttr
.GetTextBoxAttr().GetPosition().GetRight()); 
 980         if (childAttr
.GetTextBoxAttr().GetPosition().GetRight().GetPosition() == wxTEXT_BOX_ATTR_POSITION_RELATIVE
) 
 981             rect
.x 
= availableParentSpace
.x 
+ availableParentSpace
.width 
- rect
.width
; 
 986     if (childAttr
.GetTextBoxAttr().GetPosition().GetTop().IsValid()) 
 988         rect
.y 
= rect
.y 
+ converter
.GetPixels(childAttr
.GetTextBoxAttr().GetPosition().GetTop()); 
 990     else if (childAttr
.GetTextBoxAttr().GetPosition().GetBottom().IsValid()) 
 992         int y 
= converter
.GetPixels(childAttr
.GetTextBoxAttr().GetPosition().GetBottom()); 
 993         if (childAttr
.GetTextBoxAttr().GetPosition().GetBottom().GetPosition() == wxTEXT_BOX_ATTR_POSITION_RELATIVE
) 
 994             rect
.y 
= availableParentSpace
.y 
+ availableParentSpace
.height 
- rect
.height
; 
1002 // Dump to output stream for debugging 
1003 void wxRichTextObject::Dump(wxTextOutputStream
& stream
) 
1005     stream 
<< GetClassInfo()->GetClassName() << wxT("\n"); 
1006     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"); 
1007     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"); 
1010 // Gets the containing buffer 
1011 wxRichTextBuffer
* wxRichTextObject::GetBuffer() const 
1013     const wxRichTextObject
* obj 
= this; 
1014     while (obj 
&& !obj
->IsKindOf(CLASSINFO(wxRichTextBuffer
))) 
1015         obj 
= obj
->GetParent(); 
1016     return wxDynamicCast(obj
, wxRichTextBuffer
); 
1019 // Get the absolute object position, by traversing up the child/parent hierarchy 
1020 wxPoint 
wxRichTextObject::GetAbsolutePosition() const 
1022     wxPoint pt 
= GetPosition(); 
1024     wxRichTextObject
* p 
= GetParent(); 
1027         pt 
= pt 
+ p
->GetPosition(); 
1034 // Hit-testing: returns a flag indicating hit test details, plus 
1035 // information about position 
1036 int wxRichTextObject::HitTest(wxDC
& WXUNUSED(dc
), const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, wxRichTextObject
** contextObj
, int WXUNUSED(flags
)) 
1039         return wxRICHTEXT_HITTEST_NONE
; 
1041     wxRect rect 
= GetRect(); 
1042     if (pt
.x 
>= rect
.x 
&& pt
.x 
< rect
.x 
+ rect
.width 
&& 
1043         pt
.y 
>= rect
.y 
&& pt
.y 
< rect
.y 
+ rect
.height
) 
1046         *contextObj 
= GetParentContainer(); 
1047         textPosition 
= GetRange().GetStart(); 
1048         return wxRICHTEXT_HITTEST_ON
; 
1051         return wxRICHTEXT_HITTEST_NONE
; 
1054 // Lays out the object first with a given amount of space, and then if no width was specified in attr, 
1055 // lays out the object again using the maximum ('best') size 
1056 bool wxRichTextObject::LayoutToBestSize(wxDC
& dc
, wxRichTextBuffer
* buffer
, 
1057     const wxRichTextAttr
& parentAttr
, const wxRichTextAttr
& attr
, const wxRect
& availableParentSpace
, 
1060     wxRect availableChildRect 
= AdjustAvailableSpace(dc
, buffer
, parentAttr
, attr
, availableParentSpace
); 
1061     wxRect originalAvailableRect 
= availableChildRect
; 
1062     Layout(dc
, availableChildRect
, style
); 
1064     wxSize maxSize 
= GetMaxSize(); 
1066     // Don't ignore if maxSize.x is zero, since we need to redo the paragraph's lines 
1068     if (!attr
.GetTextBoxAttr().GetWidth().IsValid() && maxSize
.x 
< availableChildRect
.width 
/* && maxSize.x > 0 */) 
1070         // Redo the layout with a fixed, minimum size this time. 
1071         Invalidate(wxRICHTEXT_ALL
); 
1072         wxRichTextAttr 
newAttr(attr
); 
1073         newAttr
.GetTextBoxAttr().GetWidth().SetValue(maxSize
.x
, wxTEXT_ATTR_UNITS_PIXELS
); 
1074         newAttr
.GetTextBoxAttr().GetWidth().SetPosition(wxTEXT_BOX_ATTR_POSITION_ABSOLUTE
); 
1076         availableChildRect 
= AdjustAvailableSpace(dc
, buffer
, parentAttr
, newAttr
, availableParentSpace
); 
1078         // If a paragraph, align the whole paragraph. 
1079         // Problem with this: if we're limited by a floating object, a line may be centered 
1080         // w.r.t. the smaller resulting box rather than the actual available width. 
1081         if (attr
.HasAlignment() && !GetContainer()->GetFloatCollector()->HasFloats()) // FIXME: aligning whole paragraph not compatible with floating objects 
1083             // centering, right-justification 
1084             if (GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
1086                 availableChildRect
.x 
= (originalAvailableRect
.GetWidth() - availableChildRect
.GetWidth())/2 + availableChildRect
.x
; 
1088             else if (GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
1090                 availableChildRect
.x 
= availableChildRect
.x 
+ originalAvailableRect
.GetWidth() - availableChildRect
.GetWidth(); 
1094         Layout(dc
, availableChildRect
, style
); 
1108 // Move the object recursively, by adding the offset from old to new 
1109 void wxRichTextObject::Move(const wxPoint
& pt
) 
1116  * wxRichTextCompositeObject 
1117  * This is the base for drawable objects. 
1120 IMPLEMENT_CLASS(wxRichTextCompositeObject
, wxRichTextObject
) 
1122 wxRichTextCompositeObject::wxRichTextCompositeObject(wxRichTextObject
* parent
): 
1123     wxRichTextObject(parent
) 
1127 wxRichTextCompositeObject::~wxRichTextCompositeObject() 
1132 /// Get the nth child 
1133 wxRichTextObject
* wxRichTextCompositeObject::GetChild(size_t n
) const 
1135     wxASSERT ( n 
< m_children
.GetCount() ); 
1137     return m_children
.Item(n
)->GetData(); 
1140 /// Append a child, returning the position 
1141 size_t wxRichTextCompositeObject::AppendChild(wxRichTextObject
* child
) 
1143     m_children
.Append(child
); 
1144     child
->SetParent(this); 
1145     return m_children
.GetCount() - 1; 
1148 /// Insert the child in front of the given object, or at the beginning 
1149 bool wxRichTextCompositeObject::InsertChild(wxRichTextObject
* child
, wxRichTextObject
* inFrontOf
) 
1153         wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(inFrontOf
); 
1154         m_children
.Insert(node
, child
); 
1157         m_children
.Insert(child
); 
1158     child
->SetParent(this); 
1163 /// Delete the child 
1164 bool wxRichTextCompositeObject::RemoveChild(wxRichTextObject
* child
, bool deleteChild
) 
1166     wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(child
); 
1169         wxRichTextObject
* obj 
= node
->GetData(); 
1170         m_children
.Erase(node
); 
1179 /// Delete all children 
1180 bool wxRichTextCompositeObject::DeleteChildren() 
1182     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1185         wxRichTextObjectList::compatibility_iterator oldNode 
= node
; 
1187         wxRichTextObject
* child 
= node
->GetData(); 
1188         child
->Dereference(); // Only delete if reference count is zero 
1190         node 
= node
->GetNext(); 
1191         m_children
.Erase(oldNode
); 
1197 /// Get the child count 
1198 size_t wxRichTextCompositeObject::GetChildCount() const 
1200     return m_children
.GetCount(); 
1204 void wxRichTextCompositeObject::Copy(const wxRichTextCompositeObject
& obj
) 
1206     wxRichTextObject::Copy(obj
); 
1210     wxRichTextObjectList::compatibility_iterator node 
= obj
.m_children
.GetFirst(); 
1213         wxRichTextObject
* child 
= node
->GetData(); 
1214         wxRichTextObject
* newChild 
= child
->Clone(); 
1215         newChild
->SetParent(this); 
1216         m_children
.Append(newChild
); 
1218         node 
= node
->GetNext(); 
1222 /// Hit-testing: returns a flag indicating hit test details, plus 
1223 /// information about position 
1224 int wxRichTextCompositeObject::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, wxRichTextObject
** contextObj
, int flags
) 
1227         return wxRICHTEXT_HITTEST_NONE
; 
1229     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1232         wxRichTextObject
* child 
= node
->GetData(); 
1234         if (child
->IsShown() && child
->IsTopLevel() && (flags 
& wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
)) 
1236             // Just check if we hit the overall object 
1237             int ret 
= child
->wxRichTextObject::HitTest(dc
, pt
, textPosition
, obj
, contextObj
, flags
); 
1238             if (ret 
!= wxRICHTEXT_HITTEST_NONE
) 
1241         else if (child
->IsShown()) 
1243             int ret 
= child
->HitTest(dc
, pt
, textPosition
, obj
, contextObj
, flags
); 
1244             if (ret 
!= wxRICHTEXT_HITTEST_NONE
) 
1248         node 
= node
->GetNext(); 
1251     return wxRICHTEXT_HITTEST_NONE
; 
1254 /// Finds the absolute position and row height for the given character position 
1255 bool wxRichTextCompositeObject::FindPosition(wxDC
& dc
, long index
, wxPoint
& pt
, int* height
, bool forceLineStart
) 
1257     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1260         wxRichTextObject
* child 
= node
->GetData(); 
1262         // Don't recurse if the child is a top-level object, 
1263         // such as a text box, because the character position will no longer 
1264         // apply. By definition, a top-level object has its own range of 
1265         // character positions. 
1266         if (!child
->IsTopLevel() && child
->FindPosition(dc
, index
, pt
, height
, forceLineStart
)) 
1269         node 
= node
->GetNext(); 
1276 void wxRichTextCompositeObject::CalculateRange(long start
, long& end
) 
1278     long current 
= start
; 
1279     long lastEnd 
= current
; 
1287     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1290         wxRichTextObject
* child 
= node
->GetData(); 
1293         child
->CalculateRange(current
, childEnd
); 
1296         current 
= childEnd 
+ 1; 
1298         node 
= node
->GetNext(); 
1303         // A top-level object always has a range of size 1, 
1304         // because its children don't count at this level. 
1306         m_range
.SetRange(start
, start
); 
1308         // An object with no children has zero length 
1309         if (m_children
.GetCount() == 0) 
1311         m_ownRange
.SetRange(0, lastEnd
); 
1317         // An object with no children has zero length 
1318         if (m_children
.GetCount() == 0) 
1321         m_range
.SetRange(start
, end
); 
1325 /// Delete range from layout. 
1326 bool wxRichTextCompositeObject::DeleteRange(const wxRichTextRange
& range
) 
1328     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1332         wxRichTextObject
* obj 
= (wxRichTextObject
*) node
->GetData(); 
1333         wxRichTextObjectList::compatibility_iterator next 
= node
->GetNext(); 
1335         // Delete the range in each paragraph 
1337         // When a chunk has been deleted, internally the content does not 
1338         // now match the ranges. 
1339         // However, so long as deletion is not done on the same object twice this is OK. 
1340         // If you may delete content from the same object twice, recalculate 
1341         // the ranges inbetween DeleteRange calls by calling CalculateRanges, and 
1342         // adjust the range you're deleting accordingly. 
1344         if (!obj
->GetRange().IsOutside(range
)) 
1346             // No need to delete within a top-level object; just removing this object will do fine 
1347             if (!obj
->IsTopLevel()) 
1348                 obj
->DeleteRange(range
); 
1350             // Delete an empty object, or paragraph within this range. 
1351             if (obj
->IsEmpty() || 
1352                 (range
.GetStart() <= obj
->GetRange().GetStart() && range
.GetEnd() >= obj
->GetRange().GetEnd())) 
1354                 // An empty paragraph has length 1, so won't be deleted unless the 
1355                 // whole range is deleted. 
1356                 RemoveChild(obj
, true); 
1366 /// Get any text in this object for the given range 
1367 wxString 
wxRichTextCompositeObject::GetTextForRange(const wxRichTextRange
& range
) const 
1370     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1373         wxRichTextObject
* child 
= node
->GetData(); 
1374         wxRichTextRange childRange 
= range
; 
1375         if (!child
->GetRange().IsOutside(range
)) 
1377             childRange
.LimitTo(child
->GetRange()); 
1379             wxString childText 
= child
->GetTextForRange(childRange
); 
1383         node 
= node
->GetNext(); 
1389 /// Get the child object at the given character position 
1390 wxRichTextObject
* wxRichTextCompositeObject::GetChildAtPosition(long pos
) const 
1392     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1395         wxRichTextObject
* child 
= node
->GetData(); 
1396         if (child
->GetRange().GetStart() == pos
) 
1398         node 
= node
->GetNext(); 
1403 /// Recursively merge all pieces that can be merged. 
1404 bool wxRichTextCompositeObject::Defragment(const wxRichTextRange
& range
) 
1406     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1409         wxRichTextObject
* child 
= node
->GetData(); 
1410         if (range 
== wxRICHTEXT_ALL 
|| !child
->GetRange().IsOutside(range
)) 
1412             wxRichTextCompositeObject
* composite 
= wxDynamicCast(child
, wxRichTextCompositeObject
); 
1414                 composite
->Defragment(); 
1416             if (node
->GetNext()) 
1418                 wxRichTextObject
* nextChild 
= node
->GetNext()->GetData(); 
1419                 if (child
->CanMerge(nextChild
) && child
->Merge(nextChild
)) 
1421                     nextChild
->Dereference(); 
1422                     m_children
.Erase(node
->GetNext()); 
1424                     // Don't set node -- we'll see if we can merge again with the next 
1428                     node 
= node
->GetNext(); 
1431                 node 
= node
->GetNext(); 
1434             node 
= node
->GetNext(); 
1437     // Delete any remaining empty objects, but leave at least one empty object per composite object. 
1438     if (GetChildCount() > 1) 
1440         node 
= m_children
.GetFirst(); 
1443             wxRichTextObjectList::compatibility_iterator next 
= node
->GetNext(); 
1444             wxRichTextObject
* child 
= node
->GetData(); 
1445             if (range 
== wxRICHTEXT_ALL 
|| !child
->GetRange().IsOutside(range
)) 
1447                 if (child
->IsEmpty()) 
1449                     child
->Dereference(); 
1450                     m_children
.Erase(node
); 
1455                 node 
= node
->GetNext(); 
1462 /// Dump to output stream for debugging 
1463 void wxRichTextCompositeObject::Dump(wxTextOutputStream
& stream
) 
1465     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1468         wxRichTextObject
* child 
= node
->GetData(); 
1469         child
->Dump(stream
); 
1470         node 
= node
->GetNext(); 
1474 /// Get/set the object size for the given range. Returns false if the range 
1475 /// is invalid for this object. 
1476 bool wxRichTextCompositeObject::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
, wxPoint position
, wxArrayInt
* partialExtents
) const 
1478     if (!range
.IsWithin(GetRange())) 
1483     wxArrayInt childExtents
; 
1490     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1493         wxRichTextObject
* child 
= node
->GetData(); 
1494         if (!child
->GetRange().IsOutside(range
)) 
1496             // Floating objects have a zero size within the paragraph. 
1497             if (child
->IsFloating()) 
1502                     if (partialExtents
->GetCount() > 0) 
1503                         lastSize 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
1507                     partialExtents
->Add(0 /* zero size */ + lastSize
); 
1514                 wxRichTextRange rangeToUse 
= range
; 
1515                 rangeToUse
.LimitTo(child
->GetRange()); 
1516                 if (child
->IsTopLevel()) 
1517                     rangeToUse 
= child
->GetOwnRange(); 
1519                 int childDescent 
= 0; 
1521                 // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size, 
1522                 // but it's only going to be used after caching has taken place. 
1523                 if ((flags 
& wxRICHTEXT_HEIGHT_ONLY
) && child
->GetCachedSize().y 
!= 0) 
1525                     childDescent 
= child
->GetDescent(); 
1526                     childSize 
= child
->GetCachedSize(); 
1528                     sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
1529                     sz
.x 
+= childSize
.x
; 
1530                     descent 
= wxMax(descent
, childDescent
); 
1532                 else if (child
->GetRangeSize(rangeToUse
, childSize
, childDescent
, dc
, flags
, wxPoint(position
.x 
+ sz
.x
, position
.y
), p
)) 
1534                     sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
1535                     sz
.x 
+= childSize
.x
; 
1536                     descent 
= wxMax(descent
, childDescent
); 
1538                     if ((flags 
& wxRICHTEXT_CACHE_SIZE
) && (rangeToUse 
== child
->GetRange() || child
->IsTopLevel())) 
1540                         child
->SetCachedSize(childSize
); 
1541                         child
->SetDescent(childDescent
); 
1547                         if (partialExtents
->GetCount() > 0) 
1548                             lastSize 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
1553                         for (i 
= 0; i 
< childExtents
.GetCount(); i
++) 
1555                             partialExtents
->Add(childExtents
[i
] + lastSize
); 
1565         node 
= node
->GetNext(); 
1571 // Invalidate the buffer. With no argument, invalidates whole buffer. 
1572 void wxRichTextCompositeObject::Invalidate(const wxRichTextRange
& invalidRange
) 
1574     wxRichTextObject::Invalidate(invalidRange
); 
1576     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1579         wxRichTextObject
* child 
= node
->GetData(); 
1580         if (invalidRange 
!= wxRICHTEXT_ALL 
&& invalidRange 
!= wxRICHTEXT_NONE 
&& child
->GetRange().IsOutside(invalidRange
)) 
1584         else if (child
->IsTopLevel()) 
1586             if (invalidRange 
== wxRICHTEXT_NONE
) 
1587                 child
->Invalidate(wxRICHTEXT_NONE
); 
1589                 child
->Invalidate(wxRICHTEXT_ALL
); // All children must be invalidated if within parent range 
1592             child
->Invalidate(invalidRange
); 
1593         node 
= node
->GetNext(); 
1597 // Move the object recursively, by adding the offset from old to new 
1598 void wxRichTextCompositeObject::Move(const wxPoint
& pt
) 
1600     wxPoint oldPos 
= GetPosition(); 
1602     wxPoint offset 
= pt 
- oldPos
; 
1604     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1607         wxRichTextObject
* child 
= node
->GetData(); 
1608         wxPoint childPos 
= child
->GetPosition() + offset
; 
1609         child
->Move(childPos
); 
1610         node 
= node
->GetNext(); 
1616  * wxRichTextParagraphLayoutBox 
1617  * This box knows how to lay out paragraphs. 
1620 IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraphLayoutBox
, wxRichTextCompositeObject
) 
1622 wxRichTextParagraphLayoutBox::wxRichTextParagraphLayoutBox(wxRichTextObject
* parent
): 
1623     wxRichTextCompositeObject(parent
) 
1628 wxRichTextParagraphLayoutBox::~wxRichTextParagraphLayoutBox() 
1630     if (m_floatCollector
) 
1632         delete m_floatCollector
; 
1633         m_floatCollector 
= NULL
; 
1637 /// Initialize the object. 
1638 void wxRichTextParagraphLayoutBox::Init() 
1642     // For now, assume is the only box and has no initial size. 
1643     m_range 
= wxRichTextRange(0, -1); 
1644     m_ownRange 
= wxRichTextRange(0, -1); 
1646     m_invalidRange 
= wxRICHTEXT_ALL
; 
1649     m_partialParagraph 
= false; 
1650     m_floatCollector 
= NULL
; 
1653 void wxRichTextParagraphLayoutBox::Clear() 
1657     if (m_floatCollector
) 
1658         delete m_floatCollector
; 
1659     m_floatCollector 
= NULL
; 
1660     m_partialParagraph 
= false; 
1664 void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox
& obj
) 
1668     wxRichTextCompositeObject::Copy(obj
); 
1670     m_partialParagraph 
= obj
.m_partialParagraph
; 
1671     m_defaultAttributes 
= obj
.m_defaultAttributes
; 
1674 // Gather information about floating objects; only gather floats for those paragraphs that 
1675 // will not be formatted again due to optimization, after which floats will be gathered per-paragraph 
1677 bool wxRichTextParagraphLayoutBox::UpdateFloatingObjects(const wxRect
& availableRect
, wxRichTextObject
* untilObj
) 
1679     if (m_floatCollector 
!= NULL
) 
1680         delete m_floatCollector
; 
1681     m_floatCollector 
= new wxRichTextFloatCollector(availableRect
); 
1682     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1683     // Only gather floats up to the point we'll start formatting paragraphs. 
1684     while (untilObj 
&& node 
&& node
->GetData() != untilObj
) 
1686         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1687         wxASSERT (child 
!= NULL
); 
1689             m_floatCollector
->CollectFloat(child
); 
1690         node 
= node
->GetNext(); 
1696 // Returns the style sheet associated with the overall buffer. 
1697 wxRichTextStyleSheet
* wxRichTextParagraphLayoutBox::GetStyleSheet() const 
1699     return GetBuffer() ? GetBuffer()->GetStyleSheet() : (wxRichTextStyleSheet
*) NULL
; 
1702 // Get the number of floating objects at this level 
1703 int wxRichTextParagraphLayoutBox::GetFloatingObjectCount() const 
1705     if (m_floatCollector
) 
1706         return m_floatCollector
->GetFloatingObjectCount(); 
1711 // Get a list of floating objects 
1712 bool wxRichTextParagraphLayoutBox::GetFloatingObjects(wxRichTextObjectList
& objects
) const 
1714     if (m_floatCollector
) 
1716         return m_floatCollector
->GetFloatingObjects(objects
); 
1723 void wxRichTextParagraphLayoutBox::UpdateRanges() 
1727         start 
= GetRange().GetStart(); 
1729     CalculateRange(start
, end
); 
1733 int wxRichTextParagraphLayoutBox::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, wxRichTextObject
** contextObj
, int flags
) 
1736         return wxRICHTEXT_HITTEST_NONE
; 
1738     int ret 
= wxRICHTEXT_HITTEST_NONE
; 
1739     if (m_floatCollector 
&& (flags 
& wxRICHTEXT_HITTEST_NO_FLOATING_OBJECTS
) == 0) 
1740         ret 
= m_floatCollector
->HitTest(dc
, pt
, textPosition
, obj
, flags
); 
1742     if (ret 
== wxRICHTEXT_HITTEST_NONE
) 
1743         return wxRichTextCompositeObject::HitTest(dc
, pt
, textPosition
, obj
, contextObj
, flags
); 
1751 /// Draw the floating objects 
1752 void wxRichTextParagraphLayoutBox::DrawFloats(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
1754     if (m_floatCollector
) 
1755         m_floatCollector
->Draw(dc
, range
, selection
, rect
, descent
, style
); 
1758 void wxRichTextParagraphLayoutBox::MoveAnchoredObjectToParagraph(wxRichTextParagraph
* from
, wxRichTextParagraph
* to
, wxRichTextObject
* obj
) 
1763     from
->RemoveChild(obj
); 
1764     to
->AppendChild(obj
); 
1768 bool wxRichTextParagraphLayoutBox::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
1773     wxRect 
thisRect(GetPosition(), GetCachedSize()); 
1776     if (selection
.IsValid() && GetParentContainer() != this && selection
.WithinSelection(GetRange().GetStart(), GetParentContainer())) 
1777         flags 
|= wxRICHTEXT_DRAW_SELECTED
; 
1779     // Don't draw guidelines if at top level 
1780     int theseFlags 
= flags
; 
1782         theseFlags 
&= ~wxRICHTEXT_DRAW_GUIDELINES
; 
1783     DrawBoxAttributes(dc
, GetBuffer(), GetAttributes(), thisRect
, theseFlags
); 
1785     DrawFloats(dc
, range
, selection
, rect
, descent
, style
); 
1786     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1789         wxRichTextObject
* child 
= node
->GetData(); 
1791         if (child 
&& !child
->GetRange().IsOutside(range
)) 
1793             wxRect 
childRect(child
->GetPosition(), child
->GetCachedSize()); 
1794             wxRichTextRange childRange 
= range
; 
1795             if (child
->IsTopLevel()) 
1797                 childRange 
= child
->GetOwnRange(); 
1800             if (((style 
& wxRICHTEXT_DRAW_IGNORE_CACHE
) == 0) && childRect
.GetTop() > rect
.GetBottom()) 
1805             else if (((style 
& wxRICHTEXT_DRAW_IGNORE_CACHE
) == 0) && childRect
.GetBottom() < rect
.GetTop()) 
1810                 child
->Draw(dc
, childRange
, selection
, rect
, descent
, style
); 
1813         node 
= node
->GetNext(); 
1818 /// Lay the item out 
1819 bool wxRichTextParagraphLayoutBox::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
1821     SetPosition(rect
.GetPosition()); 
1826     wxRect availableSpace
; 
1827     bool formatRect 
= (style 
& wxRICHTEXT_LAYOUT_SPECIFIED_RECT
) == wxRICHTEXT_LAYOUT_SPECIFIED_RECT
; 
1829     // If only laying out a specific area, the passed rect has a different meaning: 
1830     // the visible part of the buffer. This is used in wxRichTextCtrl::OnSize, 
1831     // so that during a size, only the visible part will be relaid out, or 
1832     // it would take too long causing flicker. As an approximation, we assume that 
1833     // everything up to the start of the visible area is laid out correctly. 
1836         wxRect 
rect2(0, 0, rect
.width
, rect
.height
); 
1837         availableSpace 
= GetAvailableContentArea(dc
, rect2
); 
1839         // Invalidate the part of the buffer from the first visible line 
1840         // to the end. If other parts of the buffer are currently invalid, 
1841         // then they too will be taken into account if they are above 
1842         // the visible point. 
1844         wxRichTextLine
* line 
= GetLineAtYPosition(rect
.y
); 
1846             startPos 
= line
->GetAbsoluteRange().GetStart(); 
1848         Invalidate(wxRichTextRange(startPos
, GetOwnRange().GetEnd())); 
1852         availableSpace 
= GetAvailableContentArea(dc
, rect
); 
1855     int leftMargin
, rightMargin
, topMargin
, bottomMargin
; 
1856     wxRichTextObject::GetTotalMargin(dc
, GetBuffer(), GetAttributes(), leftMargin
, rightMargin
, 
1857             topMargin
, bottomMargin
); 
1862     // The maximum paragraph maximum width, so we can set the overall maximum width for this object 
1863     int maxMaxWidth 
= 0; 
1865     // The maximum paragraph minimum width, so we can set the overall minimum width for this object 
1866     int maxMinWidth 
= 0; 
1868     // If we have vertical alignment, we must recalculate everything. 
1869     bool hasVerticalAlignment 
= (GetAttributes().GetTextBoxAttr().HasVerticalAlignment() && 
1870         (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP
)); 
1872     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
1874     bool layoutAll 
= true; 
1876     // Get invalid range, rounding to paragraph start/end. 
1877     wxRichTextRange invalidRange 
= GetInvalidRange(true); 
1879     if (invalidRange 
== wxRICHTEXT_NONE 
&& !formatRect
) 
1882     if (invalidRange 
== wxRICHTEXT_ALL 
|| hasVerticalAlignment
) 
1884     else    // If we know what range is affected, start laying out from that point on. 
1885         if (invalidRange
.GetStart() >= GetOwnRange().GetStart()) 
1887         wxRichTextParagraph
* firstParagraph 
= GetParagraphAtPosition(invalidRange
.GetStart()); 
1890             wxRichTextObjectList::compatibility_iterator firstNode 
= m_children
.Find(firstParagraph
); 
1891             wxRichTextObjectList::compatibility_iterator previousNode
; 
1893                 previousNode 
= firstNode
->GetPrevious(); 
1898                     wxRichTextParagraph
* previousParagraph 
= wxDynamicCast(previousNode
->GetData(), wxRichTextParagraph
); 
1899                     availableSpace
.y 
= previousParagraph
->GetPosition().y 
+ previousParagraph
->GetCachedSize().y
; 
1902                 // Now we're going to start iterating from the first affected paragraph. 
1910     // Gather information about only those floating objects that will not be formatted, 
1911     // after which floats will be gathered per-paragraph during layout. 
1912     UpdateFloatingObjects(availableSpace
, node 
? node
->GetData() : (wxRichTextObject
*) NULL
); 
1914     // A way to force speedy rest-of-buffer layout (the 'else' below) 
1915     bool forceQuickLayout 
= false; 
1917     // First get the size of the paragraphs we won't be laying out 
1918     wxRichTextObjectList::compatibility_iterator n 
= m_children
.GetFirst(); 
1919     while (n 
&& n 
!= node
) 
1921         wxRichTextParagraph
* child 
= wxDynamicCast(n
->GetData(), wxRichTextParagraph
); 
1924             maxWidth 
= wxMax(maxWidth
, child
->GetCachedSize().x
); 
1925             maxMinWidth 
= wxMax(maxMinWidth
, child
->GetMinSize().x
); 
1926             maxMaxWidth 
= wxMax(maxMaxWidth
, child
->GetMaxSize().x
); 
1933         // Assume this box only contains paragraphs 
1935         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1936         // Unsure if this is needed 
1937         // wxCHECK_MSG( child, false, wxT("Unknown object in layout") ); 
1939         if (child 
&& child
->IsShown()) 
1941             // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines 
1942             if ( !forceQuickLayout 
&& 
1944                         child
->GetLines().IsEmpty() || 
1945                             !child
->GetRange().IsOutside(invalidRange
)) ) 
1947                 // Lays out the object first with a given amount of space, and then if no width was specified in attr, 
1948                 // lays out the object again using the minimum size 
1949                 child
->LayoutToBestSize(dc
, GetBuffer(), 
1950                         GetAttributes(), child
->GetAttributes(), availableSpace
, style
&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT
); 
1952                 // Layout must set the cached size 
1953                 availableSpace
.y 
+= child
->GetCachedSize().y
; 
1954                 maxWidth 
= wxMax(maxWidth
, child
->GetCachedSize().x
); 
1955                 maxMinWidth 
= wxMax(maxMinWidth
, child
->GetMinSize().x
); 
1956                 maxMaxWidth 
= wxMax(maxMaxWidth
, child
->GetMaxSize().x
); 
1958                 // If we're just formatting the visible part of the buffer, 
1959                 // and we're now past the bottom of the window, and we don't have any 
1960                 // floating objects (since they may cause wrapping to change for the rest of the 
1961                 // the buffer), start quick layout. 
1962                 if (!hasVerticalAlignment 
&& formatRect 
&& child
->GetPosition().y 
> rect
.GetBottom() && GetFloatingObjectCount() == 0) 
1963                     forceQuickLayout 
= true; 
1967                 // We're outside the immediately affected range, so now let's just 
1968                 // move everything up or down. This assumes that all the children have previously 
1969                 // been laid out and have wrapped line lists associated with them. 
1970                 // TODO: check all paragraphs before the affected range. 
1972                 int inc 
= availableSpace
.y 
- child
->GetPosition().y
; 
1976                     wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
1979                         if (child
->GetLines().GetCount() == 0) 
1981                             // Lays out the object first with a given amount of space, and then if no width was specified in attr, 
1982                             // lays out the object again using the minimum size 
1983                             child
->LayoutToBestSize(dc
, GetBuffer(), 
1984                                         GetAttributes(), child
->GetAttributes(), availableSpace
, style
&~wxRICHTEXT_LAYOUT_SPECIFIED_RECT
); 
1986                             //child->Layout(dc, availableChildRect, style); 
1989                             child
->Move(wxPoint(child
->GetPosition().x
, child
->GetPosition().y 
+ inc
)); 
1991                         availableSpace
.y 
+= child
->GetCachedSize().y
; 
1992                         maxWidth 
= wxMax(maxWidth
, child
->GetCachedSize().x
); 
1993                         maxMinWidth 
= wxMax(maxMinWidth
, child
->GetMinSize().x
); 
1994                         maxMaxWidth 
= wxMax(maxMaxWidth
, child
->GetMaxSize().x
); 
1997                     node 
= node
->GetNext(); 
2003         node 
= node
->GetNext(); 
2006     node 
= m_children
.GetLast(); 
2007     if (node 
&& node
->GetData()->IsShown()) 
2009         wxRichTextObject
* child 
= node
->GetData(); 
2010         // maxHeight = (child->GetPosition().y - GetPosition().y) + child->GetCachedSize().y; 
2011         maxHeight 
= child
->GetPosition().y 
- (GetPosition().y 
+ topMargin
) + child
->GetCachedSize().y
; 
2014         maxHeight 
= 0; // topMargin + bottomMargin; 
2016     // TODO: (also in para layout) should set the 
2017     // object's size to an absolute one if specified, 
2018     // but if not specified, calculate it from content. 
2020     // We need to add back the margins etc. 
2022         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
2023         contentRect 
= wxRect(wxPoint(0, 0), wxSize(maxWidth
, maxHeight
)); 
2024         GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
2025         SetCachedSize(marginRect
.GetSize()); 
2028     // The maximum size is the greatest of all maximum widths for all paragraphs. 
2030         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
2031         contentRect 
= wxRect(wxPoint(0, 0), wxSize(maxMaxWidth
, maxHeight
)); // Actually max height is a lie, we can't know it 
2032         GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
2033         SetMaxSize(marginRect
.GetSize()); 
2036     // The minimum size is the greatest of all minimum widths for all paragraphs. 
2038         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
2039         contentRect 
= wxRect(wxPoint(0, 0), wxSize(maxMinWidth
, maxHeight
)); // Actually max height is a lie, we can't know it 
2040         GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
2041         SetMinSize(marginRect
.GetSize()); 
2044     if (GetAttributes().GetTextBoxAttr().HasVerticalAlignment() && 
2045         (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() > wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_TOP
)) 
2048         int leftOverSpace 
= availableSpace
.height 
- topMargin 
- bottomMargin 
- maxHeight
; 
2049         if (leftOverSpace 
> 0) 
2051             if (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_CENTRE
) 
2053                 yOffset 
= (leftOverSpace
/2); 
2055             else if (GetAttributes().GetTextBoxAttr().GetVerticalAlignment() == wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_BOTTOM
) 
2057                 yOffset 
= leftOverSpace
; 
2061         // Move all the children to vertically align the content 
2062         // This doesn't take into account floating objects, unfortunately. 
2065             wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2068                 wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2070                     child
->Move(wxPoint(child
->GetPosition().x
, child
->GetPosition().y 
+ yOffset
)); 
2072                 node 
= node
->GetNext(); 
2077     m_invalidRange 
= wxRICHTEXT_NONE
; 
2082 /// Get/set the size for the given range. 
2083 bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
, wxPoint position
, wxArrayInt
* WXUNUSED(partialExtents
)) const 
2087     wxRichTextObjectList::compatibility_iterator startPara 
= wxRichTextObjectList::compatibility_iterator(); 
2088     wxRichTextObjectList::compatibility_iterator endPara 
= wxRichTextObjectList::compatibility_iterator(); 
2090     // First find the first paragraph whose starting position is within the range. 
2091     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2094         // child is a paragraph 
2095         wxRichTextObject
* child 
= node
->GetData(); 
2096         const wxRichTextRange
& r 
= child
->GetRange(); 
2098         if (r
.GetStart() <= range
.GetStart() && r
.GetEnd() >= range
.GetStart()) 
2104         node 
= node
->GetNext(); 
2107     // Next find the last paragraph containing part of the range 
2108     node 
= m_children
.GetFirst(); 
2111         // child is a paragraph 
2112         wxRichTextObject
* child 
= node
->GetData(); 
2113         const wxRichTextRange
& r 
= child
->GetRange(); 
2115         if (r
.GetStart() <= range
.GetEnd() && r
.GetEnd() >= range
.GetEnd()) 
2121         node 
= node
->GetNext(); 
2124     if (!startPara 
|| !endPara
) 
2127     // Now we can add up the sizes 
2128     for (node 
= startPara
; node 
; node 
= node
->GetNext()) 
2130         // child is a paragraph 
2131         wxRichTextObject
* child 
= node
->GetData(); 
2132         const wxRichTextRange
& childRange 
= child
->GetRange(); 
2133         wxRichTextRange rangeToFind 
= range
; 
2134         rangeToFind
.LimitTo(childRange
); 
2136         if (child
->IsTopLevel()) 
2137             rangeToFind 
= child
->GetOwnRange(); 
2141         int childDescent 
= 0; 
2142         child
->GetRangeSize(rangeToFind
, childSize
, childDescent
, dc
, flags
, position
); 
2144         descent 
= wxMax(childDescent
, descent
); 
2146         sz
.x 
= wxMax(sz
.x
, childSize
.x
); 
2147         sz
.y 
+= childSize
.y
; 
2149         if (node 
== endPara
) 
2158 /// Get the paragraph at the given position 
2159 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphAtPosition(long pos
, bool caretPosition
) const 
2164     // First find the first paragraph whose starting position is within the range. 
2165     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2168         // child is a paragraph 
2169         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2170         // wxASSERT (child != NULL); 
2174             // Return first child in buffer if position is -1 
2178             if (child
->GetRange().Contains(pos
)) 
2182         node 
= node
->GetNext(); 
2187 /// Get the line at the given position 
2188 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos
, bool caretPosition
) const 
2193     // First find the first paragraph whose starting position is within the range. 
2194     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2197         wxRichTextObject
* obj 
= (wxRichTextObject
*) node
->GetData(); 
2198         if (obj
->GetRange().Contains(pos
)) 
2200             // child is a paragraph 
2201             wxRichTextParagraph
* child 
= wxDynamicCast(obj
, wxRichTextParagraph
); 
2202             // wxASSERT (child != NULL); 
2206                 wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
2209                     wxRichTextLine
* line 
= node2
->GetData(); 
2211                     wxRichTextRange range 
= line
->GetAbsoluteRange(); 
2213                     if (range
.Contains(pos
) || 
2215                         // If the position is end-of-paragraph, then return the last line of 
2216                         // of the paragraph. 
2217                         ((range
.GetEnd() == child
->GetRange().GetEnd()-1) && (pos 
== child
->GetRange().GetEnd()))) 
2220                     node2 
= node2
->GetNext(); 
2225         node 
= node
->GetNext(); 
2228     int lineCount 
= GetLineCount(); 
2230         return GetLineForVisibleLineNumber(lineCount
-1); 
2235 /// Get the line at the given y pixel position, or the last line. 
2236 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineAtYPosition(int y
) const 
2238     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2241         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2242         // wxASSERT (child != NULL); 
2246             wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
2249                 wxRichTextLine
* line 
= node2
->GetData(); 
2251                 wxRect 
rect(line
->GetRect()); 
2253                 if (y 
<= rect
.GetBottom()) 
2256                 node2 
= node2
->GetNext(); 
2260         node 
= node
->GetNext(); 
2264     int lineCount 
= GetLineCount(); 
2266         return GetLineForVisibleLineNumber(lineCount
-1); 
2271 /// Get the number of visible lines 
2272 int wxRichTextParagraphLayoutBox::GetLineCount() const 
2276     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2279         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2280         // wxASSERT (child != NULL); 
2283             count 
+= child
->GetLines().GetCount(); 
2285         node 
= node
->GetNext(); 
2291 /// Get the paragraph for a given line 
2292 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphForLine(wxRichTextLine
* line
) const 
2294     return GetParagraphAtPosition(line
->GetAbsoluteRange().GetStart()); 
2297 /// Get the line size at the given position 
2298 wxSize 
wxRichTextParagraphLayoutBox::GetLineSizeAtPosition(long pos
, bool caretPosition
) const 
2300     wxRichTextLine
* line 
= GetLineAtPosition(pos
, caretPosition
); 
2303         return line
->GetSize(); 
2306         return wxSize(0, 0); 
2310 /// Convenience function to add a paragraph of text 
2311 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddParagraph(const wxString
& text
, wxRichTextAttr
* paraStyle
) 
2313     // Don't use the base style, just the default style, and the base style will 
2314     // be combined at display time. 
2315     // Divide into paragraph and character styles. 
2317     wxRichTextAttr defaultCharStyle
; 
2318     wxRichTextAttr defaultParaStyle
; 
2320     // If the default style is a named paragraph style, don't apply any character formatting 
2321     // to the initial text string. 
2322     if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet()) 
2324         wxRichTextParagraphStyleDefinition
* def 
= GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName()); 
2326             defaultParaStyle 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
2329         wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle
, defaultCharStyle
); 
2331     wxRichTextAttr
* pStyle 
= paraStyle 
? paraStyle 
: (wxRichTextAttr
*) & defaultParaStyle
; 
2332     wxRichTextAttr
* cStyle 
= & defaultCharStyle
; 
2334     wxRichTextParagraph
* para 
= new wxRichTextParagraph(text
, this, pStyle
, cStyle
); 
2340     return para
->GetRange(); 
2343 /// Adds multiple paragraphs, based on newlines. 
2344 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddParagraphs(const wxString
& text
, wxRichTextAttr
* paraStyle
) 
2346     // Don't use the base style, just the default style, and the base style will 
2347     // be combined at display time. 
2348     // Divide into paragraph and character styles. 
2350     wxRichTextAttr defaultCharStyle
; 
2351     wxRichTextAttr defaultParaStyle
; 
2353     // If the default style is a named paragraph style, don't apply any character formatting 
2354     // to the initial text string. 
2355     if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet()) 
2357         wxRichTextParagraphStyleDefinition
* def 
= GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName()); 
2359             defaultParaStyle 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
2362         wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle
, defaultCharStyle
); 
2364     wxRichTextAttr
* pStyle 
= paraStyle 
? paraStyle 
: (wxRichTextAttr
*) & defaultParaStyle
; 
2365     wxRichTextAttr
* cStyle 
= & defaultCharStyle
; 
2367     wxRichTextParagraph
* firstPara 
= NULL
; 
2368     wxRichTextParagraph
* lastPara 
= NULL
; 
2370     wxRichTextRange 
range(-1, -1); 
2373     size_t len 
= text
.length(); 
2375     wxRichTextParagraph
* para 
= new wxRichTextParagraph(wxEmptyString
, this, pStyle
, cStyle
); 
2384         wxChar ch 
= text
[i
]; 
2385         if (ch 
== wxT('\n') || ch 
== wxT('\r')) 
2389                 wxRichTextPlainText
* plainText 
= (wxRichTextPlainText
*) para
->GetChildren().GetFirst()->GetData(); 
2390                 plainText
->SetText(line
); 
2392                 para 
= new wxRichTextParagraph(wxEmptyString
, this, pStyle
, cStyle
); 
2397                 line 
= wxEmptyString
; 
2408         wxRichTextPlainText
* plainText 
= (wxRichTextPlainText
*) para
->GetChildren().GetFirst()->GetData(); 
2409         plainText
->SetText(line
); 
2414     return wxRichTextRange(firstPara
->GetRange().GetStart(), lastPara
->GetRange().GetEnd()); 
2417 /// Convenience function to add an image 
2418 wxRichTextRange 
wxRichTextParagraphLayoutBox::AddImage(const wxImage
& image
, wxRichTextAttr
* paraStyle
) 
2420     // Don't use the base style, just the default style, and the base style will 
2421     // be combined at display time. 
2422     // Divide into paragraph and character styles. 
2424     wxRichTextAttr defaultCharStyle
; 
2425     wxRichTextAttr defaultParaStyle
; 
2427     // If the default style is a named paragraph style, don't apply any character formatting 
2428     // to the initial text string. 
2429     if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet()) 
2431         wxRichTextParagraphStyleDefinition
* def 
= GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName()); 
2433             defaultParaStyle 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
2436         wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle
, defaultCharStyle
); 
2438     wxRichTextAttr
* pStyle 
= paraStyle 
? paraStyle 
: (wxRichTextAttr
*) & defaultParaStyle
; 
2439     wxRichTextAttr
* cStyle 
= & defaultCharStyle
; 
2441     wxRichTextParagraph
* para 
= new wxRichTextParagraph(this, pStyle
); 
2443     para
->AppendChild(new wxRichTextImage(image
, this, cStyle
)); 
2447     return para
->GetRange(); 
2451 /// Insert fragment into this box at the given position. If partialParagraph is true, 
2452 /// it is assumed that the last (or only) paragraph is just a piece of data with no paragraph 
2455 bool wxRichTextParagraphLayoutBox::InsertFragment(long position
, wxRichTextParagraphLayoutBox
& fragment
) 
2457     // First, find the first paragraph whose starting position is within the range. 
2458     wxRichTextParagraph
* para 
= GetParagraphAtPosition(position
); 
2461         wxRichTextAttr originalAttr 
= para
->GetAttributes(); 
2463         wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(para
); 
2465         // Now split at this position, returning the object to insert the new 
2466         // ones in front of. 
2467         wxRichTextObject
* nextObject 
= para
->SplitAt(position
); 
2469         // Special case: partial paragraph, just one paragraph. Might be a small amount of 
2470         // text, for example, so let's optimize. 
2472         if (fragment
.GetPartialParagraph() && fragment
.GetChildren().GetCount() == 1) 
2474             // Add the first para to this para... 
2475             wxRichTextObjectList::compatibility_iterator firstParaNode 
= fragment
.GetChildren().GetFirst(); 
2479             // Iterate through the fragment paragraph inserting the content into this paragraph. 
2480             wxRichTextParagraph
* firstPara 
= wxDynamicCast(firstParaNode
->GetData(), wxRichTextParagraph
); 
2481             wxASSERT (firstPara 
!= NULL
); 
2483             wxRichTextObjectList::compatibility_iterator objectNode 
= firstPara
->GetChildren().GetFirst(); 
2486                 wxRichTextObject
* newObj 
= objectNode
->GetData()->Clone(); 
2491                     para
->AppendChild(newObj
); 
2495                     // Insert before nextObject 
2496                     para
->InsertChild(newObj
, nextObject
); 
2499                 objectNode 
= objectNode
->GetNext(); 
2506             // Procedure for inserting a fragment consisting of a number of 
2509             // 1. Remove and save the content that's after the insertion point, for adding 
2510             //    back once we've added the fragment. 
2511             // 2. Add the content from the first fragment paragraph to the current 
2513             // 3. Add remaining fragment paragraphs after the current paragraph. 
2514             // 4. Add back the saved content from the first paragraph. If partialParagraph 
2515             //    is true, add it to the last paragraph added and not a new one. 
2517             // 1. Remove and save objects after split point. 
2518             wxList savedObjects
; 
2520                 para
->MoveToList(nextObject
, savedObjects
); 
2522             // 2. Add the content from the 1st fragment paragraph. 
2523             wxRichTextObjectList::compatibility_iterator firstParaNode 
= fragment
.GetChildren().GetFirst(); 
2527             wxRichTextParagraph
* firstPara 
= wxDynamicCast(firstParaNode
->GetData(), wxRichTextParagraph
); 
2528             wxASSERT(firstPara 
!= NULL
); 
2530             if (!(fragment
.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE
)) 
2531                 para
->SetAttributes(firstPara
->GetAttributes()); 
2533             // Save empty paragraph attributes for appending later 
2534             // These are character attributes deliberately set for a new paragraph. Without this, 
2535             // we couldn't pass default attributes when appending a new paragraph. 
2536             wxRichTextAttr emptyParagraphAttributes
; 
2538             wxRichTextObjectList::compatibility_iterator objectNode 
= firstPara
->GetChildren().GetFirst(); 
2540             if (objectNode 
&& firstPara
->GetChildren().GetCount() == 1 && objectNode
->GetData()->IsEmpty()) 
2541                 emptyParagraphAttributes 
= objectNode
->GetData()->GetAttributes(); 
2545                 wxRichTextObject
* newObj 
= objectNode
->GetData()->Clone(); 
2548                 para
->AppendChild(newObj
); 
2550                 objectNode 
= objectNode
->GetNext(); 
2553             // 3. Add remaining fragment paragraphs after the current paragraph. 
2554             wxRichTextObjectList::compatibility_iterator nextParagraphNode 
= node
->GetNext(); 
2555             wxRichTextObject
* nextParagraph 
= NULL
; 
2556             if (nextParagraphNode
) 
2557                 nextParagraph 
= nextParagraphNode
->GetData(); 
2559             wxRichTextObjectList::compatibility_iterator i 
= fragment
.GetChildren().GetFirst()->GetNext(); 
2560             wxRichTextParagraph
* finalPara 
= para
; 
2562             bool needExtraPara 
= (!i 
|| !fragment
.GetPartialParagraph()); 
2564             // If there was only one paragraph, we need to insert a new one. 
2567                 wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
2568                 wxASSERT( para 
!= NULL 
); 
2570                 finalPara 
= (wxRichTextParagraph
*) para
->Clone(); 
2573                     InsertChild(finalPara
, nextParagraph
); 
2575                     AppendChild(finalPara
); 
2580             // If there was only one paragraph, or we have full paragraphs in our fragment, 
2581             // we need to insert a new one. 
2584                 finalPara 
= new wxRichTextParagraph
; 
2587                     InsertChild(finalPara
, nextParagraph
); 
2589                     AppendChild(finalPara
); 
2592             // 4. Add back the remaining content. 
2596                     finalPara
->MoveFromList(savedObjects
); 
2598                 // Ensure there's at least one object 
2599                 if (finalPara
->GetChildCount() == 0) 
2601                     wxRichTextPlainText
* text 
= new wxRichTextPlainText(wxEmptyString
); 
2602                     text
->SetAttributes(emptyParagraphAttributes
); 
2604                     finalPara
->AppendChild(text
); 
2608             if ((fragment
.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE
) && firstPara
) 
2609                 finalPara
->SetAttributes(firstPara
->GetAttributes()); 
2610             else if (finalPara 
&& finalPara 
!= para
) 
2611                 finalPara
->SetAttributes(originalAttr
); 
2619         wxRichTextObjectList::compatibility_iterator i 
= fragment
.GetChildren().GetFirst(); 
2622             wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
2623             wxASSERT( para 
!= NULL 
); 
2625             AppendChild(para
->Clone()); 
2634 /// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'. 
2635 /// If there was an incomplete paragraph at the end, partialParagraph is set to true. 
2636 bool wxRichTextParagraphLayoutBox::CopyFragment(const wxRichTextRange
& range
, wxRichTextParagraphLayoutBox
& fragment
) 
2638     wxRichTextObjectList::compatibility_iterator i 
= GetChildren().GetFirst(); 
2641         wxRichTextParagraph
* para 
= wxDynamicCast(i
->GetData(), wxRichTextParagraph
); 
2642         wxASSERT( para 
!= NULL 
); 
2644         if (!para
->GetRange().IsOutside(range
)) 
2646             fragment
.AppendChild(para
->Clone()); 
2651     // Now top and tail the first and last paragraphs in our new fragment (which might be the same). 
2652     if (!fragment
.IsEmpty()) 
2654         wxRichTextParagraph
* firstPara 
= wxDynamicCast(fragment
.GetChildren().GetFirst()->GetData(), wxRichTextParagraph
); 
2655         wxASSERT( firstPara 
!= NULL 
); 
2657         wxRichTextParagraph
* lastPara 
= wxDynamicCast(fragment
.GetChildren().GetLast()->GetData(), wxRichTextParagraph
); 
2658         wxASSERT( lastPara 
!= NULL 
); 
2660         if (!firstPara 
|| !lastPara
) 
2663         bool isFragment 
= (range
.GetEnd() < lastPara
->GetRange().GetEnd()); 
2665         long firstPos 
= firstPara
->GetRange().GetStart(); 
2667         // Adjust for renumbering from zero 
2668         wxRichTextRange 
topTailRange(range
.GetStart() - firstPos
, range
.GetEnd() - firstPos
); 
2671         fragment
.CalculateRange(0, end
); 
2673         // Chop off the start of the paragraph 
2674         if (topTailRange
.GetStart() > 0) 
2676             wxRichTextRange 
r(0, topTailRange
.GetStart()-1); 
2677             firstPara
->DeleteRange(r
); 
2679             // Make sure the numbering is correct 
2680             fragment
.CalculateRange(0, end
); 
2682             // Now, we've deleted some positions, so adjust the range 
2684             topTailRange
.SetStart(range
.GetLength()); 
2685             topTailRange
.SetEnd(fragment
.GetOwnRange().GetEnd()); 
2689             topTailRange
.SetStart(range
.GetLength()); 
2690             topTailRange
.SetEnd(fragment
.GetOwnRange().GetEnd()); 
2693         if (topTailRange
.GetStart() < (lastPara
->GetRange().GetEnd()-1)) 
2695             lastPara
->DeleteRange(topTailRange
); 
2697             // Make sure the numbering is correct 
2699             fragment
.CalculateRange(0, end
); 
2701             // We only have part of a paragraph at the end 
2702             fragment
.SetPartialParagraph(true); 
2706             // We have a partial paragraph (don't save last new paragraph marker) 
2707             // or complete paragraph 
2708             fragment
.SetPartialParagraph(isFragment
); 
2715 /// Given a position, get the number of the visible line (potentially many to a paragraph), 
2716 /// starting from zero at the start of the buffer. 
2717 long wxRichTextParagraphLayoutBox::GetVisibleLineNumber(long pos
, bool caretPosition
, bool startOfLine
) const 
2724     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2727         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2728         // wxASSERT( child != NULL ); 
2732             if (child
->GetRange().Contains(pos
)) 
2734                 wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
2737                     wxRichTextLine
* line 
= node2
->GetData(); 
2738                     wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
2740                     if (lineRange
.Contains(pos
) || pos 
== lineRange
.GetStart()) 
2742                         // If the caret is displayed at the end of the previous wrapped line, 
2743                         // we want to return the line it's _displayed_ at (not the actual line 
2744                         // containing the position). 
2745                         if (lineRange
.GetStart() == pos 
&& !startOfLine 
&& child
->GetRange().GetStart() != pos
) 
2746                             return lineCount 
- 1; 
2753                     node2 
= node2
->GetNext(); 
2755                 // If we didn't find it in the lines, it must be 
2756                 // the last position of the paragraph. So return the last line. 
2760                 lineCount 
+= child
->GetLines().GetCount(); 
2763         node 
= node
->GetNext(); 
2770 /// Given a line number, get the corresponding wxRichTextLine object. 
2771 wxRichTextLine
* wxRichTextParagraphLayoutBox::GetLineForVisibleLineNumber(long lineNumber
) const 
2775     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2778         wxRichTextParagraph
* child 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2779         // wxASSERT(child != NULL); 
2783             if (lineNumber 
< (int) (child
->GetLines().GetCount() + lineCount
)) 
2785                 wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
2788                     wxRichTextLine
* line 
= node2
->GetData(); 
2790                     if (lineCount 
== lineNumber
) 
2795                     node2 
= node2
->GetNext(); 
2799                 lineCount 
+= child
->GetLines().GetCount(); 
2802         node 
= node
->GetNext(); 
2809 /// Delete range from layout. 
2810 bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange
& range
) 
2812     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2814     wxRichTextParagraph
* firstPara 
= NULL
; 
2817         wxRichTextParagraph
* obj 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
2818         // wxASSERT (obj != NULL); 
2820         wxRichTextObjectList::compatibility_iterator next 
= node
->GetNext(); 
2824             // Delete the range in each paragraph 
2826             if (!obj
->GetRange().IsOutside(range
)) 
2828                 // Deletes the content of this object within the given range 
2829                 obj
->DeleteRange(range
); 
2831                 wxRichTextRange thisRange 
= obj
->GetRange(); 
2832                 wxRichTextAttr thisAttr 
= obj
->GetAttributes(); 
2834                 // If the whole paragraph is within the range to delete, 
2835                 // delete the whole thing. 
2836                 if (range
.GetStart() <= thisRange
.GetStart() && range
.GetEnd() >= thisRange
.GetEnd()) 
2838                     // Delete the whole object 
2839                     RemoveChild(obj
, true); 
2842                 else if (!firstPara
) 
2845                 // If the range includes the paragraph end, we need to join this 
2846                 // and the next paragraph. 
2847                 if (range
.GetEnd() <= thisRange
.GetEnd()) 
2849                     // We need to move the objects from the next paragraph 
2850                     // to this paragraph 
2852                     wxRichTextParagraph
* nextParagraph 
= NULL
; 
2853                     if ((range
.GetEnd() < thisRange
.GetEnd()) && obj
) 
2854                         nextParagraph 
= obj
; 
2857                         // We're ending at the end of the paragraph, so merge the _next_ paragraph. 
2859                             nextParagraph 
= wxDynamicCast(next
->GetData(), wxRichTextParagraph
); 
2862                     bool applyFinalParagraphStyle 
= firstPara 
&& nextParagraph 
&& nextParagraph 
!= firstPara
; 
2864                     wxRichTextAttr nextParaAttr
; 
2865                     if (applyFinalParagraphStyle
) 
2867                         // Special case when deleting the end of a paragraph - use _this_ paragraph's style, 
2868                         // not the next one. 
2869                         if (range
.GetStart() == range
.GetEnd() && range
.GetStart() == thisRange
.GetEnd()) 
2870                             nextParaAttr 
= thisAttr
; 
2872                             nextParaAttr 
= nextParagraph
->GetAttributes(); 
2875                     if (firstPara 
&& nextParagraph 
&& firstPara 
!= nextParagraph
) 
2877                         // Move the objects to the previous para 
2878                         wxRichTextObjectList::compatibility_iterator node1 
= nextParagraph
->GetChildren().GetFirst(); 
2882                             wxRichTextObject
* obj1 
= node1
->GetData(); 
2884                             firstPara
->AppendChild(obj1
); 
2886                             wxRichTextObjectList::compatibility_iterator next1 
= node1
->GetNext(); 
2887                             nextParagraph
->GetChildren().Erase(node1
); 
2892                         // Delete the paragraph 
2893                         RemoveChild(nextParagraph
, true); 
2896                     // Avoid empty paragraphs 
2897                     if (firstPara 
&& firstPara
->GetChildren().GetCount() == 0) 
2899                         wxRichTextPlainText
* text 
= new wxRichTextPlainText(wxEmptyString
); 
2900                         firstPara
->AppendChild(text
); 
2903                     if (applyFinalParagraphStyle
) 
2904                         firstPara
->SetAttributes(nextParaAttr
); 
2917 /// Get any text in this object for the given range 
2918 wxString 
wxRichTextParagraphLayoutBox::GetTextForRange(const wxRichTextRange
& range
) const 
2922     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
2925         wxRichTextObject
* child 
= node
->GetData(); 
2926         if (!child
->GetRange().IsOutside(range
)) 
2928             wxRichTextRange childRange 
= range
; 
2929             childRange
.LimitTo(child
->GetRange()); 
2931             wxString childText 
= child
->GetTextForRange(childRange
); 
2935             if ((childRange
.GetEnd() == child
->GetRange().GetEnd()) && node
->GetNext()) 
2940         node 
= node
->GetNext(); 
2946 /// Get all the text 
2947 wxString 
wxRichTextParagraphLayoutBox::GetText() const 
2949     return GetTextForRange(GetOwnRange()); 
2952 /// Get the paragraph by number 
2953 wxRichTextParagraph
* wxRichTextParagraphLayoutBox::GetParagraphAtLine(long paragraphNumber
) const 
2955     if ((size_t) paragraphNumber 
>= GetChildCount()) 
2958     return (wxRichTextParagraph
*) GetChild((size_t) paragraphNumber
); 
2961 /// Get the length of the paragraph 
2962 int wxRichTextParagraphLayoutBox::GetParagraphLength(long paragraphNumber
) const 
2964     wxRichTextParagraph
* para 
= GetParagraphAtLine(paragraphNumber
); 
2966         return para
->GetRange().GetLength() - 1; // don't include newline 
2971 /// Get the text of the paragraph 
2972 wxString 
wxRichTextParagraphLayoutBox::GetParagraphText(long paragraphNumber
) const 
2974     wxRichTextParagraph
* para 
= GetParagraphAtLine(paragraphNumber
); 
2976         return para
->GetTextForRange(para
->GetRange()); 
2978         return wxEmptyString
; 
2981 /// Convert zero-based line column and paragraph number to a position. 
2982 long wxRichTextParagraphLayoutBox::XYToPosition(long x
, long y
) const 
2984     wxRichTextParagraph
* para 
= GetParagraphAtLine(y
); 
2987         return para
->GetRange().GetStart() + x
; 
2993 /// Convert zero-based position to line column and paragraph number 
2994 bool wxRichTextParagraphLayoutBox::PositionToXY(long pos
, long* x
, long* y
) const 
2996     wxRichTextParagraph
* para 
= GetParagraphAtPosition(pos
); 
3000         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3003             wxRichTextObject
* child 
= node
->GetData(); 
3007             node 
= node
->GetNext(); 
3011         *x 
= pos 
- para
->GetRange().GetStart(); 
3019 /// Get the leaf object in a paragraph at this position. 
3020 /// Given a line number, get the corresponding wxRichTextLine object. 
3021 wxRichTextObject
* wxRichTextParagraphLayoutBox::GetLeafObjectAtPosition(long position
) const 
3023     wxRichTextParagraph
* para 
= GetParagraphAtPosition(position
); 
3026         wxRichTextObjectList::compatibility_iterator node 
= para
->GetChildren().GetFirst(); 
3030             wxRichTextObject
* child 
= node
->GetData(); 
3031             if (child
->GetRange().Contains(position
)) 
3034             node 
= node
->GetNext(); 
3036         if (position 
== para
->GetRange().GetEnd() && para
->GetChildCount() > 0) 
3037             return para
->GetChildren().GetLast()->GetData(); 
3042 /// Set character or paragraph text attributes: apply character styles only to immediate text nodes 
3043 bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange
& range
, const wxRichTextAttr
& style
, int flags
) 
3045     bool characterStyle 
= false; 
3046     bool paragraphStyle 
= false; 
3048     if (style
.IsCharacterStyle()) 
3049         characterStyle 
= true; 
3050     if (style
.IsParagraphStyle()) 
3051         paragraphStyle 
= true; 
3053     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3055     bool withUndo 
= ((flags 
& wxRICHTEXT_SETSTYLE_WITH_UNDO
) != 0); 
3056     bool applyMinimal 
= ((flags 
& wxRICHTEXT_SETSTYLE_OPTIMIZE
) != 0); 
3057     bool parasOnly 
= ((flags 
& wxRICHTEXT_SETSTYLE_PARAGRAPHS_ONLY
) != 0); 
3058     bool charactersOnly 
= ((flags 
& wxRICHTEXT_SETSTYLE_CHARACTERS_ONLY
) != 0); 
3059     bool resetExistingStyle 
= ((flags 
& wxRICHTEXT_SETSTYLE_RESET
) != 0); 
3060     bool removeStyle 
= ((flags 
& wxRICHTEXT_SETSTYLE_REMOVE
) != 0); 
3062     // Apply paragraph style first, if any 
3063     wxRichTextAttr 
wholeStyle(style
); 
3065     if (!removeStyle 
&& wholeStyle
.HasParagraphStyleName() && buffer
->GetStyleSheet()) 
3067         wxRichTextParagraphStyleDefinition
* def 
= buffer
->GetStyleSheet()->FindParagraphStyle(wholeStyle
.GetParagraphStyleName()); 
3069             wxRichTextApplyStyle(wholeStyle
, def
->GetStyleMergedWithBase(buffer
->GetStyleSheet())); 
3072     // Limit the attributes to be set to the content to only character attributes. 
3073     wxRichTextAttr 
characterAttributes(wholeStyle
); 
3074     characterAttributes
.SetFlags(characterAttributes
.GetFlags() & (wxTEXT_ATTR_CHARACTER
)); 
3076     if (!removeStyle 
&& characterAttributes
.HasCharacterStyleName() && buffer
->GetStyleSheet()) 
3078         wxRichTextCharacterStyleDefinition
* def 
= buffer
->GetStyleSheet()->FindCharacterStyle(characterAttributes
.GetCharacterStyleName()); 
3080             wxRichTextApplyStyle(characterAttributes
, def
->GetStyleMergedWithBase(buffer
->GetStyleSheet())); 
3083     // If we are associated with a control, make undoable; otherwise, apply immediately 
3086     bool haveControl 
= (buffer
->GetRichTextCtrl() != NULL
); 
3088     wxRichTextAction
* action 
= NULL
; 
3090     if (haveControl 
&& withUndo
) 
3092         action 
= new wxRichTextAction(NULL
, _("Change Style"), wxRICHTEXT_CHANGE_STYLE
, buffer
, this, buffer
->GetRichTextCtrl()); 
3093         action
->SetRange(range
); 
3094         action
->SetPosition(buffer
->GetRichTextCtrl()->GetCaretPosition()); 
3097     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3100         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3101         // wxASSERT (para != NULL); 
3103         if (para 
&& para
->GetChildCount() > 0) 
3105             // Stop searching if we're beyond the range of interest 
3106             if (para
->GetRange().GetStart() > range
.GetEnd()) 
3109             if (!para
->GetRange().IsOutside(range
)) 
3111                 // We'll be using a copy of the paragraph to make style changes, 
3112                 // not updating the buffer directly. 
3113                 wxRichTextParagraph
* newPara 
wxDUMMY_INITIALIZE(NULL
); 
3115                 if (haveControl 
&& withUndo
) 
3117                     newPara 
= new wxRichTextParagraph(*para
); 
3118                     action
->GetNewParagraphs().AppendChild(newPara
); 
3120                     // Also store the old ones for Undo 
3121                     action
->GetOldParagraphs().AppendChild(new wxRichTextParagraph(*para
)); 
3126                 // If we're specifying paragraphs only, then we really mean character formatting 
3127                 // to be included in the paragraph style 
3128                 if ((paragraphStyle 
|| parasOnly
) && !charactersOnly
) 
3132                         // Removes the given style from the paragraph 
3133                         wxRichTextRemoveStyle(newPara
->GetAttributes(), style
); 
3135                     else if (resetExistingStyle
) 
3136                         newPara
->GetAttributes() = wholeStyle
; 
3141                             // Only apply attributes that will make a difference to the combined 
3142                             // style as seen on the display 
3143                             wxRichTextAttr 
combinedAttr(para
->GetCombinedAttributes(true)); 
3144                             wxRichTextApplyStyle(newPara
->GetAttributes(), wholeStyle
, & combinedAttr
); 
3147                             wxRichTextApplyStyle(newPara
->GetAttributes(), wholeStyle
); 
3151                 // When applying paragraph styles dynamically, don't change the text objects' attributes 
3152                 // since they will computed as needed. Only apply the character styling if it's _only_ 
3153                 // character styling. This policy is subject to change and might be put under user control. 
3155                 // Hm. we might well be applying a mix of paragraph and character styles, in which 
3156                 // case we _do_ want to apply character styles regardless of what para styles are set. 
3157                 // But if we're applying a paragraph style, which has some character attributes, but 
3158                 // we only want the paragraphs to hold this character style, then we _don't_ want to 
3159                 // apply the character style. So we need to be able to choose. 
3161                 if (!parasOnly 
&& (characterStyle
|charactersOnly
) && range
.GetStart() != newPara
->GetRange().GetEnd()) 
3163                     wxRichTextRange 
childRange(range
); 
3164                     childRange
.LimitTo(newPara
->GetRange()); 
3166                     // Find the starting position and if necessary split it so 
3167                     // we can start applying a different style. 
3168                     // TODO: check that the style actually changes or is different 
3169                     // from style outside of range 
3170                     wxRichTextObject
* firstObject 
wxDUMMY_INITIALIZE(NULL
); 
3171                     wxRichTextObject
* lastObject 
wxDUMMY_INITIALIZE(NULL
); 
3173                     if (childRange
.GetStart() == newPara
->GetRange().GetStart()) 
3174                         firstObject 
= newPara
->GetChildren().GetFirst()->GetData(); 
3176                         firstObject 
= newPara
->SplitAt(range
.GetStart()); 
3178                     // Increment by 1 because we're apply the style one _after_ the split point 
3179                     long splitPoint 
= childRange
.GetEnd(); 
3180                     if (splitPoint 
!= newPara
->GetRange().GetEnd()) 
3184                     if (splitPoint 
== newPara
->GetRange().GetEnd()) 
3185                         lastObject 
= newPara
->GetChildren().GetLast()->GetData(); 
3187                         // lastObject is set as a side-effect of splitting. It's 
3188                         // returned as the object before the new object. 
3189                         (void) newPara
->SplitAt(splitPoint
, & lastObject
); 
3191                     wxASSERT(firstObject 
!= NULL
); 
3192                     wxASSERT(lastObject 
!= NULL
); 
3194                     if (!firstObject 
|| !lastObject
) 
3197                     wxRichTextObjectList::compatibility_iterator firstNode 
= newPara
->GetChildren().Find(firstObject
); 
3198                     wxRichTextObjectList::compatibility_iterator lastNode 
= newPara
->GetChildren().Find(lastObject
); 
3200                     wxASSERT(firstNode
); 
3203                     wxRichTextObjectList::compatibility_iterator node2 
= firstNode
; 
3207                         wxRichTextObject
* child 
= node2
->GetData(); 
3211                             // Removes the given style from the paragraph 
3212                             wxRichTextRemoveStyle(child
->GetAttributes(), style
); 
3214                         else if (resetExistingStyle
) 
3215                             child
->GetAttributes() = characterAttributes
; 
3220                                 // Only apply attributes that will make a difference to the combined 
3221                                 // style as seen on the display 
3222                                 wxRichTextAttr 
combinedAttr(newPara
->GetCombinedAttributes(child
->GetAttributes(), true)); 
3223                                 wxRichTextApplyStyle(child
->GetAttributes(), characterAttributes
, & combinedAttr
); 
3226                                 wxRichTextApplyStyle(child
->GetAttributes(), characterAttributes
); 
3229                         if (node2 
== lastNode
) 
3232                         node2 
= node2
->GetNext(); 
3238         node 
= node
->GetNext(); 
3241     // Do action, or delay it until end of batch. 
3242     if (haveControl 
&& withUndo
) 
3243         buffer
->SubmitAction(action
); 
3248 // Just change the attributes for this single object. 
3249 void wxRichTextParagraphLayoutBox::SetStyle(wxRichTextObject
* obj
, const wxRichTextAttr
& textAttr
, int flags
) 
3251     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3252     bool withUndo 
= flags 
& wxRICHTEXT_SETSTYLE_WITH_UNDO
; 
3253     bool resetExistingStyle 
= ((flags 
& wxRICHTEXT_SETSTYLE_RESET
) != 0); 
3254     bool haveControl 
= (buffer
->GetRichTextCtrl() != NULL
); 
3256     wxRichTextAction 
*action 
= NULL
; 
3257     wxRichTextAttr newAttr 
= obj
->GetAttributes(); 
3258     if (resetExistingStyle
) 
3261         newAttr
.Apply(textAttr
); 
3263     if (haveControl 
&& withUndo
) 
3265         action 
= new wxRichTextAction(NULL
, _("Change Object Style"), wxRICHTEXT_CHANGE_ATTRIBUTES
, buffer
, obj
->GetContainer(), buffer
->GetRichTextCtrl()); 
3266         action
->SetRange(obj
->GetRange().FromInternal()); 
3267         action
->SetPosition(buffer
->GetRichTextCtrl()->GetCaretPosition()); 
3268         action
->MakeObject(obj
); 
3270         action
->GetAttributes() = newAttr
; 
3273         obj
->GetAttributes() = newAttr
; 
3275     if (haveControl 
&& withUndo
) 
3276         buffer
->SubmitAction(action
); 
3279 /// Get the text attributes for this position. 
3280 bool wxRichTextParagraphLayoutBox::GetStyle(long position
, wxRichTextAttr
& style
) 
3282     return DoGetStyle(position
, style
, true); 
3285 bool wxRichTextParagraphLayoutBox::GetUncombinedStyle(long position
, wxRichTextAttr
& style
) 
3287     return DoGetStyle(position
, style
, false); 
3290 /// Implementation helper for GetStyle. If combineStyles is true, combine base, paragraph and 
3291 /// context attributes. 
3292 bool wxRichTextParagraphLayoutBox::DoGetStyle(long position
, wxRichTextAttr
& style
, bool combineStyles
) 
3294     wxRichTextObject
* obj 
wxDUMMY_INITIALIZE(NULL
); 
3296     if (style
.IsParagraphStyle()) 
3298         obj 
= GetParagraphAtPosition(position
); 
3303                 // Start with the base style 
3304                 style 
= GetAttributes(); 
3306                 // Apply the paragraph style 
3307                 wxRichTextApplyStyle(style
, obj
->GetAttributes()); 
3310                 style 
= obj
->GetAttributes(); 
3317         obj 
= GetLeafObjectAtPosition(position
); 
3322                 wxRichTextParagraph
* para 
= wxDynamicCast(obj
->GetParent(), wxRichTextParagraph
); 
3323                 style 
= para 
? para
->GetCombinedAttributes(obj
->GetAttributes()) : obj
->GetAttributes(); 
3326                 style 
= obj
->GetAttributes(); 
3334 static bool wxHasStyle(long flags
, long style
) 
3336     return (flags 
& style
) != 0; 
3339 /// Combines 'style' with 'currentStyle' for the purpose of summarising the attributes of a range of 
3341 bool wxRichTextParagraphLayoutBox::CollectStyle(wxRichTextAttr
& currentStyle
, const wxRichTextAttr
& style
, wxRichTextAttr
& clashingAttr
, wxRichTextAttr
& absentAttr
) 
3343     currentStyle
.CollectCommonAttributes(style
, clashingAttr
, absentAttr
); 
3348 /// Get the combined style for a range - if any attribute is different within the range, 
3349 /// that attribute is not present within the flags. 
3350 /// *** Note that this is not recursive, and so assumes that content inside a paragraph is not itself 
3352 bool wxRichTextParagraphLayoutBox::GetStyleForRange(const wxRichTextRange
& range
, wxRichTextAttr
& style
) 
3354     style 
= wxRichTextAttr(); 
3356     wxRichTextAttr clashingAttr
; 
3357     wxRichTextAttr absentAttrPara
, absentAttrChar
; 
3359     wxRichTextObjectList::compatibility_iterator node 
= GetChildren().GetFirst(); 
3362         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3363         if (para 
&& !(para
->GetRange().GetStart() > range
.GetEnd() || para
->GetRange().GetEnd() < range
.GetStart())) 
3365             if (para
->GetChildren().GetCount() == 0) 
3367                 wxRichTextAttr paraStyle 
= para
->GetCombinedAttributes(true /* use box attributes */); 
3369                 CollectStyle(style
, paraStyle
, clashingAttr
, absentAttrPara
); 
3373                 wxRichTextRange 
paraRange(para
->GetRange()); 
3374                 paraRange
.LimitTo(range
); 
3376                 // First collect paragraph attributes only 
3377                 wxRichTextAttr paraStyle 
= para
->GetCombinedAttributes(); 
3378                 paraStyle
.SetFlags(paraStyle
.GetFlags() & wxTEXT_ATTR_PARAGRAPH
); 
3379                 CollectStyle(style
, paraStyle
, clashingAttr
, absentAttrPara
); 
3381                 wxRichTextObjectList::compatibility_iterator childNode 
= para
->GetChildren().GetFirst(); 
3385                     wxRichTextObject
* child 
= childNode
->GetData(); 
3386                     if (!(child
->GetRange().GetStart() > range
.GetEnd() || child
->GetRange().GetEnd() < range
.GetStart())) 
3388                         wxRichTextAttr childStyle 
= para
->GetCombinedAttributes(child
->GetAttributes(), true /* include box attributes */); 
3390                         // Now collect character attributes only 
3391                         childStyle
.SetFlags(childStyle
.GetFlags() & wxTEXT_ATTR_CHARACTER
); 
3393                         CollectStyle(style
, childStyle
, clashingAttr
, absentAttrChar
); 
3396                     childNode 
= childNode
->GetNext(); 
3400         node 
= node
->GetNext(); 
3405 /// Set default style 
3406 bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxRichTextAttr
& style
) 
3408     m_defaultAttributes 
= style
; 
3412 /// Test if this whole range has character attributes of the specified kind. If any 
3413 /// of the attributes are different within the range, the test fails. You 
3414 /// can use this to implement, for example, bold button updating. style must have 
3415 /// flags indicating which attributes are of interest. 
3416 bool wxRichTextParagraphLayoutBox::HasCharacterAttributes(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) const 
3419     int matchingCount 
= 0; 
3421     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3424         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3425         // wxASSERT (para != NULL); 
3429             // Stop searching if we're beyond the range of interest 
3430             if (para
->GetRange().GetStart() > range
.GetEnd()) 
3431                 return foundCount 
== matchingCount 
&& foundCount 
!= 0; 
3433             if (!para
->GetRange().IsOutside(range
)) 
3435                 wxRichTextObjectList::compatibility_iterator node2 
= para
->GetChildren().GetFirst(); 
3439                     wxRichTextObject
* child 
= node2
->GetData(); 
3440                     // Allow for empty string if no buffer 
3441                     wxRichTextRange childRange 
= child
->GetRange(); 
3442                     if (childRange
.GetLength() == 0 && GetRange().GetLength() == 1) 
3443                         childRange
.SetEnd(childRange
.GetEnd()+1); 
3445                     if (!childRange
.IsOutside(range
) && child
->IsKindOf(CLASSINFO(wxRichTextPlainText
))) 
3448                         wxRichTextAttr textAttr 
= para
->GetCombinedAttributes(child
->GetAttributes()); 
3450                         if (wxTextAttrEqPartial(textAttr
, style
)) 
3454                     node2 
= node2
->GetNext(); 
3459         node 
= node
->GetNext(); 
3462     return foundCount 
== matchingCount 
&& foundCount 
!= 0; 
3465 /// Test if this whole range has paragraph attributes of the specified kind. If any 
3466 /// of the attributes are different within the range, the test fails. You 
3467 /// can use this to implement, for example, centering button updating. style must have 
3468 /// flags indicating which attributes are of interest. 
3469 bool wxRichTextParagraphLayoutBox::HasParagraphAttributes(const wxRichTextRange
& range
, const wxRichTextAttr
& style
) const 
3472     int matchingCount 
= 0; 
3474     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3477         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3478         // wxASSERT (para != NULL); 
3482             // Stop searching if we're beyond the range of interest 
3483             if (para
->GetRange().GetStart() > range
.GetEnd()) 
3484                 return foundCount 
== matchingCount 
&& foundCount 
!= 0; 
3486             if (!para
->GetRange().IsOutside(range
)) 
3488                 wxRichTextAttr textAttr 
= GetAttributes(); 
3489                 // Apply the paragraph style 
3490                 wxRichTextApplyStyle(textAttr
, para
->GetAttributes()); 
3493                 if (wxTextAttrEqPartial(textAttr
, style
)) 
3498         node 
= node
->GetNext(); 
3500     return foundCount 
== matchingCount 
&& foundCount 
!= 0; 
3503 void wxRichTextParagraphLayoutBox::Reset() 
3507     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3508     if (buffer 
&& buffer
->GetRichTextCtrl()) 
3510         wxRichTextEvent 
event(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET
, buffer
->GetRichTextCtrl()->GetId()); 
3511         event
.SetEventObject(buffer
->GetRichTextCtrl()); 
3512         event
.SetContainer(this); 
3514         buffer
->SendEvent(event
, true); 
3517     AddParagraph(wxEmptyString
); 
3519     InvalidateHierarchy(wxRICHTEXT_ALL
); 
3522 /// Invalidate the buffer. With no argument, invalidates whole buffer. 
3523 void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange
& invalidRange
) 
3525     wxRichTextCompositeObject::Invalidate(invalidRange
); 
3527     DoInvalidate(invalidRange
); 
3530 // Do the (in)validation for this object only 
3531 void wxRichTextParagraphLayoutBox::DoInvalidate(const wxRichTextRange
& invalidRange
) 
3533     if (invalidRange 
== wxRICHTEXT_ALL
) 
3535         m_invalidRange 
= wxRICHTEXT_ALL
; 
3537     // Already invalidating everything 
3538     else if (m_invalidRange 
== wxRICHTEXT_ALL
) 
3543         if ((invalidRange
.GetStart() < m_invalidRange
.GetStart()) || m_invalidRange
.GetStart() == -1) 
3544             m_invalidRange
.SetStart(invalidRange
.GetStart()); 
3545         if (invalidRange
.GetEnd() > m_invalidRange
.GetEnd()) 
3546             m_invalidRange
.SetEnd(invalidRange
.GetEnd()); 
3550 // Do the (in)validation both up and down the hierarchy 
3551 void wxRichTextParagraphLayoutBox::InvalidateHierarchy(const wxRichTextRange
& invalidRange
) 
3553     Invalidate(invalidRange
); 
3555     if (invalidRange 
!= wxRICHTEXT_NONE
) 
3557         // Now go up the hierarchy 
3558         wxRichTextObject
* thisObj 
= this; 
3559         wxRichTextObject
* p 
= GetParent(); 
3562             wxRichTextParagraphLayoutBox
* l 
= wxDynamicCast(p
, wxRichTextParagraphLayoutBox
); 
3564                 l
->DoInvalidate(thisObj
->GetRange()); 
3572 /// Get invalid range, rounding to entire paragraphs if argument is true. 
3573 wxRichTextRange 
wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagraphs
) const 
3575     if (m_invalidRange 
== wxRICHTEXT_ALL 
|| m_invalidRange 
== wxRICHTEXT_NONE
) 
3576         return m_invalidRange
; 
3578     wxRichTextRange range 
= m_invalidRange
; 
3580     if (wholeParagraphs
) 
3582         wxRichTextParagraph
* para1 
= GetParagraphAtPosition(range
.GetStart()); 
3584             range
.SetStart(para1
->GetRange().GetStart()); 
3585         // floating layout make all child should be relayout 
3586         range
.SetEnd(GetOwnRange().GetEnd()); 
3591 /// Apply the style sheet to the buffer, for example if the styles have changed. 
3592 bool wxRichTextParagraphLayoutBox::ApplyStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
3594     wxASSERT(styleSheet 
!= NULL
); 
3600     wxRichTextAttr 
attr(GetBasicStyle()); 
3601     if (GetBasicStyle().HasParagraphStyleName()) 
3603         wxRichTextParagraphStyleDefinition
* paraDef 
= styleSheet
->FindParagraphStyle(GetBasicStyle().GetParagraphStyleName()); 
3606             attr
.Apply(paraDef
->GetStyleMergedWithBase(styleSheet
)); 
3607             SetBasicStyle(attr
); 
3612     if (GetBasicStyle().HasCharacterStyleName()) 
3614         wxRichTextCharacterStyleDefinition
* charDef 
= styleSheet
->FindCharacterStyle(GetBasicStyle().GetCharacterStyleName()); 
3617             attr
.Apply(charDef
->GetStyleMergedWithBase(styleSheet
)); 
3618             SetBasicStyle(attr
); 
3623     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3626         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3627         // wxASSERT (para != NULL); 
3631             // Combine paragraph and list styles. If there is a list style in the original attributes, 
3632             // the current indentation overrides anything else and is used to find the item indentation. 
3633             // Also, for applying paragraph styles, consider having 2 modes: (1) we merge with what we have, 
3634             // thereby taking into account all user changes, (2) reset the style completely (except for indentation/list 
3635             // exception as above). 
3636             // Problem: when changing from one list style to another, there's a danger that the level info will get lost. 
3637             // So when changing a list style interactively, could retrieve level based on current style, then 
3638             // set appropriate indent and apply new style. 
3642             if (para
->GetAttributes().HasOutlineLevel()) 
3643                 outline 
= para
->GetAttributes().GetOutlineLevel(); 
3644             if (para
->GetAttributes().HasBulletNumber()) 
3645                 num 
= para
->GetAttributes().GetBulletNumber(); 
3647             if (!para
->GetAttributes().GetParagraphStyleName().IsEmpty() && !para
->GetAttributes().GetListStyleName().IsEmpty()) 
3649                 int currentIndent 
= para
->GetAttributes().GetLeftIndent(); 
3651                 wxRichTextParagraphStyleDefinition
* paraDef 
= styleSheet
->FindParagraphStyle(para
->GetAttributes().GetParagraphStyleName()); 
3652                 wxRichTextListStyleDefinition
* listDef 
= styleSheet
->FindListStyle(para
->GetAttributes().GetListStyleName()); 
3653                 if (paraDef 
&& !listDef
) 
3655                     para
->GetAttributes() = paraDef
->GetStyleMergedWithBase(styleSheet
); 
3658                 else if (listDef 
&& !paraDef
) 
3660                     // Set overall style defined for the list style definition 
3661                     para
->GetAttributes() = listDef
->GetStyleMergedWithBase(styleSheet
); 
3663                     // Apply the style for this level 
3664                     wxRichTextApplyStyle(para
->GetAttributes(), * listDef
->GetLevelAttributes(listDef
->FindLevelForIndent(currentIndent
))); 
3667                 else if (listDef 
&& paraDef
) 
3669                     // Combines overall list style, style for level, and paragraph style 
3670                     para
->GetAttributes() = listDef
->CombineWithParagraphStyle(currentIndent
, paraDef
->GetStyleMergedWithBase(styleSheet
)); 
3674             else if (para
->GetAttributes().GetParagraphStyleName().IsEmpty() && !para
->GetAttributes().GetListStyleName().IsEmpty()) 
3676                 int currentIndent 
= para
->GetAttributes().GetLeftIndent(); 
3678                 wxRichTextListStyleDefinition
* listDef 
= styleSheet
->FindListStyle(para
->GetAttributes().GetListStyleName()); 
3680                 // Overall list definition style 
3681                 para
->GetAttributes() = listDef
->GetStyleMergedWithBase(styleSheet
); 
3683                 // Style for this level 
3684                 wxRichTextApplyStyle(para
->GetAttributes(), * listDef
->GetLevelAttributes(listDef
->FindLevelForIndent(currentIndent
))); 
3688             else if (!para
->GetAttributes().GetParagraphStyleName().IsEmpty() && para
->GetAttributes().GetListStyleName().IsEmpty()) 
3690                 wxRichTextParagraphStyleDefinition
* def 
= styleSheet
->FindParagraphStyle(para
->GetAttributes().GetParagraphStyleName()); 
3693                     para
->GetAttributes() = def
->GetStyleMergedWithBase(styleSheet
); 
3699                 para
->GetAttributes().SetOutlineLevel(outline
); 
3701                 para
->GetAttributes().SetBulletNumber(num
); 
3704         node 
= node
->GetNext(); 
3706     return foundCount 
!= 0; 
3710 bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3712     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3713     wxRichTextStyleSheet
* styleSheet 
= buffer
->GetStyleSheet(); 
3715     bool withUndo 
= ((flags 
& wxRICHTEXT_SETSTYLE_WITH_UNDO
) != 0); 
3716     // bool applyMinimal = ((flags & wxRICHTEXT_SETSTYLE_OPTIMIZE) != 0); 
3717     bool specifyLevel 
= ((flags 
& wxRICHTEXT_SETSTYLE_SPECIFY_LEVEL
) != 0); 
3718     bool renumber 
= ((flags 
& wxRICHTEXT_SETSTYLE_RENUMBER
) != 0); 
3720     // Current number, if numbering 
3723     wxASSERT (!specifyLevel 
|| (specifyLevel 
&& (specifiedLevel 
>= 0))); 
3725     // If we are associated with a control, make undoable; otherwise, apply immediately 
3728     bool haveControl 
= (buffer
->GetRichTextCtrl() != NULL
); 
3730     wxRichTextAction
* action 
= NULL
; 
3732     if (haveControl 
&& withUndo
) 
3734         action 
= new wxRichTextAction(NULL
, _("Change List Style"), wxRICHTEXT_CHANGE_STYLE
, buffer
, this, buffer
->GetRichTextCtrl()); 
3735         action
->SetRange(range
); 
3736         action
->SetPosition(buffer
->GetRichTextCtrl()->GetCaretPosition()); 
3739     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3742         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3743         // wxASSERT (para != NULL); 
3745         if (para 
&& para
->GetChildCount() > 0) 
3747             // Stop searching if we're beyond the range of interest 
3748             if (para
->GetRange().GetStart() > range
.GetEnd()) 
3751             if (!para
->GetRange().IsOutside(range
)) 
3753                 // We'll be using a copy of the paragraph to make style changes, 
3754                 // not updating the buffer directly. 
3755                 wxRichTextParagraph
* newPara 
wxDUMMY_INITIALIZE(NULL
); 
3757                 if (haveControl 
&& withUndo
) 
3759                     newPara 
= new wxRichTextParagraph(*para
); 
3760                     action
->GetNewParagraphs().AppendChild(newPara
); 
3762                     // Also store the old ones for Undo 
3763                     action
->GetOldParagraphs().AppendChild(new wxRichTextParagraph(*para
)); 
3770                     int thisIndent 
= newPara
->GetAttributes().GetLeftIndent(); 
3771                     int thisLevel 
= specifyLevel 
? specifiedLevel 
: def
->FindLevelForIndent(thisIndent
); 
3773                     // How is numbering going to work? 
3774                     // If we are renumbering, or numbering for the first time, we need to keep 
3775                     // track of the number for each level. But we might be simply applying a different 
3777                     // In Word, applying a style to several paragraphs, even if at different levels, 
3778                     // reverts the level back to the same one. So we could do the same here. 
3779                     // Renumbering will need to be done when we promote/demote a paragraph. 
3781                     // Apply the overall list style, and item style for this level 
3782                     wxRichTextAttr 
listStyle(def
->GetCombinedStyleForLevel(thisLevel
, styleSheet
)); 
3783                     wxRichTextApplyStyle(newPara
->GetAttributes(), listStyle
); 
3785                     // Now we need to do numbering 
3788                         newPara
->GetAttributes().SetBulletNumber(n
); 
3793                 else if (!newPara
->GetAttributes().GetListStyleName().IsEmpty()) 
3795                     // if def is NULL, remove list style, applying any associated paragraph style 
3796                     // to restore the attributes 
3798                     newPara
->GetAttributes().SetListStyleName(wxEmptyString
); 
3799                     newPara
->GetAttributes().SetLeftIndent(0, 0); 
3800                     newPara
->GetAttributes().SetBulletText(wxEmptyString
); 
3802                     // Eliminate the main list-related attributes 
3803                     newPara
->GetAttributes().SetFlags(newPara
->GetAttributes().GetFlags() & ~wxTEXT_ATTR_LEFT_INDENT 
& ~wxTEXT_ATTR_BULLET_STYLE 
& ~wxTEXT_ATTR_BULLET_NUMBER 
& ~wxTEXT_ATTR_BULLET_TEXT 
& wxTEXT_ATTR_LIST_STYLE_NAME
); 
3805                     if (styleSheet 
&& !newPara
->GetAttributes().GetParagraphStyleName().IsEmpty()) 
3807                         wxRichTextParagraphStyleDefinition
* def 
= styleSheet
->FindParagraphStyle(newPara
->GetAttributes().GetParagraphStyleName()); 
3810                             newPara
->GetAttributes() = def
->GetStyleMergedWithBase(styleSheet
); 
3817         node 
= node
->GetNext(); 
3820     // Do action, or delay it until end of batch. 
3821     if (haveControl 
&& withUndo
) 
3822         buffer
->SubmitAction(action
); 
3827 bool wxRichTextParagraphLayoutBox::SetListStyle(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
3829     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3830     if (buffer 
&& buffer
->GetStyleSheet()) 
3832         wxRichTextListStyleDefinition
* def 
= buffer
->GetStyleSheet()->FindListStyle(defName
); 
3834             return SetListStyle(range
, def
, flags
, startFrom
, specifiedLevel
); 
3839 /// Clear list for given range 
3840 bool wxRichTextParagraphLayoutBox::ClearListStyle(const wxRichTextRange
& range
, int flags
) 
3842     return SetListStyle(range
, NULL
, flags
); 
3845 /// Number/renumber any list elements in the given range 
3846 bool wxRichTextParagraphLayoutBox::NumberList(const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3848     return DoNumberList(range
, range
, 0, def
, flags
, startFrom
, specifiedLevel
); 
3851 /// Number/renumber any list elements in the given range. Also do promotion or demotion of items, if specified 
3852 bool wxRichTextParagraphLayoutBox::DoNumberList(const wxRichTextRange
& range
, const wxRichTextRange
& promotionRange
, int promoteBy
, 
3853                                                 wxRichTextListStyleDefinition
* def
, int flags
, int startFrom
, int specifiedLevel
) 
3855     wxRichTextBuffer
* buffer 
= GetBuffer(); 
3856     wxRichTextStyleSheet
* styleSheet 
= buffer
->GetStyleSheet(); 
3858     bool withUndo 
= ((flags 
& wxRICHTEXT_SETSTYLE_WITH_UNDO
) != 0); 
3859     // bool applyMinimal = ((flags & wxRICHTEXT_SETSTYLE_OPTIMIZE) != 0); 
3861     bool specifyLevel 
= ((flags 
& wxRICHTEXT_SETSTYLE_SPECIFY_LEVEL
) != 0); 
3864     bool renumber 
= ((flags 
& wxRICHTEXT_SETSTYLE_RENUMBER
) != 0); 
3866     // Max number of levels 
3867     const int maxLevels 
= 10; 
3869     // The level we're looking at now 
3870     int currentLevel 
= -1; 
3872     // The item number for each level 
3873     int levels
[maxLevels
]; 
3876     // Reset all numbering 
3877     for (i 
= 0; i 
< maxLevels
; i
++) 
3879         if (startFrom 
!= -1) 
3880             levels
[i
] = startFrom
-1; 
3881         else if (renumber
) // start again 
3884             levels
[i
] = -1; // start from the number we found, if any 
3887     wxASSERT(!specifyLevel 
|| (specifyLevel 
&& (specifiedLevel 
>= 0))); 
3889     // If we are associated with a control, make undoable; otherwise, apply immediately 
3892     bool haveControl 
= (buffer
->GetRichTextCtrl() != NULL
); 
3894     wxRichTextAction
* action 
= NULL
; 
3896     if (haveControl 
&& withUndo
) 
3898         action 
= new wxRichTextAction(NULL
, _("Renumber List"), wxRICHTEXT_CHANGE_STYLE
, buffer
, this, buffer
->GetRichTextCtrl()); 
3899         action
->SetRange(range
); 
3900         action
->SetPosition(buffer
->GetRichTextCtrl()->GetCaretPosition()); 
3903     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
3906         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
3907         // wxASSERT (para != NULL); 
3909         if (para 
&& para
->GetChildCount() > 0) 
3911             // Stop searching if we're beyond the range of interest 
3912             if (para
->GetRange().GetStart() > range
.GetEnd()) 
3915             if (!para
->GetRange().IsOutside(range
)) 
3917                 // We'll be using a copy of the paragraph to make style changes, 
3918                 // not updating the buffer directly. 
3919                 wxRichTextParagraph
* newPara 
wxDUMMY_INITIALIZE(NULL
); 
3921                 if (haveControl 
&& withUndo
) 
3923                     newPara 
= new wxRichTextParagraph(*para
); 
3924                     action
->GetNewParagraphs().AppendChild(newPara
); 
3926                     // Also store the old ones for Undo 
3927                     action
->GetOldParagraphs().AppendChild(new wxRichTextParagraph(*para
)); 
3932                 wxRichTextListStyleDefinition
* defToUse 
= def
; 
3935                     if (styleSheet 
&& !newPara
->GetAttributes().GetListStyleName().IsEmpty()) 
3936                         defToUse 
= styleSheet
->FindListStyle(newPara
->GetAttributes().GetListStyleName()); 
3941                     int thisIndent 
= newPara
->GetAttributes().GetLeftIndent(); 
3942                     int thisLevel 
= defToUse
->FindLevelForIndent(thisIndent
); 
3944                     // If we've specified a level to apply to all, change the level. 
3945                     if (specifiedLevel 
!= -1) 
3946                         thisLevel 
= specifiedLevel
; 
3948                     // Do promotion if specified 
3949                     if ((promoteBy 
!= 0) && !para
->GetRange().IsOutside(promotionRange
)) 
3951                         thisLevel 
= thisLevel 
- promoteBy
; 
3958                     // Apply the overall list style, and item style for this level 
3959                     wxRichTextAttr 
listStyle(defToUse
->GetCombinedStyleForLevel(thisLevel
, styleSheet
)); 
3960                     wxRichTextApplyStyle(newPara
->GetAttributes(), listStyle
); 
3962                     // OK, we've (re)applied the style, now let's get the numbering right. 
3964                     if (currentLevel 
== -1) 
3965                         currentLevel 
= thisLevel
; 
3967                     // Same level as before, do nothing except increment level's number afterwards 
3968                     if (currentLevel 
== thisLevel
) 
3971                     // A deeper level: start renumbering all levels after current level 
3972                     else if (thisLevel 
> currentLevel
) 
3974                         for (i 
= currentLevel
+1; i 
<= thisLevel
; i
++) 
3978                         currentLevel 
= thisLevel
; 
3980                     else if (thisLevel 
< currentLevel
) 
3982                         currentLevel 
= thisLevel
; 
3985                     // Use the current numbering if -1 and we have a bullet number already 
3986                     if (levels
[currentLevel
] == -1) 
3988                         if (newPara
->GetAttributes().HasBulletNumber()) 
3989                             levels
[currentLevel
] = newPara
->GetAttributes().GetBulletNumber(); 
3991                             levels
[currentLevel
] = 1; 
3995                         levels
[currentLevel
] ++; 
3998                     newPara
->GetAttributes().SetBulletNumber(levels
[currentLevel
]); 
4000                     // Create the bullet text if an outline list 
4001                     if (listStyle
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE
) 
4004                         for (i 
= 0; i 
<= currentLevel
; i
++) 
4006                             if (!text
.IsEmpty()) 
4008                             text 
+= wxString::Format(wxT("%d"), levels
[i
]); 
4010                         newPara
->GetAttributes().SetBulletText(text
); 
4016         node 
= node
->GetNext(); 
4019     // Do action, or delay it until end of batch. 
4020     if (haveControl 
&& withUndo
) 
4021         buffer
->SubmitAction(action
); 
4026 bool wxRichTextParagraphLayoutBox::NumberList(const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int startFrom
, int specifiedLevel
) 
4028     wxRichTextBuffer
* buffer 
= GetBuffer(); 
4029     if (buffer
->GetStyleSheet()) 
4031         wxRichTextListStyleDefinition
* def 
= NULL
; 
4032         if (!defName
.IsEmpty()) 
4033             def 
= buffer
->GetStyleSheet()->FindListStyle(defName
); 
4034         return NumberList(range
, def
, flags
, startFrom
, specifiedLevel
); 
4039 /// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1 
4040 bool wxRichTextParagraphLayoutBox::PromoteList(int promoteBy
, const wxRichTextRange
& range
, wxRichTextListStyleDefinition
* def
, int flags
, int specifiedLevel
) 
4043     // One strategy is to first work out the range within which renumbering must occur. Then could pass these two ranges 
4044     // to NumberList with a flag indicating promotion is required within one of the ranges. 
4045     // Find first and last paragraphs in range. Then for first, calculate new indentation and look back until we find 
4046     // a paragraph that either has no list style, or has one that is different or whose indentation is less. 
4047     // We start renumbering from the para after that different para we found. We specify that the numbering of that 
4048     // list position will start from 1. 
4049     // Similarly, we look after the last para in the promote range for an indentation that is less (or no list style). 
4050     // We can end the renumbering at this point. 
4052     // For now, only renumber within the promotion range. 
4054     return DoNumberList(range
, range
, promoteBy
, def
, flags
, 1, specifiedLevel
); 
4057 bool wxRichTextParagraphLayoutBox::PromoteList(int promoteBy
, const wxRichTextRange
& range
, const wxString
& defName
, int flags
, int specifiedLevel
) 
4059     wxRichTextBuffer
* buffer 
= GetBuffer(); 
4060     if (buffer
->GetStyleSheet()) 
4062         wxRichTextListStyleDefinition
* def 
= NULL
; 
4063         if (!defName
.IsEmpty()) 
4064             def 
= buffer
->GetStyleSheet()->FindListStyle(defName
); 
4065         return PromoteList(promoteBy
, range
, def
, flags
, specifiedLevel
); 
4070 /// Fills in the attributes for numbering a paragraph after previousParagraph. It also finds the 
4071 /// position of the paragraph that it had to start looking from. 
4072 bool wxRichTextParagraphLayoutBox::FindNextParagraphNumber(wxRichTextParagraph
* previousParagraph
, wxRichTextAttr
& attr
) const 
4074     if (!previousParagraph
->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE
) || previousParagraph
->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE
) 
4077     wxRichTextBuffer
* buffer 
= GetBuffer(); 
4078     wxRichTextStyleSheet
* styleSheet 
= buffer
->GetStyleSheet(); 
4079     if (styleSheet 
&& !previousParagraph
->GetAttributes().GetListStyleName().IsEmpty()) 
4081         wxRichTextListStyleDefinition
* def 
= styleSheet
->FindListStyle(previousParagraph
->GetAttributes().GetListStyleName()); 
4084             // int thisIndent = previousParagraph->GetAttributes().GetLeftIndent(); 
4085             // int thisLevel = def->FindLevelForIndent(thisIndent); 
4087             bool isOutline 
= (previousParagraph
->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE
) != 0; 
4089             attr
.SetFlags(previousParagraph
->GetAttributes().GetFlags() & (wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_BULLET_NUMBER
|wxTEXT_ATTR_BULLET_TEXT
|wxTEXT_ATTR_BULLET_NAME
)); 
4090             if (previousParagraph
->GetAttributes().HasBulletName()) 
4091                 attr
.SetBulletName(previousParagraph
->GetAttributes().GetBulletName()); 
4092             attr
.SetBulletStyle(previousParagraph
->GetAttributes().GetBulletStyle()); 
4093             attr
.SetListStyleName(previousParagraph
->GetAttributes().GetListStyleName()); 
4095             int nextNumber 
= previousParagraph
->GetAttributes().GetBulletNumber() + 1; 
4096             attr
.SetBulletNumber(nextNumber
); 
4100                 wxString text 
= previousParagraph
->GetAttributes().GetBulletText(); 
4101                 if (!text
.IsEmpty()) 
4103                     int pos 
= text
.Find(wxT('.'), true); 
4104                     if (pos 
!= wxNOT_FOUND
) 
4106                         text 
= text
.Mid(0, text
.Length() - pos 
- 1); 
4109                         text 
= wxEmptyString
; 
4110                     if (!text
.IsEmpty()) 
4112                     text 
+= wxString::Format(wxT("%d"), nextNumber
); 
4113                     attr
.SetBulletText(text
); 
4127  * wxRichTextParagraph 
4128  * This object represents a single paragraph (or in a straight text editor, a line). 
4131 IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraph
, wxRichTextCompositeObject
) 
4133 wxArrayInt 
wxRichTextParagraph::sm_defaultTabs
; 
4135 wxRichTextParagraph::wxRichTextParagraph(wxRichTextObject
* parent
, wxRichTextAttr
* style
): 
4136     wxRichTextCompositeObject(parent
) 
4139         SetAttributes(*style
); 
4142 wxRichTextParagraph::wxRichTextParagraph(const wxString
& text
, wxRichTextObject
* parent
, wxRichTextAttr
* paraStyle
, wxRichTextAttr
* charStyle
): 
4143     wxRichTextCompositeObject(parent
) 
4146         SetAttributes(*paraStyle
); 
4148     AppendChild(new wxRichTextPlainText(text
, this, charStyle
)); 
4151 wxRichTextParagraph::~wxRichTextParagraph() 
4157 bool wxRichTextParagraph::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int WXUNUSED(descent
), int style
) 
4162     // Currently we don't merge these attributes with the parent, but we 
4163     // should consider whether we should (e.g. if we set a border colour 
4164     // for all paragraphs). But generally box attributes are likely to be 
4165     // different for different objects. 
4166     wxRect paraRect 
= GetRect(); 
4167     DrawBoxAttributes(dc
, GetBuffer(), GetAttributes(), paraRect
); 
4169     wxRichTextAttr attr 
= GetCombinedAttributes(); 
4171     // Draw the bullet, if any 
4172     if (attr
.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE
) 
4174         if (attr
.GetLeftSubIndent() != 0) 
4176             int spaceBeforePara 
= ConvertTenthsMMToPixels(dc
, attr
.GetParagraphSpacingBefore()); 
4177             int leftIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetLeftIndent()); 
4179             wxRichTextAttr 
bulletAttr(GetCombinedAttributes()); 
4181             // Combine with the font of the first piece of content, if one is specified 
4182             if (GetChildren().GetCount() > 0) 
4184                 wxRichTextObject
* firstObj 
= (wxRichTextObject
*) GetChildren().GetFirst()->GetData(); 
4185                 if (!firstObj
->IsFloatable() && firstObj
->GetAttributes().HasFont()) 
4187                     wxRichTextApplyStyle(bulletAttr
, firstObj
->GetAttributes()); 
4191             // Get line height from first line, if any 
4192             wxRichTextLine
* line 
= m_cachedLines
.GetFirst() ? (wxRichTextLine
* ) m_cachedLines
.GetFirst()->GetData() : NULL
; 
4195             int lineHeight 
wxDUMMY_INITIALIZE(0); 
4198                 lineHeight 
= line
->GetSize().y
; 
4199                 linePos 
= line
->GetPosition() + GetPosition(); 
4204                 if (bulletAttr
.HasFont() && GetBuffer()) 
4205                     font 
= GetBuffer()->GetFontTable().FindFont(bulletAttr
); 
4207                     font 
= (*wxNORMAL_FONT
); 
4209                 wxCheckSetFont(dc
, font
); 
4211                 lineHeight 
= dc
.GetCharHeight(); 
4212                 linePos 
= GetPosition(); 
4213                 linePos
.y 
+= spaceBeforePara
; 
4216             wxRect 
bulletRect(GetPosition().x 
+ leftIndent
, linePos
.y
, linePos
.x 
- (GetPosition().x 
+ leftIndent
), lineHeight
); 
4218             if (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP
) 
4220                 if (wxRichTextBuffer::GetRenderer()) 
4221                     wxRichTextBuffer::GetRenderer()->DrawBitmapBullet(this, dc
, bulletAttr
, bulletRect
); 
4223             else if (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_STANDARD
) 
4225                 if (wxRichTextBuffer::GetRenderer()) 
4226                     wxRichTextBuffer::GetRenderer()->DrawStandardBullet(this, dc
, bulletAttr
, bulletRect
); 
4230                 wxString bulletText 
= GetBulletText(); 
4232                 if (!bulletText
.empty() && wxRichTextBuffer::GetRenderer()) 
4233                     wxRichTextBuffer::GetRenderer()->DrawTextBullet(this, dc
, bulletAttr
, bulletRect
, bulletText
); 
4238     // Draw the range for each line, one object at a time. 
4240     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
4243         wxRichTextLine
* line 
= node
->GetData(); 
4244         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
4246         // Lines are specified relative to the paragraph 
4248         wxPoint linePosition 
= line
->GetPosition() + GetPosition(); 
4250         // Don't draw if off the screen 
4251         if (((style 
& wxRICHTEXT_DRAW_IGNORE_CACHE
) != 0) || ((linePosition
.y 
+ line
->GetSize().y
) >= rect
.y 
&& linePosition
.y 
<= rect
.y 
+ rect
.height
)) 
4253             wxPoint objectPosition 
= linePosition
; 
4254             int maxDescent 
= line
->GetDescent(); 
4256             // Loop through objects until we get to the one within range 
4257             wxRichTextObjectList::compatibility_iterator node2 
= m_children
.GetFirst(); 
4262                 wxRichTextObject
* child 
= node2
->GetData(); 
4264                 if (!child
->IsFloating() && child
->GetRange().GetLength() > 0 && !child
->GetRange().IsOutside(lineRange
) && !lineRange
.IsOutside(range
)) 
4266                     // Draw this part of the line at the correct position 
4267                     wxRichTextRange 
objectRange(child
->GetRange()); 
4268                     objectRange
.LimitTo(lineRange
); 
4271                     if (child
->IsTopLevel()) 
4273                         objectSize 
= child
->GetCachedSize(); 
4274                         objectRange 
= child
->GetOwnRange(); 
4278 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING && wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
4279                         if (i 
< (int) line
->GetObjectSizes().GetCount()) 
4281                             objectSize
.x 
= line
->GetObjectSizes()[(size_t) i
]; 
4287                             child
->GetRangeSize(objectRange
, objectSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
, objectPosition
); 
4291                     // Use the child object's width, but the whole line's height 
4292                     wxRect 
childRect(objectPosition
, wxSize(objectSize
.x
, line
->GetSize().y
)); 
4293                     child
->Draw(dc
, objectRange
, selection
, childRect
, maxDescent
, style
); 
4295                     objectPosition
.x 
+= objectSize
.x
; 
4298                 else if (child
->GetRange().GetStart() > lineRange
.GetEnd()) 
4299                     // Can break out of inner loop now since we've passed this line's range 
4302                 node2 
= node2
->GetNext(); 
4306         node 
= node
->GetNext(); 
4312 // Get the range width using partial extents calculated for the whole paragraph. 
4313 static int wxRichTextGetRangeWidth(const wxRichTextParagraph
& para
, const wxRichTextRange
& range
, const wxArrayInt
& partialExtents
) 
4315     wxASSERT(partialExtents
.GetCount() >= (size_t) range
.GetLength()); 
4317     if (partialExtents
.GetCount() < (size_t) range
.GetLength()) 
4320     int leftMostPos 
= 0; 
4321     if (range
.GetStart() - para
.GetRange().GetStart() > 0) 
4322         leftMostPos 
= partialExtents
[range
.GetStart() - para
.GetRange().GetStart() - 1]; 
4324     int rightMostPos 
= partialExtents
[range
.GetEnd() - para
.GetRange().GetStart()]; 
4326     int w 
= rightMostPos 
- leftMostPos
; 
4331 /// Lay the item out 
4332 bool wxRichTextParagraph::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
4334     // Deal with floating objects firstly before the normal layout 
4335     wxRichTextBuffer
* buffer 
= GetBuffer(); 
4337     wxRichTextFloatCollector
* collector 
= GetContainer()->GetFloatCollector(); 
4338     wxASSERT(collector
); 
4339     LayoutFloat(dc
, rect
, style
, collector
); 
4341     wxRichTextAttr attr 
= GetCombinedAttributes(); 
4345     // Increase the size of the paragraph due to spacing 
4346     int spaceBeforePara 
= ConvertTenthsMMToPixels(dc
, attr
.GetParagraphSpacingBefore()); 
4347     int spaceAfterPara 
= ConvertTenthsMMToPixels(dc
, attr
.GetParagraphSpacingAfter()); 
4348     int leftIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetLeftIndent()); 
4349     int leftSubIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetLeftSubIndent()); 
4350     int rightIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetRightIndent()); 
4352     int lineSpacing 
= 0; 
4354     // Let's assume line spacing of 10 is normal, 15 is 1.5, 20 is 2, etc. 
4355     if (attr
.HasLineSpacing() && attr
.GetLineSpacing() > 0 && attr
.GetFont().IsOk()) 
4357         wxCheckSetFont(dc
, attr
.GetFont()); 
4358         lineSpacing 
= (int) (double(dc
.GetCharHeight()) * (double(attr
.GetLineSpacing())/10.0 - 1.0)); 
4361     // Start position for each line relative to the paragraph 
4362     int startPositionFirstLine 
= leftIndent
; 
4363     int startPositionSubsequentLines 
= leftIndent 
+ leftSubIndent
; 
4365     // If we have a bullet in this paragraph, the start position for the first line's text 
4366     // is actually leftIndent + leftSubIndent. 
4367     if (attr
.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE
) 
4368         startPositionFirstLine 
= startPositionSubsequentLines
; 
4370     long lastEndPos 
= GetRange().GetStart()-1; 
4371     long lastCompletedEndPos 
= lastEndPos
; 
4373     int currentWidth 
= 0; 
4374     SetPosition(rect
.GetPosition()); 
4376     wxPoint 
currentPosition(0, spaceBeforePara
); // We will calculate lines relative to paragraph 
4379     int maxHeight 
= currentPosition
.y
; 
4384     int lineDescent 
= 0; 
4386     wxRichTextObjectList::compatibility_iterator node
; 
4388 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
4390     wxArrayInt partialExtents
; 
4393     int paraDescent 
= 0; 
4395     // This calculates the partial text extents 
4396     GetRangeSize(GetRange(), paraSize
, paraDescent
, dc
, wxRICHTEXT_UNFORMATTED
|wxRICHTEXT_CACHE_SIZE
, rect
.GetPosition(), & partialExtents
); 
4398     node 
= m_children
.GetFirst(); 
4401         wxRichTextObject
* child 
= node
->GetData(); 
4403         //child->SetCachedSize(wxDefaultSize); 
4404         child
->Layout(dc
, rect
, style
); 
4406         node 
= node
->GetNext(); 
4413     // We may need to go back to a previous child, in which case create the new line, 
4414     // find the child corresponding to the start position of the string, and 
4417     wxRect availableRect
; 
4419     node 
= m_children
.GetFirst(); 
4422         wxRichTextObject
* child 
= node
->GetData(); 
4424         // If floating, ignore. We already laid out floats. 
4425         // Also ignore if empty object, except if we haven't got any 
4427         if (child
->IsFloating() || !child
->IsShown() || 
4428             (child
->GetRange().GetLength() == 0 && maxHeight 
> spaceBeforePara
) 
4431             node 
= node
->GetNext(); 
4435         // If this is e.g. a composite text box, it will need to be laid out itself. 
4436         // But if just a text fragment or image, for example, this will 
4437         // do nothing. NB: won't we need to set the position after layout? 
4438         // since for example if position is dependent on vertical line size, we 
4439         // can't tell the position until the size is determined. So possibly introduce 
4440         // another layout phase. 
4442         // We may only be looking at part of a child, if we searched back for wrapping 
4443         // and found a suitable point some way into the child. So get the size for the fragment 
4446         long nextBreakPos 
= GetFirstLineBreakPosition(lastEndPos
+1); 
4447         long lastPosToUse 
= child
->GetRange().GetEnd(); 
4448         bool lineBreakInThisObject 
= (nextBreakPos 
> -1 && nextBreakPos 
<= child
->GetRange().GetEnd()); 
4450         if (lineBreakInThisObject
) 
4451             lastPosToUse 
= nextBreakPos
; 
4454         int childDescent 
= 0; 
4456         int startOffset 
= (lineCount 
== 0 ? startPositionFirstLine 
: startPositionSubsequentLines
); 
4457         availableRect 
= wxRect(rect
.x 
+ startOffset
, rect
.y 
+ currentPosition
.y
, 
4458                                      rect
.width 
- startOffset 
- rightIndent
, rect
.height
); 
4460         if (child
->IsTopLevel()) 
4462             wxSize oldSize 
= child
->GetCachedSize(); 
4464             child
->Invalidate(wxRICHTEXT_ALL
); 
4465             child
->SetPosition(wxPoint(0, 0)); 
4467             // Lays out the object first with a given amount of space, and then if no width was specified in attr, 
4468             // lays out the object again using the minimum size 
4469             // The position will be determined by its location in its line, 
4470             // and not by the child's actual position. 
4471             child
->LayoutToBestSize(dc
, buffer
, 
4472                     GetAttributes(), child
->GetAttributes(), availableRect
, style
); 
4474             if (oldSize 
!= child
->GetCachedSize()) 
4476                 partialExtents
.Clear(); 
4478                 // Recalculate the partial text extents since the child object changed size 
4479                 GetRangeSize(GetRange(), paraSize
, paraDescent
, dc
, wxRICHTEXT_UNFORMATTED
|wxRICHTEXT_CACHE_SIZE
, wxPoint(0,0), & partialExtents
); 
4483         // Problem: we need to layout composites here for which we need the available width, 
4484         // but we can't get the available width without using the float collector which 
4485         // needs to know the object height. 
4487         if ((nextBreakPos 
== -1) && (lastEndPos 
== child
->GetRange().GetStart() - 1)) // i.e. we want to get the whole thing 
4489             childSize 
= child
->GetCachedSize(); 
4490             childDescent 
= child
->GetDescent(); 
4494 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
4495             // Get height only, then the width using the partial extents 
4496             GetRangeSize(wxRichTextRange(lastEndPos
+1, lastPosToUse
), childSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
|wxRICHTEXT_HEIGHT_ONLY
); 
4497             childSize
.x 
= wxRichTextGetRangeWidth(*this, wxRichTextRange(lastEndPos
+1, lastPosToUse
), partialExtents
); 
4499             GetRangeSize(wxRichTextRange(lastEndPos
+1, lastPosToUse
), childSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
, rect
.GetPosition()); 
4504         int loopIterations 
= 0; 
4506         // If there are nested objects that need to lay themselves out, we have to do this in a 
4507         // loop because the height of the object may well depend on the available width. 
4508         // And because of floating object positioning, the available width depends on the 
4509         // height of the object and whether it will clash with the floating objects. 
4510         // So, we see whether the available width changes due to the presence of floating images. 
4511         // If it does, then we'll use the new restricted width to find the object height again. 
4512         // If this causes another restriction in the available width, we'll try again, until 
4513         // either we lose patience or the available width settles down. 
4518             wxRect oldAvailableRect 
= availableRect
; 
4520             // Available width depends on the floating objects and the line height. 
4521             // Note: the floating objects may be placed vertically along the two side of 
4522             // buffer, so we may have different available line widths with different 
4523             // [startY, endY]. So, we can't determine how wide the available 
4524             // space is until we know the exact line height. 
4525             lineDescent 
= wxMax(childDescent
, maxDescent
); 
4526             lineAscent 
= wxMax(childSize
.y
-childDescent
, maxAscent
); 
4527             lineHeight 
= lineDescent 
+ lineAscent
; 
4528             wxRect floatAvailableRect 
= collector
->GetAvailableRect(rect
.y 
+ currentPosition
.y
, rect
.y 
+ currentPosition
.y 
+ lineHeight
); 
4530             // Adjust availableRect to the space that is available when taking floating objects into account. 
4532             if (floatAvailableRect
.x 
+ startOffset 
> availableRect
.x
) 
4534                 int newX 
= floatAvailableRect
.x 
+ startOffset
; 
4535                 int newW 
= availableRect
.width 
- (newX 
- availableRect
.x
); 
4536                 availableRect
.x 
= newX
; 
4537                 availableRect
.width 
= newW
; 
4540             if (floatAvailableRect
.width 
< availableRect
.width
) 
4541                 availableRect
.width 
= floatAvailableRect
.width
; 
4543             currentPosition
.x 
= availableRect
.x 
- rect
.x
; 
4545             if (child
->IsTopLevel() && loopIterations 
<= 20) 
4547                 if (availableRect 
!= oldAvailableRect
) 
4549                     wxSize oldSize 
= child
->GetCachedSize(); 
4551                     //child->SetCachedSize(wxDefaultSize); 
4552                     // Lays out the object first with a given amount of space, and then if no width was specified in attr, 
4553                     // lays out the object again using the minimum size 
4554                     child
->Invalidate(wxRICHTEXT_ALL
); 
4555                     child
->LayoutToBestSize(dc
, buffer
, 
4556                                 GetAttributes(), child
->GetAttributes(), availableRect
, style
); 
4557                     childSize 
= child
->GetCachedSize(); 
4558                     childDescent 
= child
->GetDescent(); 
4559                     //child->SetPosition(availableRect.GetPosition()); 
4561                     if (oldSize 
!= child
->GetCachedSize()) 
4563                         partialExtents
.Clear(); 
4565                         // Recalculate the partial text extents since the child object changed size 
4566                         GetRangeSize(GetRange(), paraSize
, paraDescent
, dc
, wxRICHTEXT_UNFORMATTED
|wxRICHTEXT_CACHE_SIZE
, wxPoint(0,0), & partialExtents
); 
4569                     // Go around the loop finding the available rect for the given floating objects 
4580         // 1) There was a line break BEFORE the natural break 
4581         // 2) There was a line break AFTER the natural break 
4582         // 3) It's the last line 
4583         // 4) The child still fits (carry on) - 'else' clause 
4585         if ((lineBreakInThisObject 
&& (childSize
.x 
+ currentWidth 
<= availableRect
.width
)) 
4587             (childSize
.x 
+ currentWidth 
> availableRect
.width
) 
4589             ((childSize
.x 
+ currentWidth 
<= availableRect
.width
) && !node
->GetNext()) 
4593             if (child
->IsTopLevel()) 
4595                 // We can move it to the correct position at this point 
4596                 child
->Move(GetPosition() + wxPoint(currentWidth
, currentPosition
.y
)); 
4599             long wrapPosition 
= 0; 
4600             if ((childSize
.x 
+ currentWidth 
<= availableRect
.width
) && !node
->GetNext() && !lineBreakInThisObject
) 
4601                 wrapPosition 
= child
->GetRange().GetEnd(); 
4604             // Find a place to wrap. This may walk back to previous children, 
4605             // for example if a word spans several objects. 
4606             // Note: one object must contains only one wxTextAtrr, so the line height will not 
4607             //       change inside one object. Thus, we can pass the remain line width to the 
4608             //       FindWrapPosition function. 
4609             if (!FindWrapPosition(wxRichTextRange(lastCompletedEndPos
+1, child
->GetRange().GetEnd()), dc
, availableRect
.width
, wrapPosition
, & partialExtents
)) 
4611                 // If the function failed, just cut it off at the end of this child. 
4612                 wrapPosition 
= child
->GetRange().GetEnd(); 
4615             // FindWrapPosition can still return a value that will put us in an endless wrapping loop 
4616             if (wrapPosition 
<= lastCompletedEndPos
) 
4617                 wrapPosition 
= wxMax(lastCompletedEndPos
+1,child
->GetRange().GetEnd()); 
4619             // Line end position shouldn't be the same as the end, or greater. 
4620             if (wrapPosition 
>= GetRange().GetEnd()) 
4621                 wrapPosition 
= GetRange().GetEnd()-1; 
4623             // wxLogDebug(wxT("Split at %ld"), wrapPosition); 
4625             // Let's find the actual size of the current line now 
4627             wxRichTextRange 
actualRange(lastCompletedEndPos
+1, wrapPosition
); 
4629             /// Use previous descent, not the wrapping descent we just found, since this may be too big 
4630             /// for the fragment we're about to add. 
4631             childDescent 
= maxDescent
; 
4633 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
4634             if (!child
->IsEmpty()) 
4636                 // Get height only, then the width using the partial extents 
4637                 GetRangeSize(actualRange
, actualSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
|wxRICHTEXT_HEIGHT_ONLY
); 
4638                 actualSize
.x 
= wxRichTextGetRangeWidth(*this, actualRange
, partialExtents
); 
4642                 GetRangeSize(actualRange
, actualSize
, childDescent
, dc
, wxRICHTEXT_UNFORMATTED
); 
4644             currentWidth 
= actualSize
.x
; 
4645             maxDescent 
= wxMax(childDescent
, maxDescent
); 
4646             maxAscent 
= wxMax(actualSize
.y
-childDescent
, maxAscent
); 
4647             lineHeight 
= maxDescent 
+ maxAscent
; 
4649             if (lineHeight 
== 0 && buffer
) 
4651                 wxFont 
font(buffer
->GetFontTable().FindFont(attr
)); 
4652                 wxCheckSetFont(dc
, font
); 
4653                 lineHeight 
= dc
.GetCharHeight(); 
4656             if (maxDescent 
== 0) 
4659                 dc
.GetTextExtent(wxT("X"), & w
, &h
, & maxDescent
); 
4663             wxRichTextLine
* line 
= AllocateLine(lineCount
); 
4665             // Set relative range so we won't have to change line ranges when paragraphs are moved 
4666             line
->SetRange(wxRichTextRange(actualRange
.GetStart() - GetRange().GetStart(), actualRange
.GetEnd() - GetRange().GetStart())); 
4667             line
->SetPosition(currentPosition
); 
4668             line
->SetSize(wxSize(currentWidth
, lineHeight
)); 
4669             line
->SetDescent(maxDescent
); 
4671             maxHeight 
= currentPosition
.y 
+ lineHeight
; 
4673             // Now move down a line. TODO: add margins, spacing 
4674             currentPosition
.y 
+= lineHeight
; 
4675             currentPosition
.y 
+= lineSpacing
; 
4678             maxWidth 
= wxMax(maxWidth
, currentWidth
+startOffset
); 
4683             // TODO: account for zero-length objects, such as fields 
4684             // wxASSERT(wrapPosition > lastCompletedEndPos); 
4686             lastEndPos 
= wrapPosition
; 
4687             lastCompletedEndPos 
= lastEndPos
; 
4691             if (wrapPosition 
< GetRange().GetEnd()-1) 
4693                 // May need to set the node back to a previous one, due to searching back in wrapping 
4694                 wxRichTextObject
* childAfterWrapPosition 
= FindObjectAtPosition(wrapPosition
+1); 
4695                 if (childAfterWrapPosition
) 
4696                     node 
= m_children
.Find(childAfterWrapPosition
); 
4698                     node 
= node
->GetNext(); 
4701                 node 
= node
->GetNext(); 
4703             // Apply paragraph styles such as alignment to the wrapped line 
4704             ApplyParagraphStyle(line
, attr
, availableRect
, dc
); 
4708             // We still fit, so don't add a line, and keep going 
4709             currentWidth 
+= childSize
.x
; 
4710             maxDescent 
= wxMax(childDescent
, maxDescent
); 
4711             maxAscent 
= wxMax(childSize
.y
-childDescent
, maxAscent
); 
4712             lineHeight 
= maxDescent 
+ maxAscent
; 
4714             maxWidth 
= wxMax(maxWidth
, currentWidth
+startOffset
); 
4715             lastEndPos 
= child
->GetRange().GetEnd(); 
4717             node 
= node
->GetNext(); 
4721     //wxASSERT(!(lastCompletedEndPos != -1 && lastCompletedEndPos < GetRange().GetEnd()-1)); 
4723     // Remove remaining unused line objects, if any 
4724     ClearUnusedLines(lineCount
); 
4726     // We need to add back the margins etc. 
4728         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
4729         contentRect 
= wxRect(wxPoint(0, 0), wxSize(maxWidth
, currentPosition
.y 
+ spaceAfterPara
)); 
4730         GetBoxRects(dc
, buffer
, GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
4731         SetCachedSize(marginRect
.GetSize()); 
4734     // The maximum size is the length of the paragraph stretched out into a line. 
4735     // So if there were a single word, or an image, or a fixed-size text box, the object could be shrunk around 
4736     // this size. TODO: take into account line breaks. 
4738         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
4739         contentRect 
= wxRect(wxPoint(0, 0), wxSize(paraSize
.x 
+ wxMax(leftIndent
, leftIndent 
+ leftSubIndent
) + rightIndent
, currentPosition
.y 
+ spaceAfterPara
)); 
4740         GetBoxRects(dc
, buffer
, GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
4741         SetMaxSize(marginRect
.GetSize()); 
4744     // Find the greatest minimum size. Currently we only look at non-text objects, 
4745     // which isn't ideal but it would be slow to find the maximum word width to 
4746     // use as the minimum. 
4749         node 
= m_children
.GetFirst(); 
4752             wxRichTextObject
* child 
= node
->GetData(); 
4754             // If floating, ignore. We already laid out floats. 
4755             // Also ignore if empty object, except if we haven't got any 
4757             if (!child
->IsFloating() && child
->GetRange().GetLength() != 0 && !child
->IsKindOf(CLASSINFO(wxRichTextPlainText
))) 
4759                 if (child
->GetCachedSize().x 
> minWidth
) 
4760                     minWidth 
= child
->GetMinSize().x
; 
4762             node 
= node
->GetNext(); 
4765         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
4766         contentRect 
= wxRect(wxPoint(0, 0), wxSize(minWidth
, currentPosition
.y 
+ spaceAfterPara
)); 
4767         GetBoxRects(dc
, buffer
, GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
4768         SetMinSize(marginRect
.GetSize()); 
4772 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
4773 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 
4774     // Use the text extents to calculate the size of each fragment in each line 
4775     wxRichTextLineList::compatibility_iterator lineNode 
= m_cachedLines
.GetFirst(); 
4778         wxRichTextLine
* line 
= lineNode
->GetData(); 
4779         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
4781         // Loop through objects until we get to the one within range 
4782         wxRichTextObjectList::compatibility_iterator node2 
= m_children
.GetFirst(); 
4786             wxRichTextObject
* child 
= node2
->GetData(); 
4788             if (child
->GetRange().GetLength() > 0 && !child
->GetRange().IsOutside(lineRange
)) 
4790                 wxRichTextRange rangeToUse 
= lineRange
; 
4791                 rangeToUse
.LimitTo(child
->GetRange()); 
4793                 // Find the size of the child from the text extents, and store in an array 
4794                 // for drawing later 
4796                 if (rangeToUse
.GetStart() > GetRange().GetStart()) 
4797                     left 
= partialExtents
[(rangeToUse
.GetStart()-1) - GetRange().GetStart()]; 
4798                 int right 
= partialExtents
[rangeToUse
.GetEnd() - GetRange().GetStart()]; 
4799                 int sz 
= right 
- left
; 
4800                 line
->GetObjectSizes().Add(sz
); 
4802             else if (child
->GetRange().GetStart() > lineRange
.GetEnd()) 
4803                 // Can break out of inner loop now since we've passed this line's range 
4806             node2 
= node2
->GetNext(); 
4809         lineNode 
= lineNode
->GetNext(); 
4817 /// Apply paragraph styles, such as centering, to wrapped lines 
4818 /// TODO: take into account box attributes, possibly 
4819 void wxRichTextParagraph::ApplyParagraphStyle(wxRichTextLine
* line
, const wxRichTextAttr
& attr
, const wxRect
& rect
, wxDC
& dc
) 
4821     if (!attr
.HasAlignment()) 
4824     wxPoint pos 
= line
->GetPosition(); 
4825     wxSize size 
= line
->GetSize(); 
4827     // centering, right-justification 
4828     if (attr
.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_CENTRE
) 
4830         int rightIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetRightIndent()); 
4831         pos
.x 
= (rect
.GetWidth() - rightIndent 
- size
.x
)/2 + pos
.x
; 
4832         line
->SetPosition(pos
); 
4834     else if (attr
.HasAlignment() && GetAttributes().GetAlignment() == wxTEXT_ALIGNMENT_RIGHT
) 
4836         int rightIndent 
= ConvertTenthsMMToPixels(dc
, attr
.GetRightIndent()); 
4837         pos
.x 
= pos
.x 
+ rect
.GetWidth() - size
.x 
- rightIndent
; 
4838         line
->SetPosition(pos
); 
4842 /// Insert text at the given position 
4843 bool wxRichTextParagraph::InsertText(long pos
, const wxString
& text
) 
4845     wxRichTextObject
* childToUse 
= NULL
; 
4846     wxRichTextObjectList::compatibility_iterator nodeToUse 
= wxRichTextObjectList::compatibility_iterator(); 
4848     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
4851         wxRichTextObject
* child 
= node
->GetData(); 
4852         if (child
->GetRange().Contains(pos
) && child
->GetRange().GetLength() > 0) 
4859         node 
= node
->GetNext(); 
4864         wxRichTextPlainText
* textObject 
= wxDynamicCast(childToUse
, wxRichTextPlainText
); 
4867             int posInString 
= pos 
- textObject
->GetRange().GetStart(); 
4869             wxString newText 
= textObject
->GetText().Mid(0, posInString
) + 
4870                                text 
+ textObject
->GetText().Mid(posInString
); 
4871             textObject
->SetText(newText
); 
4873             int textLength 
= text
.length(); 
4875             textObject
->SetRange(wxRichTextRange(textObject
->GetRange().GetStart(), 
4876                                                  textObject
->GetRange().GetEnd() + textLength
)); 
4878             // Increment the end range of subsequent fragments in this paragraph. 
4879             // We'll set the paragraph range itself at a higher level. 
4881             wxRichTextObjectList::compatibility_iterator node 
= nodeToUse
->GetNext(); 
4884                 wxRichTextObject
* child 
= node
->GetData(); 
4885                 child
->SetRange(wxRichTextRange(textObject
->GetRange().GetStart() + textLength
, 
4886                                                  textObject
->GetRange().GetEnd() + textLength
)); 
4888                 node 
= node
->GetNext(); 
4895             // TODO: if not a text object, insert at closest position, e.g. in front of it 
4901         // Don't pass parent initially to suppress auto-setting of parent range. 
4902         // We'll do that at a higher level. 
4903         wxRichTextPlainText
* textObject 
= new wxRichTextPlainText(text
, this); 
4905         AppendChild(textObject
); 
4912 void wxRichTextParagraph::Copy(const wxRichTextParagraph
& obj
) 
4914     wxRichTextCompositeObject::Copy(obj
); 
4917 /// Clear the cached lines 
4918 void wxRichTextParagraph::ClearLines() 
4920     WX_CLEAR_LIST(wxRichTextLineList
, m_cachedLines
); 
4923 /// Get/set the object size for the given range. Returns false if the range 
4924 /// is invalid for this object. 
4925 bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
, wxPoint position
, wxArrayInt
* partialExtents
) const 
4927     if (!range
.IsWithin(GetRange())) 
4930     if (flags 
& wxRICHTEXT_UNFORMATTED
) 
4932         // Just use unformatted data, assume no line breaks 
4933         // TODO: take into account line breaks 
4937         wxArrayInt childExtents
; 
4944         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
4948             wxRichTextObject
* child 
= node
->GetData(); 
4949             if (!child
->GetRange().IsOutside(range
)) 
4951                 // Floating objects have a zero size within the paragraph. 
4952                 if (child
->IsFloating()) 
4957                         if (partialExtents
->GetCount() > 0) 
4958                             lastSize 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
4962                         partialExtents
->Add(0 /* zero size */ + lastSize
); 
4969                     wxRichTextRange rangeToUse 
= range
; 
4970                     rangeToUse
.LimitTo(child
->GetRange()); 
4972                     if (child
->IsTopLevel()) 
4973                         rangeToUse 
= child
->GetOwnRange(); 
4975                     int childDescent 
= 0; 
4977                     // At present wxRICHTEXT_HEIGHT_ONLY is only fast if we're already cached the size, 
4978                     // but it's only going to be used after caching has taken place. 
4979                     if ((flags 
& wxRICHTEXT_HEIGHT_ONLY
) && child
->GetCachedSize().y 
!= 0) 
4981                         childDescent 
= child
->GetDescent(); 
4982                         childSize 
= child
->GetCachedSize(); 
4984                         sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
4985                         sz
.x 
+= childSize
.x
; 
4986                         descent 
= wxMax(descent
, childDescent
); 
4988                     else if (child
->IsTopLevel()) 
4990                         childDescent 
= child
->GetDescent(); 
4991                         childSize 
= child
->GetCachedSize(); 
4993                         sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
4994                         sz
.x 
+= childSize
.x
; 
4995                         descent 
= wxMax(descent
, childDescent
); 
4996                         if ((flags 
& wxRICHTEXT_CACHE_SIZE
) && (rangeToUse 
== child
->GetRange())) 
4998                             child
->SetCachedSize(childSize
); 
4999                             child
->SetDescent(childDescent
); 
5005                             if (partialExtents
->GetCount() > 0) 
5006                                 lastSize 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
5010                             partialExtents
->Add(childSize
.x 
+ lastSize
); 
5013                     else if (child
->GetRangeSize(rangeToUse
, childSize
, childDescent
, dc
, flags
, wxPoint(position
.x 
+ sz
.x
, position
.y
), p
)) 
5015                         sz
.y 
= wxMax(sz
.y
, childSize
.y
); 
5016                         sz
.x 
+= childSize
.x
; 
5017                         descent 
= wxMax(descent
, childDescent
); 
5019                         if ((flags 
& wxRICHTEXT_CACHE_SIZE
) && (rangeToUse 
== child
->GetRange())) 
5021                             child
->SetCachedSize(childSize
); 
5022                             child
->SetDescent(childDescent
); 
5028                             if (partialExtents
->GetCount() > 0) 
5029                                 lastSize 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
5034                             for (i 
= 0; i 
< childExtents
.GetCount(); i
++) 
5036                                 partialExtents
->Add(childExtents
[i
] + lastSize
); 
5046             node 
= node
->GetNext(); 
5052         // Use formatted data, with line breaks 
5055         // We're going to loop through each line, and then for each line, 
5056         // call GetRangeSize for the fragment that comprises that line. 
5057         // Only we have to do that multiple times within the line, because 
5058         // the line may be broken into pieces. For now ignore line break commands 
5059         // (so we can assume that getting the unformatted size for a fragment 
5060         // within a line is the actual size) 
5062         wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
5065             wxRichTextLine
* line 
= node
->GetData(); 
5066             wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
5067             if (!lineRange
.IsOutside(range
)) 
5071                 wxRichTextObjectList::compatibility_iterator node2 
= m_children
.GetFirst(); 
5074                     wxRichTextObject
* child 
= node2
->GetData(); 
5076                     if (!child
->IsFloating() && !child
->GetRange().IsOutside(lineRange
)) 
5078                         wxRichTextRange rangeToUse 
= lineRange
; 
5079                         rangeToUse
.LimitTo(child
->GetRange()); 
5080                         if (child
->IsTopLevel()) 
5081                             rangeToUse 
= child
->GetOwnRange(); 
5084                         int childDescent 
= 0; 
5085                         if (child
->GetRangeSize(rangeToUse
, childSize
, childDescent
, dc
, flags
, wxPoint(position
.x 
+ sz
.x
, position
.y
))) 
5087                             lineSize
.y 
= wxMax(lineSize
.y
, childSize
.y
); 
5088                             lineSize
.x 
+= childSize
.x
; 
5090                         descent 
= wxMax(descent
, childDescent
); 
5093                     node2 
= node2
->GetNext(); 
5096                 // Increase size by a line (TODO: paragraph spacing) 
5098                 sz
.x 
= wxMax(sz
.x
, lineSize
.x
); 
5100             node 
= node
->GetNext(); 
5107 /// Finds the absolute position and row height for the given character position 
5108 bool wxRichTextParagraph::FindPosition(wxDC
& dc
, long index
, wxPoint
& pt
, int* height
, bool forceLineStart
) 
5112         wxRichTextLine
* line 
= ((wxRichTextParagraphLayoutBox
*)GetParent())->GetLineAtPosition(0); 
5114             *height 
= line
->GetSize().y
; 
5116             *height 
= dc
.GetCharHeight(); 
5118         // -1 means 'the start of the buffer'. 
5121             pt 
= pt 
+ line
->GetPosition(); 
5126     // The final position in a paragraph is taken to mean the position 
5127     // at the start of the next paragraph. 
5128     if (index 
== GetRange().GetEnd()) 
5130         wxRichTextParagraphLayoutBox
* parent 
= wxDynamicCast(GetParent(), wxRichTextParagraphLayoutBox
); 
5131         wxASSERT( parent 
!= NULL 
); 
5133         // Find the height at the next paragraph, if any 
5134         wxRichTextLine
* line 
= parent
->GetLineAtPosition(index 
+ 1); 
5137             *height 
= line
->GetSize().y
; 
5138             pt 
= line
->GetAbsolutePosition(); 
5142             *height 
= dc
.GetCharHeight(); 
5143             int indent 
= ConvertTenthsMMToPixels(dc
, m_attributes
.GetLeftIndent()); 
5144             pt 
= wxPoint(indent
, GetCachedSize().y
); 
5150     if (index 
< GetRange().GetStart() || index 
> GetRange().GetEnd()) 
5153     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
5156         wxRichTextLine
* line 
= node
->GetData(); 
5157         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
5158         if (index 
>= lineRange
.GetStart() && index 
<= lineRange
.GetEnd()) 
5160             // If this is the last point in the line, and we're forcing the 
5161             // returned value to be the start of the next line, do the required 
5163             if (index 
== lineRange
.GetEnd() && forceLineStart
) 
5165                 if (node
->GetNext()) 
5167                     wxRichTextLine
* nextLine 
= node
->GetNext()->GetData(); 
5168                     *height 
= nextLine
->GetSize().y
; 
5169                     pt 
= nextLine
->GetAbsolutePosition(); 
5174             pt
.y 
= line
->GetPosition().y 
+ GetPosition().y
; 
5176             wxRichTextRange 
r(lineRange
.GetStart(), index
); 
5180             // We find the size of the line up to this point, 
5181             // then we can add this size to the line start position and 
5182             // paragraph start position to find the actual position. 
5184             if (GetRangeSize(r
, rangeSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
, line
->GetPosition()+ GetPosition())) 
5186                 pt
.x 
= line
->GetPosition().x 
+ GetPosition().x 
+ rangeSize
.x
; 
5187                 *height 
= line
->GetSize().y
; 
5194         node 
= node
->GetNext(); 
5200 /// Hit-testing: returns a flag indicating hit test details, plus 
5201 /// information about position 
5202 int wxRichTextParagraph::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, wxRichTextObject
** contextObj
, int flags
) 
5205         return wxRICHTEXT_HITTEST_NONE
; 
5207     // If we're in the top-level container, then we can return 
5208     // a suitable hit test code even if the point is outside the container area, 
5209     // so that we can position the caret sensibly even if we don't 
5210     // click on valid content. If we're not at the top-level, and the point 
5211     // is not within this paragraph object, then we don't want to stop more 
5212     // precise hit-testing from working prematurely, so return immediately. 
5213     // NEW STRATEGY: use the parent boundary to test whether we're in the 
5214     // right region, not the paragraph, since the paragraph may be positioned 
5215     // some way in from where the user clicks. 
5218         wxRichTextObject
* tempObj
, *tempContextObj
; 
5219         if (GetParent() && GetParent()->wxRichTextObject::HitTest(dc
, pt
, tmpPos
, & tempObj
, & tempContextObj
, flags
) == wxRICHTEXT_HITTEST_NONE
) 
5220             return wxRICHTEXT_HITTEST_NONE
; 
5223     wxRichTextObjectList::compatibility_iterator objNode 
= m_children
.GetFirst(); 
5226         wxRichTextObject
* child 
= objNode
->GetData(); 
5227         if (child
->IsTopLevel() && ((flags 
& wxRICHTEXT_HITTEST_NO_NESTED_OBJECTS
) == 0)) 
5230                 int hitTest 
= child
->HitTest(dc
, pt
, textPosition
, obj
, contextObj
); 
5231                 if (hitTest 
!= wxRICHTEXT_HITTEST_NONE
) 
5236         objNode 
= objNode
->GetNext(); 
5239     wxPoint paraPos 
= GetPosition(); 
5241     wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetFirst(); 
5244         wxRichTextLine
* line 
= node
->GetData(); 
5245         wxPoint linePos 
= paraPos 
+ line
->GetPosition(); 
5246         wxSize lineSize 
= line
->GetSize(); 
5247         wxRichTextRange lineRange 
= line
->GetAbsoluteRange(); 
5249         if (pt
.y 
<= linePos
.y 
+ lineSize
.y
) 
5251             if (pt
.x 
< linePos
.x
) 
5253                 textPosition 
= lineRange
.GetStart(); 
5254                 *obj 
= FindObjectAtPosition(textPosition
); 
5255                 *contextObj 
= GetContainer(); 
5256                 return wxRICHTEXT_HITTEST_BEFORE
|wxRICHTEXT_HITTEST_OUTSIDE
; 
5258             else if (pt
.x 
>= (linePos
.x 
+ lineSize
.x
)) 
5260                 textPosition 
= lineRange
.GetEnd(); 
5261                 *obj 
= FindObjectAtPosition(textPosition
); 
5262                 *contextObj 
= GetContainer(); 
5263                 return wxRICHTEXT_HITTEST_AFTER
|wxRICHTEXT_HITTEST_OUTSIDE
; 
5267 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
5268                 wxArrayInt partialExtents
; 
5273                 // This calculates the partial text extents 
5274                 GetRangeSize(lineRange
, paraSize
, paraDescent
, dc
, wxRICHTEXT_UNFORMATTED
, linePos
, & partialExtents
); 
5276                 int lastX 
= linePos
.x
; 
5278                 for (i 
= 0; i 
< partialExtents
.GetCount(); i
++) 
5280                     int nextX 
= partialExtents
[i
] + linePos
.x
; 
5282                     if (pt
.x 
>= lastX 
&& pt
.x 
<= nextX
) 
5284                         textPosition 
= i 
+ lineRange
.GetStart(); // minus 1? 
5286                         *obj 
= FindObjectAtPosition(textPosition
); 
5287                         *contextObj 
= GetContainer(); 
5289                         // So now we know it's between i-1 and i. 
5290                         // Let's see if we can be more precise about 
5291                         // which side of the position it's on. 
5293                         int midPoint 
= (nextX 
+ lastX
)/2; 
5294                         if (pt
.x 
>= midPoint
) 
5295                             return wxRICHTEXT_HITTEST_AFTER
; 
5297                             return wxRICHTEXT_HITTEST_BEFORE
; 
5304                 int lastX 
= linePos
.x
; 
5305                 for (i 
= lineRange
.GetStart(); i 
<= lineRange
.GetEnd(); i
++) 
5310                     wxRichTextRange 
rangeToUse(lineRange
.GetStart(), i
); 
5312                     GetRangeSize(rangeToUse
, childSize
, descent
, dc
, wxRICHTEXT_UNFORMATTED
, linePos
); 
5314                     int nextX 
= childSize
.x 
+ linePos
.x
; 
5316                     if (pt
.x 
>= lastX 
&& pt
.x 
<= nextX
) 
5320                         *obj 
= FindObjectAtPosition(textPosition
); 
5321                         *contextObj 
= GetContainer(); 
5323                         // So now we know it's between i-1 and i. 
5324                         // Let's see if we can be more precise about 
5325                         // which side of the position it's on. 
5327                         int midPoint 
= (nextX 
+ lastX
)/2; 
5328                         if (pt
.x 
>= midPoint
) 
5329                             return wxRICHTEXT_HITTEST_AFTER
; 
5331                             return wxRICHTEXT_HITTEST_BEFORE
; 
5342         node 
= node
->GetNext(); 
5345     return wxRICHTEXT_HITTEST_NONE
; 
5348 /// Split an object at this position if necessary, and return 
5349 /// the previous object, or NULL if inserting at beginning. 
5350 wxRichTextObject
* wxRichTextParagraph::SplitAt(long pos
, wxRichTextObject
** previousObject
) 
5352     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
5355         wxRichTextObject
* child 
= node
->GetData(); 
5357         if (pos 
== child
->GetRange().GetStart()) 
5361                 if (node
->GetPrevious()) 
5362                     *previousObject 
= node
->GetPrevious()->GetData(); 
5364                     *previousObject 
= NULL
; 
5370         if (child
->GetRange().Contains(pos
)) 
5372             // This should create a new object, transferring part of 
5373             // the content to the old object and the rest to the new object. 
5374             wxRichTextObject
* newObject 
= child
->DoSplit(pos
); 
5376             // If we couldn't split this object, just insert in front of it. 
5379                 // Maybe this is an empty string, try the next one 
5384                 // Insert the new object after 'child' 
5385                 if (node
->GetNext()) 
5386                     m_children
.Insert(node
->GetNext(), newObject
); 
5388                     m_children
.Append(newObject
); 
5389                 newObject
->SetParent(this); 
5392                     *previousObject 
= child
; 
5398         node 
= node
->GetNext(); 
5401         *previousObject 
= NULL
; 
5405 /// Move content to a list from obj on 
5406 void wxRichTextParagraph::MoveToList(wxRichTextObject
* obj
, wxList
& list
) 
5408     wxRichTextObjectList::compatibility_iterator node 
= m_children
.Find(obj
); 
5411         wxRichTextObject
* child 
= node
->GetData(); 
5414         wxRichTextObjectList::compatibility_iterator oldNode 
= node
; 
5416         node 
= node
->GetNext(); 
5418         m_children
.DeleteNode(oldNode
); 
5422 /// Add content back from list 
5423 void wxRichTextParagraph::MoveFromList(wxList
& list
) 
5425     for (wxList::compatibility_iterator node 
= list
.GetFirst(); node
; node 
= node
->GetNext()) 
5427         AppendChild((wxRichTextObject
*) node
->GetData()); 
5432 void wxRichTextParagraph::CalculateRange(long start
, long& end
) 
5434     wxRichTextCompositeObject::CalculateRange(start
, end
); 
5436     // Add one for end of paragraph 
5439     m_range
.SetRange(start
, end
); 
5442 /// Find the object at the given position 
5443 wxRichTextObject
* wxRichTextParagraph::FindObjectAtPosition(long position
) 
5445     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
5448         wxRichTextObject
* obj 
= node
->GetData(); 
5449         if (obj
->GetRange().Contains(position
) || 
5450             obj
->GetRange().GetStart() == position 
|| 
5451             obj
->GetRange().GetEnd() == position
) 
5454         node 
= node
->GetNext(); 
5459 /// Get the plain text searching from the start or end of the range. 
5460 /// The resulting string may be shorter than the range given. 
5461 bool wxRichTextParagraph::GetContiguousPlainText(wxString
& text
, const wxRichTextRange
& range
, bool fromStart
) 
5463     text 
= wxEmptyString
; 
5467         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
5470             wxRichTextObject
* obj 
= node
->GetData(); 
5471             if (!obj
->GetRange().IsOutside(range
)) 
5473                 wxRichTextPlainText
* textObj 
= wxDynamicCast(obj
, wxRichTextPlainText
); 
5476                     text 
+= textObj
->GetTextForRange(range
); 
5484             node 
= node
->GetNext(); 
5489         wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetLast(); 
5492             wxRichTextObject
* obj 
= node
->GetData(); 
5493             if (!obj
->GetRange().IsOutside(range
)) 
5495                 wxRichTextPlainText
* textObj 
= wxDynamicCast(obj
, wxRichTextPlainText
); 
5498                     text 
= textObj
->GetTextForRange(range
) + text
; 
5502                     text 
= wxT(" ") + text
; 
5506             node 
= node
->GetPrevious(); 
5513 /// Find a suitable wrap position. 
5514 bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange
& range
, wxDC
& dc
, int availableSpace
, long& wrapPosition
, wxArrayInt
* partialExtents
) 
5516     if (range
.GetLength() <= 0) 
5519     // Find the first position where the line exceeds the available space. 
5521     long breakPosition 
= range
.GetEnd(); 
5523 #if wxRICHTEXT_USE_PARTIAL_TEXT_EXTENTS 
5524     if (partialExtents 
&& partialExtents
->GetCount() >= (size_t) (GetRange().GetLength()-1)) // the final position in a paragraph is the newline 
5528         if (range
.GetStart() > GetRange().GetStart()) 
5529             widthBefore 
= (*partialExtents
)[range
.GetStart() - GetRange().GetStart() - 1]; 
5534         for (i 
= (size_t) range
.GetStart(); i 
<= (size_t) range
.GetEnd(); i
++) 
5536             int widthFromStartOfThisRange 
= (*partialExtents
)[i 
- GetRange().GetStart()] - widthBefore
; 
5538             if (widthFromStartOfThisRange 
> availableSpace
) 
5540                 breakPosition 
= i
-1; 
5548         // Binary chop for speed 
5549         long minPos 
= range
.GetStart(); 
5550         long maxPos 
= range
.GetEnd(); 
5553             if (minPos 
== maxPos
) 
5556                 GetRangeSize(wxRichTextRange(range
.GetStart(), minPos
), sz
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
5558                 if (sz
.x 
> availableSpace
) 
5559                     breakPosition 
= minPos 
- 1; 
5562             else if ((maxPos 
- minPos
) == 1) 
5565                 GetRangeSize(wxRichTextRange(range
.GetStart(), minPos
), sz
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
5567                 if (sz
.x 
> availableSpace
) 
5568                     breakPosition 
= minPos 
- 1; 
5571                     GetRangeSize(wxRichTextRange(range
.GetStart(), maxPos
), sz
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
5572                     if (sz
.x 
> availableSpace
) 
5573                         breakPosition 
= maxPos
-1; 
5579                 long nextPos 
= minPos 
+ ((maxPos 
- minPos
) / 2); 
5582                 GetRangeSize(wxRichTextRange(range
.GetStart(), nextPos
), sz
, descent
, dc
, wxRICHTEXT_UNFORMATTED
); 
5584                 if (sz
.x 
> availableSpace
) 
5596     // Now we know the last position on the line. 
5597     // Let's try to find a word break. 
5600     if (GetContiguousPlainText(plainText
, wxRichTextRange(range
.GetStart(), breakPosition
), false)) 
5602         int newLinePos 
= plainText
.Find(wxRichTextLineBreakChar
); 
5603         if (newLinePos 
!= wxNOT_FOUND
) 
5605             breakPosition 
= wxMax(0, range
.GetStart() + newLinePos
); 
5609             int spacePos 
= plainText
.Find(wxT(' '), true); 
5610             int tabPos 
= plainText
.Find(wxT('\t'), true); 
5611             int pos 
= wxMax(spacePos
, tabPos
); 
5612             if (pos 
!= wxNOT_FOUND
) 
5614                 int positionsFromEndOfString 
= plainText
.length() - pos 
- 1; 
5615                 breakPosition 
= breakPosition 
- positionsFromEndOfString
; 
5620     wrapPosition 
= breakPosition
; 
5625 /// Get the bullet text for this paragraph. 
5626 wxString 
wxRichTextParagraph::GetBulletText() 
5628     if (GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE 
|| 
5629         (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP
)) 
5630         return wxEmptyString
; 
5632     int number 
= GetAttributes().GetBulletNumber(); 
5635     if ((GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ARABIC
) || (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE
)) 
5637         text
.Printf(wxT("%d"), number
); 
5639     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_LETTERS_UPPER
) 
5641         // TODO: Unicode, and also check if number > 26 
5642         text
.Printf(wxT("%c"), (wxChar
) (number
+64)); 
5644     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_LETTERS_LOWER
) 
5646         // TODO: Unicode, and also check if number > 26 
5647         text
.Printf(wxT("%c"), (wxChar
) (number
+96)); 
5649     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ROMAN_UPPER
) 
5651         text 
= wxRichTextDecimalToRoman(number
); 
5653     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ROMAN_LOWER
) 
5655         text 
= wxRichTextDecimalToRoman(number
); 
5658     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
) 
5660         text 
= GetAttributes().GetBulletText(); 
5663     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE
) 
5665         // The outline style relies on the text being computed statically, 
5666         // since it depends on other levels points (e.g. 1.2.1.1). So normally the bullet text 
5667         // should be stored in the attributes; if not, just use the number for this 
5668         // level, as previously computed. 
5669         if (!GetAttributes().GetBulletText().IsEmpty()) 
5670             text 
= GetAttributes().GetBulletText(); 
5673     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_PARENTHESES
) 
5675         text 
= wxT("(") + text 
+ wxT(")"); 
5677     else if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_RIGHT_PARENTHESIS
) 
5679         text 
= text 
+ wxT(")"); 
5682     if (GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_PERIOD
) 
5690 /// Allocate or reuse a line object 
5691 wxRichTextLine
* wxRichTextParagraph::AllocateLine(int pos
) 
5693     if (pos 
< (int) m_cachedLines
.GetCount()) 
5695         wxRichTextLine
* line 
= m_cachedLines
.Item(pos
)->GetData(); 
5701         wxRichTextLine
* line 
= new wxRichTextLine(this); 
5702         m_cachedLines
.Append(line
); 
5707 /// Clear remaining unused line objects, if any 
5708 bool wxRichTextParagraph::ClearUnusedLines(int lineCount
) 
5710     int cachedLineCount 
= m_cachedLines
.GetCount(); 
5711     if ((int) cachedLineCount 
> lineCount
) 
5713         for (int i 
= 0; i 
< (int) (cachedLineCount 
- lineCount
); i 
++) 
5715             wxRichTextLineList::compatibility_iterator node 
= m_cachedLines
.GetLast(); 
5716             wxRichTextLine
* line 
= node
->GetData(); 
5717             m_cachedLines
.Erase(node
); 
5724 /// Get combined attributes of the base style, paragraph style and character style. We use this to dynamically 
5725 /// retrieve the actual style. 
5726 wxRichTextAttr 
wxRichTextParagraph::GetCombinedAttributes(const wxRichTextAttr
& contentStyle
, bool includingBoxAttr
) const 
5728     wxRichTextAttr attr
; 
5729     wxRichTextParagraphLayoutBox
* buf 
= wxDynamicCast(GetParent(), wxRichTextParagraphLayoutBox
); 
5732         attr 
= buf
->GetBasicStyle(); 
5733         if (!includingBoxAttr
) 
5735             attr
.GetTextBoxAttr().Reset(); 
5736             // The background colour will be painted by the container, and we don't 
5737             // want to unnecessarily overwrite the background when we're drawing text 
5738             // because this may erase the guideline (which appears just under the text 
5739             // if there's no padding). 
5740             attr
.SetFlags(attr
.GetFlags() & ~wxTEXT_ATTR_BACKGROUND_COLOUR
); 
5742         wxRichTextApplyStyle(attr
, GetAttributes()); 
5745         attr 
= GetAttributes(); 
5747     wxRichTextApplyStyle(attr
, contentStyle
); 
5751 /// Get combined attributes of the base style and paragraph style. 
5752 wxRichTextAttr 
wxRichTextParagraph::GetCombinedAttributes(bool includingBoxAttr
) const 
5754     wxRichTextAttr attr
; 
5755     wxRichTextParagraphLayoutBox
* buf 
= wxDynamicCast(GetParent(), wxRichTextParagraphLayoutBox
); 
5758         attr 
= buf
->GetBasicStyle(); 
5759         if (!includingBoxAttr
) 
5760             attr
.GetTextBoxAttr().Reset(); 
5761         wxRichTextApplyStyle(attr
, GetAttributes()); 
5764         attr 
= GetAttributes(); 
5769 // Create default tabstop array 
5770 void wxRichTextParagraph::InitDefaultTabs() 
5772     // create a default tab list at 10 mm each. 
5773     for (int i 
= 0; i 
< 20; ++i
) 
5775         sm_defaultTabs
.Add(i
*100); 
5779 // Clear default tabstop array 
5780 void wxRichTextParagraph::ClearDefaultTabs() 
5782     sm_defaultTabs
.Clear(); 
5785 void wxRichTextParagraph::LayoutFloat(wxDC
& dc
, const wxRect
& rect
, int style
, wxRichTextFloatCollector
* floatCollector
) 
5787     wxRichTextObjectList::compatibility_iterator node 
= GetChildren().GetFirst(); 
5790         wxRichTextObject
* anchored 
= node
->GetData(); 
5791         if (anchored 
&& anchored
->IsFloating() && !floatCollector
->HasFloat(anchored
)) 
5795             anchored
->GetRangeSize(anchored
->GetRange(), size
, descent
, dc
, style
); 
5798             if (anchored
->GetAttributes().GetTextBoxAttr().GetTop().IsValid()) 
5800                 offsetY 
= anchored
->GetAttributes().GetTextBoxAttr().GetTop().GetValue(); 
5801                 if (anchored
->GetAttributes().GetTextBoxAttr().GetTop().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
5803                     offsetY 
= ConvertTenthsMMToPixels(dc
, offsetY
); 
5807             int pos 
= floatCollector
->GetFitPosition(anchored
->GetAttributes().GetTextBoxAttr().GetFloatMode(), rect
.y 
+ offsetY
, size
.y
); 
5809             /* Update the offset */ 
5810             int newOffsetY 
= pos 
- rect
.y
; 
5811             if (newOffsetY 
!= offsetY
) 
5813                 if (anchored
->GetAttributes().GetTextBoxAttr().GetTop().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
5814                     newOffsetY 
= ConvertPixelsToTenthsMM(dc
, newOffsetY
); 
5815                 anchored
->GetAttributes().GetTextBoxAttr().GetTop().SetValue(newOffsetY
); 
5818             if (anchored
->GetAttributes().GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_LEFT
) 
5820             else if (anchored
->GetAttributes().GetTextBoxAttr().GetFloatMode() == wxTEXT_BOX_ATTR_FLOAT_RIGHT
) 
5821                 x 
= rect
.x 
+ rect
.width 
- size
.x
; 
5823             anchored
->SetPosition(wxPoint(x
, pos
)); 
5824             anchored
->SetCachedSize(size
); 
5825             floatCollector
->CollectFloat(this, anchored
); 
5828         node 
= node
->GetNext(); 
5832 // Get the first position from pos that has a line break character. 
5833 long wxRichTextParagraph::GetFirstLineBreakPosition(long pos
) 
5835     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
5838         wxRichTextObject
* obj 
= node
->GetData(); 
5839         if (pos 
>= obj
->GetRange().GetStart() && pos 
<= obj
->GetRange().GetEnd()) 
5841             wxRichTextPlainText
* textObj 
= wxDynamicCast(obj
, wxRichTextPlainText
); 
5844                 long breakPos 
= textObj
->GetFirstLineBreakPosition(pos
); 
5849         node 
= node
->GetNext(); 
5856  * This object represents a line in a paragraph, and stores 
5857  * offsets from the start of the paragraph representing the 
5858  * start and end positions of the line. 
5861 wxRichTextLine::wxRichTextLine(wxRichTextParagraph
* parent
) 
5867 void wxRichTextLine::Init(wxRichTextParagraph
* parent
) 
5870     m_range
.SetRange(-1, -1); 
5871     m_pos 
= wxPoint(0, 0); 
5872     m_size 
= wxSize(0, 0); 
5874 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 
5875     m_objectSizes
.Clear(); 
5880 void wxRichTextLine::Copy(const wxRichTextLine
& obj
) 
5882     m_range 
= obj
.m_range
; 
5883 #if wxRICHTEXT_USE_OPTIMIZED_LINE_DRAWING 
5884     m_objectSizes 
= obj
.m_objectSizes
; 
5888 /// Get the absolute object position 
5889 wxPoint 
wxRichTextLine::GetAbsolutePosition() const 
5891     return m_parent
->GetPosition() + m_pos
; 
5894 /// Get the absolute range 
5895 wxRichTextRange 
wxRichTextLine::GetAbsoluteRange() const 
5897     wxRichTextRange 
range(m_range
.GetStart() + m_parent
->GetRange().GetStart(), 0); 
5898     range
.SetEnd(range
.GetStart() + m_range
.GetLength()-1); 
5903  * wxRichTextPlainText 
5904  * This object represents a single piece of text. 
5907 IMPLEMENT_DYNAMIC_CLASS(wxRichTextPlainText
, wxRichTextObject
) 
5909 wxRichTextPlainText::wxRichTextPlainText(const wxString
& text
, wxRichTextObject
* parent
, wxRichTextAttr
* style
): 
5910     wxRichTextObject(parent
) 
5913         SetAttributes(*style
); 
5918 #define USE_KERNING_FIX 1 
5920 // If insufficient tabs are defined, this is the tab width used 
5921 #define WIDTH_FOR_DEFAULT_TABS 50 
5924 bool wxRichTextPlainText::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int WXUNUSED(style
)) 
5926     wxRichTextParagraph
* para 
= wxDynamicCast(GetParent(), wxRichTextParagraph
); 
5927     wxASSERT (para 
!= NULL
); 
5929     wxRichTextAttr 
textAttr(para 
? para
->GetCombinedAttributes(GetAttributes(), false /* no box attributes */) : GetAttributes()); 
5931     // Let's make the assumption for now that for content in a paragraph, including 
5932     // text, we never have a discontinuous selection. So we only deal with a 
5934     wxRichTextRange selectionRange
; 
5935     if (selection
.IsValid()) 
5937         wxRichTextRangeArray selectionRanges 
= selection
.GetSelectionForObject(this); 
5938         if (selectionRanges
.GetCount() > 0) 
5939             selectionRange 
= selectionRanges
[0]; 
5941             selectionRange 
= wxRICHTEXT_NO_SELECTION
; 
5944         selectionRange 
= wxRICHTEXT_NO_SELECTION
; 
5946     int offset 
= GetRange().GetStart(); 
5948     // Replace line break characters with spaces 
5949     wxString str 
= m_text
; 
5950     wxString toRemove 
= wxRichTextLineBreakChar
; 
5951     str
.Replace(toRemove
, wxT(" ")); 
5952     if (textAttr
.HasTextEffects() && (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS
)) 
5955     long len 
= range
.GetLength(); 
5956     wxString stringChunk 
= str
.Mid(range
.GetStart() - offset
, (size_t) len
); 
5958     // Test for the optimized situations where all is selected, or none 
5961     wxFont 
textFont(GetBuffer()->GetFontTable().FindFont(textAttr
)); 
5962     wxCheckSetFont(dc
, textFont
); 
5963     int charHeight 
= dc
.GetCharHeight(); 
5966     if ( textFont
.IsOk() ) 
5968         if ( textAttr
.HasTextEffects() && (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT
) ) 
5970             double size 
= static_cast<double>(textFont
.GetPointSize()) / wxSCRIPT_MUL_FACTOR
; 
5971             textFont
.SetPointSize( static_cast<int>(size
) ); 
5974             wxCheckSetFont(dc
, textFont
); 
5976         else if ( textAttr
.HasTextEffects() && (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT
) ) 
5978             double size 
= static_cast<double>(textFont
.GetPointSize()) / wxSCRIPT_MUL_FACTOR
; 
5979             textFont
.SetPointSize( static_cast<int>(size
) ); 
5981             int sub_height 
= static_cast<int>( static_cast<double>(charHeight
) / wxSCRIPT_MUL_FACTOR
); 
5982             y 
= rect
.y 
+ (rect
.height 
- sub_height 
+ (descent 
- m_descent
)); 
5983             wxCheckSetFont(dc
, textFont
); 
5988             y 
= rect
.y 
+ (rect
.height 
- charHeight 
- (descent 
- m_descent
)); 
5994         y 
= rect
.y 
+ (rect
.height 
- charHeight 
- (descent 
- m_descent
)); 
5997     // TODO: new selection code 
5999     // (a) All selected. 
6000     if (selectionRange
.GetStart() <= range
.GetStart() && selectionRange
.GetEnd() >= range
.GetEnd()) 
6002         DrawTabbedString(dc
, textAttr
, rect
, stringChunk
, x
, y
, true); 
6004     // (b) None selected. 
6005     else if (selectionRange
.GetEnd() < range
.GetStart() || selectionRange
.GetStart() > range
.GetEnd()) 
6007         // Draw all unselected 
6008         DrawTabbedString(dc
, textAttr
, rect
, stringChunk
, x
, y
, false); 
6012         // (c) Part selected, part not 
6013         // Let's draw unselected chunk, selected chunk, then unselected chunk. 
6015         dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
6017         // 1. Initial unselected chunk, if any, up until start of selection. 
6018         if (selectionRange
.GetStart() > range
.GetStart() && selectionRange
.GetStart() <= range
.GetEnd()) 
6020             int r1 
= range
.GetStart(); 
6021             int s1 
= selectionRange
.GetStart()-1; 
6022             int fragmentLen 
= s1 
- r1 
+ 1; 
6023             if (fragmentLen 
< 0) 
6025                 wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 
- offset
), (int)fragmentLen
); 
6027             wxString stringFragment 
= str
.Mid(r1 
- offset
, fragmentLen
); 
6029             DrawTabbedString(dc
, textAttr
, rect
, stringFragment
, x
, y
, false); 
6032             if (stringChunk
.Find(wxT("\t")) == wxNOT_FOUND
) 
6034                 // Compensate for kerning difference 
6035                 wxString 
stringFragment2(str
.Mid(r1 
- offset
, fragmentLen
+1)); 
6036                 wxString 
stringFragment3(str
.Mid(r1 
- offset 
+ fragmentLen
, 1)); 
6038                 wxCoord w1
, h1
, w2
, h2
, w3
, h3
; 
6039                 dc
.GetTextExtent(stringFragment
,  & w1
, & h1
); 
6040                 dc
.GetTextExtent(stringFragment2
, & w2
, & h2
); 
6041                 dc
.GetTextExtent(stringFragment3
, & w3
, & h3
); 
6043                 int kerningDiff 
= (w1 
+ w3
) - w2
; 
6044                 x 
= x 
- kerningDiff
; 
6049         // 2. Selected chunk, if any. 
6050         if (selectionRange
.GetEnd() >= range
.GetStart()) 
6052             int s1 
= wxMax(selectionRange
.GetStart(), range
.GetStart()); 
6053             int s2 
= wxMin(selectionRange
.GetEnd(), range
.GetEnd()); 
6055             int fragmentLen 
= s2 
- s1 
+ 1; 
6056             if (fragmentLen 
< 0) 
6058                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 
- offset
), (int)fragmentLen
); 
6060             wxString stringFragment 
= str
.Mid(s1 
- offset
, fragmentLen
); 
6062             DrawTabbedString(dc
, textAttr
, rect
, stringFragment
, x
, y
, true); 
6065             if (stringChunk
.Find(wxT("\t")) == wxNOT_FOUND
) 
6067                 // Compensate for kerning difference 
6068                 wxString 
stringFragment2(str
.Mid(s1 
- offset
, fragmentLen
+1)); 
6069                 wxString 
stringFragment3(str
.Mid(s1 
- offset 
+ fragmentLen
, 1)); 
6071                 wxCoord w1
, h1
, w2
, h2
, w3
, h3
; 
6072                 dc
.GetTextExtent(stringFragment
,  & w1
, & h1
); 
6073                 dc
.GetTextExtent(stringFragment2
, & w2
, & h2
); 
6074                 dc
.GetTextExtent(stringFragment3
, & w3
, & h3
); 
6076                 int kerningDiff 
= (w1 
+ w3
) - w2
; 
6077                 x 
= x 
- kerningDiff
; 
6082         // 3. Remaining unselected chunk, if any 
6083         if (selectionRange
.GetEnd() < range
.GetEnd()) 
6085             int s2 
= wxMin(selectionRange
.GetEnd()+1, range
.GetEnd()); 
6086             int r2 
= range
.GetEnd(); 
6088             int fragmentLen 
= r2 
- s2 
+ 1; 
6089             if (fragmentLen 
< 0) 
6091                 wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 
- offset
), (int)fragmentLen
); 
6093             wxString stringFragment 
= str
.Mid(s2 
- offset
, fragmentLen
); 
6095             DrawTabbedString(dc
, textAttr
, rect
, stringFragment
, x
, y
, false); 
6102 bool wxRichTextPlainText::DrawTabbedString(wxDC
& dc
, const wxRichTextAttr
& attr
, const wxRect
& rect
,wxString
& str
, wxCoord
& x
, wxCoord
& y
, bool selected
) 
6104     bool hasTabs 
= (str
.Find(wxT('\t')) != wxNOT_FOUND
); 
6106     wxArrayInt tabArray
; 
6110         if (attr
.GetTabs().IsEmpty()) 
6111             tabArray 
= wxRichTextParagraph::GetDefaultTabs(); 
6113             tabArray 
= attr
.GetTabs(); 
6114         tabCount 
= tabArray
.GetCount(); 
6116         for (int i 
= 0; i 
< tabCount
; ++i
) 
6118             int pos 
= tabArray
[i
]; 
6119             pos 
= ConvertTenthsMMToPixels(dc
, pos
); 
6126     int nextTabPos 
= -1; 
6132         wxColour 
highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT
)); 
6133         wxColour 
highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT
)); 
6135         wxCheckSetBrush(dc
, wxBrush(highlightColour
)); 
6136         wxCheckSetPen(dc
, wxPen(highlightColour
)); 
6137         dc
.SetTextForeground(highlightTextColour
); 
6138         dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
6142         dc
.SetTextForeground(attr
.GetTextColour()); 
6144         if (attr
.HasFlag(wxTEXT_ATTR_BACKGROUND_COLOUR
) && attr
.GetBackgroundColour().IsOk()) 
6146             dc
.SetBackgroundMode(wxBRUSHSTYLE_SOLID
); 
6147             dc
.SetTextBackground(attr
.GetBackgroundColour()); 
6150             dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
6153     wxCoord x_orig 
= GetParent()->GetPosition().x
; 
6156         // the string has a tab 
6157         // break up the string at the Tab 
6158         wxString stringChunk 
= str
.BeforeFirst(wxT('\t')); 
6159         str 
= str
.AfterFirst(wxT('\t')); 
6160         dc
.GetTextExtent(stringChunk
, & w
, & h
); 
6162         bool not_found 
= true; 
6163         for (int i 
= 0; i 
< tabCount 
&& not_found
; ++i
) 
6165             nextTabPos 
= tabArray
.Item(i
) + x_orig
; 
6167             // Find the next tab position. 
6168             // Even if we're at the end of the tab array, we must still draw the chunk. 
6170             if (nextTabPos 
> tabPos 
|| (i 
== (tabCount 
- 1))) 
6172                 if (nextTabPos 
<= tabPos
) 
6174                     int defaultTabWidth 
= ConvertTenthsMMToPixels(dc
, WIDTH_FOR_DEFAULT_TABS
); 
6175                     nextTabPos 
= tabPos 
+ defaultTabWidth
; 
6182                     wxRect 
selRect(x
, rect
.y
, w
, rect
.GetHeight()); 
6183                     dc
.DrawRectangle(selRect
); 
6185                 dc
.DrawText(stringChunk
, x
, y
); 
6187                 if (attr
.HasTextEffects() && (attr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH
)) 
6189                     wxPen oldPen 
= dc
.GetPen(); 
6190                     wxCheckSetPen(dc
, wxPen(attr
.GetTextColour(), 1)); 
6191                     dc
.DrawLine(x
, (int) (y
+(h
/2)+0.5), x
+w
, (int) (y
+(h
/2)+0.5)); 
6192                     wxCheckSetPen(dc
, oldPen
); 
6198         hasTabs 
= (str
.Find(wxT('\t')) != wxNOT_FOUND
); 
6203         dc
.GetTextExtent(str
, & w
, & h
); 
6206             wxRect 
selRect(x
, rect
.y
, w
, rect
.GetHeight()); 
6207             dc
.DrawRectangle(selRect
); 
6209         dc
.DrawText(str
, x
, y
); 
6211         if (attr
.HasTextEffects() && (attr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH
)) 
6213             wxPen oldPen 
= dc
.GetPen(); 
6214             wxCheckSetPen(dc
, wxPen(attr
.GetTextColour(), 1)); 
6215             dc
.DrawLine(x
, (int) (y
+(h
/2)+0.5), x
+w
, (int) (y
+(h
/2)+0.5)); 
6216             wxCheckSetPen(dc
, oldPen
); 
6225 /// Lay the item out 
6226 bool wxRichTextPlainText::Layout(wxDC
& dc
, const wxRect
& WXUNUSED(rect
), int WXUNUSED(style
)) 
6228     // Only lay out if we haven't already cached the size 
6230         GetRangeSize(GetRange(), m_size
, m_descent
, dc
, 0, wxPoint(0, 0)); 
6232     // Eventually we want to have a reasonable estimate of minimum size. 
6233     m_minSize 
= wxSize(0, 0); 
6238 void wxRichTextPlainText::Copy(const wxRichTextPlainText
& obj
) 
6240     wxRichTextObject::Copy(obj
); 
6242     m_text 
= obj
.m_text
; 
6245 /// Get/set the object size for the given range. Returns false if the range 
6246 /// is invalid for this object. 
6247 bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int WXUNUSED(flags
), wxPoint position
, wxArrayInt
* partialExtents
) const 
6249     if (!range
.IsWithin(GetRange())) 
6252     wxRichTextParagraph
* para 
= wxDynamicCast(GetParent(), wxRichTextParagraph
); 
6253     wxASSERT (para 
!= NULL
); 
6255     int relativeX 
= position
.x 
- GetParent()->GetPosition().x
; 
6257     wxRichTextAttr 
textAttr(para 
? para
->GetCombinedAttributes(GetAttributes()) : GetAttributes()); 
6259     // Always assume unformatted text, since at this level we have no knowledge 
6260     // of line breaks - and we don't need it, since we'll calculate size within 
6261     // formatted text by doing it in chunks according to the line ranges 
6263     bool bScript(false); 
6264     wxFont 
font(GetBuffer()->GetFontTable().FindFont(textAttr
)); 
6267         if ( textAttr
.HasTextEffects() && ( (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUPERSCRIPT
) 
6268             || (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_SUBSCRIPT
) ) ) 
6270             wxFont textFont 
= font
; 
6271             double size 
= static_cast<double>(textFont
.GetPointSize()) / wxSCRIPT_MUL_FACTOR
; 
6272             textFont
.SetPointSize( static_cast<int>(size
) ); 
6273             wxCheckSetFont(dc
, textFont
); 
6278             wxCheckSetFont(dc
, font
); 
6282     bool haveDescent 
= false; 
6283     int startPos 
= range
.GetStart() - GetRange().GetStart(); 
6284     long len 
= range
.GetLength(); 
6286     wxString 
str(m_text
); 
6287     wxString toReplace 
= wxRichTextLineBreakChar
; 
6288     str
.Replace(toReplace
, wxT(" ")); 
6290     wxString stringChunk 
= str
.Mid(startPos
, (size_t) len
); 
6292     if (textAttr
.HasTextEffects() && (textAttr
.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS
)) 
6293         stringChunk
.MakeUpper(); 
6297     if (stringChunk
.Find(wxT('\t')) != wxNOT_FOUND
) 
6299         // the string has a tab 
6300         wxArrayInt tabArray
; 
6301         if (textAttr
.GetTabs().IsEmpty()) 
6302             tabArray 
= wxRichTextParagraph::GetDefaultTabs(); 
6304             tabArray 
= textAttr
.GetTabs(); 
6306         int tabCount 
= tabArray
.GetCount(); 
6308         for (int i 
= 0; i 
< tabCount
; ++i
) 
6310             int pos 
= tabArray
[i
]; 
6311             pos 
= ((wxRichTextPlainText
*) this)->ConvertTenthsMMToPixels(dc
, pos
); 
6315         int nextTabPos 
= -1; 
6317         while (stringChunk
.Find(wxT('\t')) >= 0) 
6319             int absoluteWidth 
= 0; 
6321             // the string has a tab 
6322             // break up the string at the Tab 
6323             wxString stringFragment 
= stringChunk
.BeforeFirst(wxT('\t')); 
6324             stringChunk 
= stringChunk
.AfterFirst(wxT('\t')); 
6329                 if (partialExtents
->GetCount() > 0) 
6330                     oldWidth 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
6334                 // Add these partial extents 
6336                 dc
.GetPartialTextExtents(stringFragment
, p
); 
6338                 for (j 
= 0; j 
< p
.GetCount(); j
++) 
6339                     partialExtents
->Add(oldWidth 
+ p
[j
]); 
6341                 if (partialExtents
->GetCount() > 0) 
6342                     absoluteWidth 
= (*partialExtents
)[(*partialExtents
).GetCount()-1] + relativeX
; 
6344                     absoluteWidth 
= relativeX
; 
6348                 dc
.GetTextExtent(stringFragment
, & w
, & h
); 
6350                 absoluteWidth 
= width 
+ relativeX
; 
6354             bool notFound 
= true; 
6355             for (int i 
= 0; i 
< tabCount 
&& notFound
; ++i
) 
6357                 nextTabPos 
= tabArray
.Item(i
); 
6359                 // Find the next tab position. 
6360                 // Even if we're at the end of the tab array, we must still process the chunk. 
6362                 if (nextTabPos 
> absoluteWidth 
|| (i 
== (tabCount 
- 1))) 
6364                     if (nextTabPos 
<= absoluteWidth
) 
6366                         int defaultTabWidth 
= ((wxRichTextPlainText
*) this)->ConvertTenthsMMToPixels(dc
, WIDTH_FOR_DEFAULT_TABS
); 
6367                         nextTabPos 
= absoluteWidth 
+ defaultTabWidth
; 
6371                     width 
= nextTabPos 
- relativeX
; 
6374                         partialExtents
->Add(width
); 
6380     if (!stringChunk
.IsEmpty()) 
6385             if (partialExtents
->GetCount() > 0) 
6386                 oldWidth 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
6390             // Add these partial extents 
6392             dc
.GetPartialTextExtents(stringChunk
, p
); 
6394             for (j 
= 0; j 
< p
.GetCount(); j
++) 
6395                 partialExtents
->Add(oldWidth 
+ p
[j
]); 
6399             dc
.GetTextExtent(stringChunk
, & w
, & h
, & descent
); 
6407         int charHeight 
= dc
.GetCharHeight(); 
6408         if ((*partialExtents
).GetCount() > 0) 
6409             w 
= (*partialExtents
)[partialExtents
->GetCount()-1]; 
6412         size 
= wxSize(w
, charHeight
); 
6416         size 
= wxSize(width
, dc
.GetCharHeight()); 
6420         dc
.GetTextExtent(wxT("X"), & w
, & h
, & descent
); 
6428 /// Do a split, returning an object containing the second part, and setting 
6429 /// the first part in 'this'. 
6430 wxRichTextObject
* wxRichTextPlainText::DoSplit(long pos
) 
6432     long index 
= pos 
- GetRange().GetStart(); 
6434     if (index 
< 0 || index 
>= (int) m_text
.length()) 
6437     wxString firstPart 
= m_text
.Mid(0, index
); 
6438     wxString secondPart 
= m_text
.Mid(index
); 
6442     wxRichTextPlainText
* newObject 
= new wxRichTextPlainText(secondPart
); 
6443     newObject
->SetAttributes(GetAttributes()); 
6445     newObject
->SetRange(wxRichTextRange(pos
, GetRange().GetEnd())); 
6446     GetRange().SetEnd(pos
-1); 
6452 void wxRichTextPlainText::CalculateRange(long start
, long& end
) 
6454     end 
= start 
+ m_text
.length() - 1; 
6455     m_range
.SetRange(start
, end
); 
6459 bool wxRichTextPlainText::DeleteRange(const wxRichTextRange
& range
) 
6461     wxRichTextRange r 
= range
; 
6463     r
.LimitTo(GetRange()); 
6465     if (r
.GetStart() == GetRange().GetStart() && r
.GetEnd() == GetRange().GetEnd()) 
6471     long startIndex 
= r
.GetStart() - GetRange().GetStart(); 
6472     long len 
= r
.GetLength(); 
6474     m_text 
= m_text
.Mid(0, startIndex
) + m_text
.Mid(startIndex
+len
); 
6478 /// Get text for the given range. 
6479 wxString 
wxRichTextPlainText::GetTextForRange(const wxRichTextRange
& range
) const 
6481     wxRichTextRange r 
= range
; 
6483     r
.LimitTo(GetRange()); 
6485     long startIndex 
= r
.GetStart() - GetRange().GetStart(); 
6486     long len 
= r
.GetLength(); 
6488     return m_text
.Mid(startIndex
, len
); 
6491 /// Returns true if this object can merge itself with the given one. 
6492 bool wxRichTextPlainText::CanMerge(wxRichTextObject
* object
) const 
6494     return object
->GetClassInfo() == CLASSINFO(wxRichTextPlainText
) && 
6495         (m_text
.empty() || wxTextAttrEq(GetAttributes(), object
->GetAttributes())); 
6498 /// Returns true if this object merged itself with the given one. 
6499 /// The calling code will then delete the given object. 
6500 bool wxRichTextPlainText::Merge(wxRichTextObject
* object
) 
6502     wxRichTextPlainText
* textObject 
= wxDynamicCast(object
, wxRichTextPlainText
); 
6503     wxASSERT( textObject 
!= NULL 
); 
6507         m_text 
+= textObject
->GetText(); 
6508         wxRichTextApplyStyle(m_attributes
, textObject
->GetAttributes()); 
6515 /// Dump to output stream for debugging 
6516 void wxRichTextPlainText::Dump(wxTextOutputStream
& stream
) 
6518     wxRichTextObject::Dump(stream
); 
6519     stream 
<< m_text 
<< wxT("\n"); 
6522 /// Get the first position from pos that has a line break character. 
6523 long wxRichTextPlainText::GetFirstLineBreakPosition(long pos
) 
6526     int len 
= m_text
.length(); 
6527     int startPos 
= pos 
- m_range
.GetStart(); 
6528     for (i 
= startPos
; i 
< len
; i
++) 
6530         wxChar ch 
= m_text
[i
]; 
6531         if (ch 
== wxRichTextLineBreakChar
) 
6533             return i 
+ m_range
.GetStart(); 
6541  * This is a kind of box, used to represent the whole buffer 
6544 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBuffer
, wxRichTextParagraphLayoutBox
) 
6546 wxList                  
wxRichTextBuffer::sm_handlers
; 
6547 wxRichTextRenderer
*     wxRichTextBuffer::sm_renderer 
= NULL
; 
6548 int                     wxRichTextBuffer::sm_bulletRightMargin 
= 20; 
6549 float                   wxRichTextBuffer::sm_bulletProportion 
= (float) 0.3; 
6552 void wxRichTextBuffer::Init() 
6554     m_commandProcessor 
= new wxCommandProcessor
; 
6555     m_styleSheet 
= NULL
; 
6557     m_batchedCommandDepth 
= 0; 
6558     m_batchedCommand 
= NULL
; 
6565 wxRichTextBuffer::~wxRichTextBuffer() 
6567     delete m_commandProcessor
; 
6568     delete m_batchedCommand
; 
6571     ClearEventHandlers(); 
6574 void wxRichTextBuffer::ResetAndClearCommands() 
6578     GetCommandProcessor()->ClearCommands(); 
6581     Invalidate(wxRICHTEXT_ALL
); 
6584 void wxRichTextBuffer::Copy(const wxRichTextBuffer
& obj
) 
6586     wxRichTextParagraphLayoutBox::Copy(obj
); 
6588     m_styleSheet 
= obj
.m_styleSheet
; 
6589     m_modified 
= obj
.m_modified
; 
6590     m_batchedCommandDepth 
= 0; 
6591     if (m_batchedCommand
) 
6592         delete m_batchedCommand
; 
6593     m_batchedCommand 
= NULL
; 
6594     m_suppressUndo 
= obj
.m_suppressUndo
; 
6595     m_invalidRange 
= obj
.m_invalidRange
; 
6598 /// Push style sheet to top of stack 
6599 bool wxRichTextBuffer::PushStyleSheet(wxRichTextStyleSheet
* styleSheet
) 
6602         styleSheet
->InsertSheet(m_styleSheet
); 
6604     SetStyleSheet(styleSheet
); 
6609 /// Pop style sheet from top of stack 
6610 wxRichTextStyleSheet
* wxRichTextBuffer::PopStyleSheet() 
6614         wxRichTextStyleSheet
* oldSheet 
= m_styleSheet
; 
6615         m_styleSheet 
= oldSheet
->GetNextSheet(); 
6624 /// Submit command to insert paragraphs 
6625 bool wxRichTextBuffer::InsertParagraphsWithUndo(long pos
, const wxRichTextParagraphLayoutBox
& paragraphs
, wxRichTextCtrl
* ctrl
, int flags
) 
6627     return ctrl
->GetFocusObject()->InsertParagraphsWithUndo(pos
, paragraphs
, ctrl
, this, flags
); 
6630 /// Submit command to insert paragraphs 
6631 bool wxRichTextParagraphLayoutBox::InsertParagraphsWithUndo(long pos
, const wxRichTextParagraphLayoutBox
& paragraphs
, wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
, int WXUNUSED(flags
)) 
6633     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Text"), wxRICHTEXT_INSERT
, buffer
, this, ctrl
, false); 
6635     action
->GetNewParagraphs() = paragraphs
; 
6637     action
->SetPosition(pos
); 
6639     wxRichTextRange range 
= wxRichTextRange(pos
, pos 
+ paragraphs
.GetOwnRange().GetEnd() - 1); 
6640     if (!paragraphs
.GetPartialParagraph()) 
6641         range
.SetEnd(range
.GetEnd()+1); 
6643     // Set the range we'll need to delete in Undo 
6644     action
->SetRange(range
); 
6646     buffer
->SubmitAction(action
); 
6651 /// Submit command to insert the given text 
6652 bool wxRichTextBuffer::InsertTextWithUndo(long pos
, const wxString
& text
, wxRichTextCtrl
* ctrl
, int flags
) 
6654     return ctrl
->GetFocusObject()->InsertTextWithUndo(pos
, text
, ctrl
, this, flags
); 
6657 /// Submit command to insert the given text 
6658 bool wxRichTextParagraphLayoutBox::InsertTextWithUndo(long pos
, const wxString
& text
, wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
, int flags
) 
6660     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Text"), wxRICHTEXT_INSERT
, buffer
, this, ctrl
, false); 
6662     wxRichTextAttr
* p 
= NULL
; 
6663     wxRichTextAttr paraAttr
; 
6664     if (flags 
& wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
) 
6666         // Get appropriate paragraph style 
6667         paraAttr 
= GetStyleForNewParagraph(buffer
, pos
, false, false); 
6668         if (!paraAttr
.IsDefault()) 
6672     action
->GetNewParagraphs().AddParagraphs(text
, p
); 
6674     int length 
= action
->GetNewParagraphs().GetOwnRange().GetLength(); 
6676     if (!text
.empty() && text
.Last() != wxT('\n')) 
6678         // Don't count the newline when undoing 
6680         action
->GetNewParagraphs().SetPartialParagraph(true); 
6682     else if (!text
.empty() && text
.Last() == wxT('\n')) 
6685     action
->SetPosition(pos
); 
6687     // Set the range we'll need to delete in Undo 
6688     action
->SetRange(wxRichTextRange(pos
, pos 
+ length 
- 1)); 
6690     buffer
->SubmitAction(action
); 
6695 /// Submit command to insert the given text 
6696 bool wxRichTextBuffer::InsertNewlineWithUndo(long pos
, wxRichTextCtrl
* ctrl
, int flags
) 
6698     return ctrl
->GetFocusObject()->InsertNewlineWithUndo(pos
, ctrl
, this, flags
); 
6701 /// Submit command to insert the given text 
6702 bool wxRichTextParagraphLayoutBox::InsertNewlineWithUndo(long pos
, wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
, int flags
) 
6704     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Text"), wxRICHTEXT_INSERT
, buffer
, this, ctrl
, false); 
6706     wxRichTextAttr
* p 
= NULL
; 
6707     wxRichTextAttr paraAttr
; 
6708     if (flags 
& wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
) 
6710         paraAttr 
= GetStyleForNewParagraph(buffer
, pos
, false, true /* look for next paragraph style */); 
6711         if (!paraAttr
.IsDefault()) 
6715     wxRichTextAttr 
attr(buffer
->GetDefaultStyle()); 
6717     wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(wxEmptyString
, this, & attr
); 
6718     action
->GetNewParagraphs().AppendChild(newPara
); 
6719     action
->GetNewParagraphs().UpdateRanges(); 
6720     action
->GetNewParagraphs().SetPartialParagraph(false); 
6721     wxRichTextParagraph
* para 
= GetParagraphAtPosition(pos
, false); 
6725         newPara
->SetAttributes(*p
); 
6727     if (flags 
& wxRICHTEXT_INSERT_INTERACTIVE
) 
6729         if (para 
&& para
->GetRange().GetEnd() == pos
) 
6732         // Now see if we need to number the paragraph. 
6733         if (newPara
->GetAttributes().HasBulletNumber()) 
6735             wxRichTextAttr numberingAttr
; 
6736             if (FindNextParagraphNumber(para
, numberingAttr
)) 
6737                 wxRichTextApplyStyle(newPara
->GetAttributes(), (const wxRichTextAttr
&) numberingAttr
); 
6741     action
->SetPosition(pos
); 
6743     // Use the default character style 
6744     // Use the default character style 
6745     if (!buffer
->GetDefaultStyle().IsDefault() && newPara
->GetChildren().GetFirst()) 
6747         // Check whether the default style merely reflects the paragraph/basic style, 
6748         // in which case don't apply it. 
6749         wxRichTextAttr 
defaultStyle(buffer
->GetDefaultStyle()); 
6750         wxRichTextAttr toApply
; 
6753             wxRichTextAttr combinedAttr 
= para
->GetCombinedAttributes(true /* include box attributes */); 
6754             wxRichTextAttr newAttr
; 
6755             // This filters out attributes that are accounted for by the current 
6756             // paragraph/basic style 
6757             wxRichTextApplyStyle(toApply
, defaultStyle
, & combinedAttr
); 
6760             toApply 
= defaultStyle
; 
6762         if (!toApply
.IsDefault()) 
6763             newPara
->GetChildren().GetFirst()->GetData()->SetAttributes(toApply
); 
6766     // Set the range we'll need to delete in Undo 
6767     action
->SetRange(wxRichTextRange(pos1
, pos1
)); 
6769     buffer
->SubmitAction(action
); 
6774 /// Submit command to insert the given image 
6775 bool wxRichTextBuffer::InsertImageWithUndo(long pos
, const wxRichTextImageBlock
& imageBlock
, wxRichTextCtrl
* ctrl
, int flags
, 
6776                                             const wxRichTextAttr
& textAttr
) 
6778     return ctrl
->GetFocusObject()->InsertImageWithUndo(pos
, imageBlock
, ctrl
, this, flags
, textAttr
); 
6781 /// Submit command to insert the given image 
6782 bool wxRichTextParagraphLayoutBox::InsertImageWithUndo(long pos
, const wxRichTextImageBlock
& imageBlock
, 
6783                                                         wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
, int flags
, 
6784                                                         const wxRichTextAttr
& textAttr
) 
6786     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Image"), wxRICHTEXT_INSERT
, buffer
, this, ctrl
, false); 
6788     wxRichTextAttr
* p 
= NULL
; 
6789     wxRichTextAttr paraAttr
; 
6790     if (flags 
& wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
) 
6792         paraAttr 
= GetStyleForNewParagraph(buffer
, pos
); 
6793         if (!paraAttr
.IsDefault()) 
6797     wxRichTextAttr 
attr(buffer
->GetDefaultStyle()); 
6799     wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(this, & attr
); 
6801         newPara
->SetAttributes(*p
); 
6803     wxRichTextImage
* imageObject 
= new wxRichTextImage(imageBlock
, newPara
); 
6804     newPara
->AppendChild(imageObject
); 
6805     imageObject
->SetAttributes(textAttr
); 
6806     action
->GetNewParagraphs().AppendChild(newPara
); 
6807     action
->GetNewParagraphs().UpdateRanges(); 
6809     action
->GetNewParagraphs().SetPartialParagraph(true); 
6811     action
->SetPosition(pos
); 
6813     // Set the range we'll need to delete in Undo 
6814     action
->SetRange(wxRichTextRange(pos
, pos
)); 
6816     buffer
->SubmitAction(action
); 
6821 // Insert an object with no change of it 
6822 wxRichTextObject
* wxRichTextBuffer::InsertObjectWithUndo(long pos
, wxRichTextObject 
*object
, wxRichTextCtrl
* ctrl
, int flags
) 
6824     return ctrl
->GetFocusObject()->InsertObjectWithUndo(pos
, object
, ctrl
, this, flags
); 
6827 // Insert an object with no change of it 
6828 wxRichTextObject
* wxRichTextParagraphLayoutBox::InsertObjectWithUndo(long pos
, wxRichTextObject 
*object
, wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
, int flags
) 
6830     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Object"), wxRICHTEXT_INSERT
, buffer
, this, ctrl
, false); 
6832     wxRichTextAttr
* p 
= NULL
; 
6833     wxRichTextAttr paraAttr
; 
6834     if (flags 
& wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
) 
6836         paraAttr 
= GetStyleForNewParagraph(buffer
, pos
); 
6837         if (!paraAttr
.IsDefault()) 
6841     wxRichTextAttr 
attr(buffer
->GetDefaultStyle()); 
6843     wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(this, & attr
); 
6845         newPara
->SetAttributes(*p
); 
6847     newPara
->AppendChild(object
); 
6848     action
->GetNewParagraphs().AppendChild(newPara
); 
6849     action
->GetNewParagraphs().UpdateRanges(); 
6851     action
->GetNewParagraphs().SetPartialParagraph(true); 
6853     action
->SetPosition(pos
); 
6855     // Set the range we'll need to delete in Undo 
6856     action
->SetRange(wxRichTextRange(pos
, pos
)); 
6858     buffer
->SubmitAction(action
); 
6860     wxRichTextObject
* obj 
= GetLeafObjectAtPosition(pos
); 
6864 /// Get the style that is appropriate for a new paragraph at this position. 
6865 /// If the previous paragraph has a paragraph style name, look up the next-paragraph 
6867 wxRichTextAttr 
wxRichTextParagraphLayoutBox::GetStyleForNewParagraph(wxRichTextBuffer
* buffer
, long pos
, bool caretPosition
, bool lookUpNewParaStyle
) const 
6869     wxRichTextParagraph
* para 
= GetParagraphAtPosition(pos
, caretPosition
); 
6872         wxRichTextAttr attr
; 
6873         bool foundAttributes 
= false; 
6875         // Look for a matching paragraph style 
6876         if (lookUpNewParaStyle 
&& !para
->GetAttributes().GetParagraphStyleName().IsEmpty() && buffer
->GetStyleSheet()) 
6878             wxRichTextParagraphStyleDefinition
* paraDef 
= buffer
->GetStyleSheet()->FindParagraphStyle(para
->GetAttributes().GetParagraphStyleName()); 
6881                 // If we're not at the end of the paragraph, then we apply THIS style, and not the designated next style. 
6882                 if (para
->GetRange().GetEnd() == pos 
&& !paraDef
->GetNextStyle().IsEmpty()) 
6884                     wxRichTextParagraphStyleDefinition
* nextParaDef 
= buffer
->GetStyleSheet()->FindParagraphStyle(paraDef
->GetNextStyle()); 
6887                         foundAttributes 
= true; 
6888                         attr 
= nextParaDef
->GetStyleMergedWithBase(buffer
->GetStyleSheet()); 
6892                 // If we didn't find the 'next style', use this style instead. 
6893                 if (!foundAttributes
) 
6895                     foundAttributes 
= true; 
6896                     attr 
= paraDef
->GetStyleMergedWithBase(buffer
->GetStyleSheet()); 
6901         // Also apply list style if present 
6902         if (lookUpNewParaStyle 
&& !para
->GetAttributes().GetListStyleName().IsEmpty() && buffer
->GetStyleSheet()) 
6904             wxRichTextListStyleDefinition
* listDef 
= buffer
->GetStyleSheet()->FindListStyle(para
->GetAttributes().GetListStyleName()); 
6907                 int thisIndent 
= para
->GetAttributes().GetLeftIndent(); 
6908                 int thisLevel 
= para
->GetAttributes().HasOutlineLevel() ? para
->GetAttributes().GetOutlineLevel() : listDef
->FindLevelForIndent(thisIndent
); 
6910                 // Apply the overall list style, and item style for this level 
6911                 wxRichTextAttr 
listStyle(listDef
->GetCombinedStyleForLevel(thisLevel
, buffer
->GetStyleSheet())); 
6912                 wxRichTextApplyStyle(attr
, listStyle
); 
6913                 attr
.SetOutlineLevel(thisLevel
); 
6914                 if (para
->GetAttributes().HasBulletNumber()) 
6915                     attr
.SetBulletNumber(para
->GetAttributes().GetBulletNumber()); 
6919         if (!foundAttributes
) 
6921             attr 
= para
->GetAttributes(); 
6922             int flags 
= attr
.GetFlags(); 
6924             // Eliminate character styles 
6925             flags 
&= ( (~ wxTEXT_ATTR_FONT
) | 
6926                     (~ wxTEXT_ATTR_TEXT_COLOUR
) | 
6927                     (~ wxTEXT_ATTR_BACKGROUND_COLOUR
) ); 
6928             attr
.SetFlags(flags
); 
6934         return wxRichTextAttr(); 
6937 /// Submit command to delete this range 
6938 bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange
& range
, wxRichTextCtrl
* ctrl
) 
6940     return ctrl
->GetFocusObject()->DeleteRangeWithUndo(range
, ctrl
, this); 
6943 /// Submit command to delete this range 
6944 bool wxRichTextParagraphLayoutBox::DeleteRangeWithUndo(const wxRichTextRange
& range
, wxRichTextCtrl
* ctrl
, wxRichTextBuffer
* buffer
) 
6946     wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Delete"), wxRICHTEXT_DELETE
, buffer
, this, ctrl
); 
6948     action
->SetPosition(ctrl
->GetCaretPosition()); 
6950     // Set the range to delete 
6951     action
->SetRange(range
); 
6953     // Copy the fragment that we'll need to restore in Undo 
6954     CopyFragment(range
, action
->GetOldParagraphs()); 
6956     // See if we're deleting a paragraph marker, in which case we need to 
6957     // make a note not to copy the attributes from the 2nd paragraph to the 1st. 
6958     if (range
.GetStart() == range
.GetEnd()) 
6960         wxRichTextParagraph
* para 
= GetParagraphAtPosition(range
.GetStart()); 
6961         if (para 
&& para
->GetRange().GetEnd() == range
.GetEnd()) 
6963             wxRichTextParagraph
* nextPara 
= GetParagraphAtPosition(range
.GetStart()+1); 
6964             if (nextPara 
&& nextPara 
!= para
) 
6966                 action
->GetOldParagraphs().GetChildren().GetFirst()->GetData()->SetAttributes(nextPara
->GetAttributes()); 
6967                 action
->GetOldParagraphs().GetAttributes().SetFlags(action
->GetOldParagraphs().GetAttributes().GetFlags() | wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE
); 
6972     buffer
->SubmitAction(action
); 
6977 /// Collapse undo/redo commands 
6978 bool wxRichTextBuffer::BeginBatchUndo(const wxString
& cmdName
) 
6980     if (m_batchedCommandDepth 
== 0) 
6982         wxASSERT(m_batchedCommand 
== NULL
); 
6983         if (m_batchedCommand
) 
6985             GetCommandProcessor()->Store(m_batchedCommand
); 
6987         m_batchedCommand 
= new wxRichTextCommand(cmdName
); 
6990     m_batchedCommandDepth 
++; 
6995 /// Collapse undo/redo commands 
6996 bool wxRichTextBuffer::EndBatchUndo() 
6998     m_batchedCommandDepth 
--; 
7000     wxASSERT(m_batchedCommandDepth 
>= 0); 
7001     wxASSERT(m_batchedCommand 
!= NULL
); 
7003     if (m_batchedCommandDepth 
== 0) 
7005         GetCommandProcessor()->Store(m_batchedCommand
); 
7006         m_batchedCommand 
= NULL
; 
7012 /// Submit immediately, or delay according to whether collapsing is on 
7013 bool wxRichTextBuffer::SubmitAction(wxRichTextAction
* action
) 
7015     if (BatchingUndo() && m_batchedCommand 
&& !SuppressingUndo()) 
7017         wxRichTextCommand
* cmd 
= new wxRichTextCommand(action
->GetName()); 
7018         cmd
->AddAction(action
); 
7020         cmd
->GetActions().Clear(); 
7023         m_batchedCommand
->AddAction(action
); 
7027         wxRichTextCommand
* cmd 
= new wxRichTextCommand(action
->GetName()); 
7028         cmd
->AddAction(action
); 
7030         // Only store it if we're not suppressing undo. 
7031         return GetCommandProcessor()->Submit(cmd
, !SuppressingUndo()); 
7037 /// Begin suppressing undo/redo commands. 
7038 bool wxRichTextBuffer::BeginSuppressUndo() 
7045 /// End suppressing undo/redo commands. 
7046 bool wxRichTextBuffer::EndSuppressUndo() 
7053 /// Begin using a style 
7054 bool wxRichTextBuffer::BeginStyle(const wxRichTextAttr
& style
) 
7056     wxRichTextAttr 
newStyle(GetDefaultStyle()); 
7058     // Save the old default style 
7059     m_attributeStack
.Append((wxObject
*) new wxRichTextAttr(GetDefaultStyle())); 
7061     wxRichTextApplyStyle(newStyle
, style
); 
7062     newStyle
.SetFlags(style
.GetFlags()|newStyle
.GetFlags()); 
7064     SetDefaultStyle(newStyle
); 
7070 bool wxRichTextBuffer::EndStyle() 
7072     if (!m_attributeStack
.GetFirst()) 
7074         wxLogDebug(_("Too many EndStyle calls!")); 
7078     wxList::compatibility_iterator node 
= m_attributeStack
.GetLast(); 
7079     wxRichTextAttr
* attr 
= (wxRichTextAttr
*)node
->GetData(); 
7080     m_attributeStack
.Erase(node
); 
7082     SetDefaultStyle(*attr
); 
7089 bool wxRichTextBuffer::EndAllStyles() 
7091     while (m_attributeStack
.GetCount() != 0) 
7096 /// Clear the style stack 
7097 void wxRichTextBuffer::ClearStyleStack() 
7099     for (wxList::compatibility_iterator node 
= m_attributeStack
.GetFirst(); node
; node 
= node
->GetNext()) 
7100         delete (wxRichTextAttr
*) node
->GetData(); 
7101     m_attributeStack
.Clear(); 
7104 /// Begin using bold 
7105 bool wxRichTextBuffer::BeginBold() 
7107     wxRichTextAttr attr
; 
7108     attr
.SetFontWeight(wxFONTWEIGHT_BOLD
); 
7110     return BeginStyle(attr
); 
7113 /// Begin using italic 
7114 bool wxRichTextBuffer::BeginItalic() 
7116     wxRichTextAttr attr
; 
7117     attr
.SetFontStyle(wxFONTSTYLE_ITALIC
); 
7119     return BeginStyle(attr
); 
7122 /// Begin using underline 
7123 bool wxRichTextBuffer::BeginUnderline() 
7125     wxRichTextAttr attr
; 
7126     attr
.SetFontUnderlined(true); 
7128     return BeginStyle(attr
); 
7131 /// Begin using point size 
7132 bool wxRichTextBuffer::BeginFontSize(int pointSize
) 
7134     wxRichTextAttr attr
; 
7135     attr
.SetFontSize(pointSize
); 
7137     return BeginStyle(attr
); 
7140 /// Begin using this font 
7141 bool wxRichTextBuffer::BeginFont(const wxFont
& font
) 
7143     wxRichTextAttr attr
; 
7146     return BeginStyle(attr
); 
7149 /// Begin using this colour 
7150 bool wxRichTextBuffer::BeginTextColour(const wxColour
& colour
) 
7152     wxRichTextAttr attr
; 
7153     attr
.SetFlags(wxTEXT_ATTR_TEXT_COLOUR
); 
7154     attr
.SetTextColour(colour
); 
7156     return BeginStyle(attr
); 
7159 /// Begin using alignment 
7160 bool wxRichTextBuffer::BeginAlignment(wxTextAttrAlignment alignment
) 
7162     wxRichTextAttr attr
; 
7163     attr
.SetFlags(wxTEXT_ATTR_ALIGNMENT
); 
7164     attr
.SetAlignment(alignment
); 
7166     return BeginStyle(attr
); 
7169 /// Begin left indent 
7170 bool wxRichTextBuffer::BeginLeftIndent(int leftIndent
, int leftSubIndent
) 
7172     wxRichTextAttr attr
; 
7173     attr
.SetFlags(wxTEXT_ATTR_LEFT_INDENT
); 
7174     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
7176     return BeginStyle(attr
); 
7179 /// Begin right indent 
7180 bool wxRichTextBuffer::BeginRightIndent(int rightIndent
) 
7182     wxRichTextAttr attr
; 
7183     attr
.SetFlags(wxTEXT_ATTR_RIGHT_INDENT
); 
7184     attr
.SetRightIndent(rightIndent
); 
7186     return BeginStyle(attr
); 
7189 /// Begin paragraph spacing 
7190 bool wxRichTextBuffer::BeginParagraphSpacing(int before
, int after
) 
7194         flags 
|= wxTEXT_ATTR_PARA_SPACING_BEFORE
; 
7196         flags 
|= wxTEXT_ATTR_PARA_SPACING_AFTER
; 
7198     wxRichTextAttr attr
; 
7199     attr
.SetFlags(flags
); 
7200     attr
.SetParagraphSpacingBefore(before
); 
7201     attr
.SetParagraphSpacingAfter(after
); 
7203     return BeginStyle(attr
); 
7206 /// Begin line spacing 
7207 bool wxRichTextBuffer::BeginLineSpacing(int lineSpacing
) 
7209     wxRichTextAttr attr
; 
7210     attr
.SetFlags(wxTEXT_ATTR_LINE_SPACING
); 
7211     attr
.SetLineSpacing(lineSpacing
); 
7213     return BeginStyle(attr
); 
7216 /// Begin numbered bullet 
7217 bool wxRichTextBuffer::BeginNumberedBullet(int bulletNumber
, int leftIndent
, int leftSubIndent
, int bulletStyle
) 
7219     wxRichTextAttr attr
; 
7220     attr
.SetFlags(wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_LEFT_INDENT
); 
7221     attr
.SetBulletStyle(bulletStyle
); 
7222     attr
.SetBulletNumber(bulletNumber
); 
7223     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
7225     return BeginStyle(attr
); 
7228 /// Begin symbol bullet 
7229 bool wxRichTextBuffer::BeginSymbolBullet(const wxString
& symbol
, int leftIndent
, int leftSubIndent
, int bulletStyle
) 
7231     wxRichTextAttr attr
; 
7232     attr
.SetFlags(wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_LEFT_INDENT
); 
7233     attr
.SetBulletStyle(bulletStyle
); 
7234     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
7235     attr
.SetBulletText(symbol
); 
7237     return BeginStyle(attr
); 
7240 /// Begin standard bullet 
7241 bool wxRichTextBuffer::BeginStandardBullet(const wxString
& bulletName
, int leftIndent
, int leftSubIndent
, int bulletStyle
) 
7243     wxRichTextAttr attr
; 
7244     attr
.SetFlags(wxTEXT_ATTR_BULLET_STYLE
|wxTEXT_ATTR_LEFT_INDENT
); 
7245     attr
.SetBulletStyle(bulletStyle
); 
7246     attr
.SetLeftIndent(leftIndent
, leftSubIndent
); 
7247     attr
.SetBulletName(bulletName
); 
7249     return BeginStyle(attr
); 
7252 /// Begin named character style 
7253 bool wxRichTextBuffer::BeginCharacterStyle(const wxString
& characterStyle
) 
7255     if (GetStyleSheet()) 
7257         wxRichTextCharacterStyleDefinition
* def 
= GetStyleSheet()->FindCharacterStyle(characterStyle
); 
7260             wxRichTextAttr attr 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
7261             return BeginStyle(attr
); 
7267 /// Begin named paragraph style 
7268 bool wxRichTextBuffer::BeginParagraphStyle(const wxString
& paragraphStyle
) 
7270     if (GetStyleSheet()) 
7272         wxRichTextParagraphStyleDefinition
* def 
= GetStyleSheet()->FindParagraphStyle(paragraphStyle
); 
7275             wxRichTextAttr attr 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
7276             return BeginStyle(attr
); 
7282 /// Begin named list style 
7283 bool wxRichTextBuffer::BeginListStyle(const wxString
& listStyle
, int level
, int number
) 
7285     if (GetStyleSheet()) 
7287         wxRichTextListStyleDefinition
* def 
= GetStyleSheet()->FindListStyle(listStyle
); 
7290             wxRichTextAttr 
attr(def
->GetCombinedStyleForLevel(level
)); 
7292             attr
.SetBulletNumber(number
); 
7294             return BeginStyle(attr
); 
7301 bool wxRichTextBuffer::BeginURL(const wxString
& url
, const wxString
& characterStyle
) 
7303     wxRichTextAttr attr
; 
7305     if (!characterStyle
.IsEmpty() && GetStyleSheet()) 
7307         wxRichTextCharacterStyleDefinition
* def 
= GetStyleSheet()->FindCharacterStyle(characterStyle
); 
7310             attr 
= def
->GetStyleMergedWithBase(GetStyleSheet()); 
7315     return BeginStyle(attr
); 
7318 /// Adds a handler to the end 
7319 void wxRichTextBuffer::AddHandler(wxRichTextFileHandler 
*handler
) 
7321     sm_handlers
.Append(handler
); 
7324 /// Inserts a handler at the front 
7325 void wxRichTextBuffer::InsertHandler(wxRichTextFileHandler 
*handler
) 
7327     sm_handlers
.Insert( handler 
); 
7330 /// Removes a handler 
7331 bool wxRichTextBuffer::RemoveHandler(const wxString
& name
) 
7333     wxRichTextFileHandler 
*handler 
= FindHandler(name
); 
7336         sm_handlers
.DeleteObject(handler
); 
7344 /// Finds a handler by filename or, if supplied, type 
7345 wxRichTextFileHandler 
*wxRichTextBuffer::FindHandlerFilenameOrType(const wxString
& filename
, 
7346                                                                    wxRichTextFileType imageType
) 
7348     if (imageType 
!= wxRICHTEXT_TYPE_ANY
) 
7349         return FindHandler(imageType
); 
7350     else if (!filename
.IsEmpty()) 
7352         wxString path
, file
, ext
; 
7353         wxFileName::SplitPath(filename
, & path
, & file
, & ext
); 
7354         return FindHandler(ext
, imageType
); 
7361 /// Finds a handler by name 
7362 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(const wxString
& name
) 
7364     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
7367         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
7368         if (handler
->GetName().Lower() == name
.Lower()) return handler
; 
7370         node 
= node
->GetNext(); 
7375 /// Finds a handler by extension and type 
7376 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(const wxString
& extension
, wxRichTextFileType type
) 
7378     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
7381         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
7382         if ( handler
->GetExtension().Lower() == extension
.Lower() && 
7383             (type 
== wxRICHTEXT_TYPE_ANY 
|| handler
->GetType() == type
) ) 
7385         node 
= node
->GetNext(); 
7390 /// Finds a handler by type 
7391 wxRichTextFileHandler
* wxRichTextBuffer::FindHandler(wxRichTextFileType type
) 
7393     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
7396         wxRichTextFileHandler 
*handler 
= (wxRichTextFileHandler 
*)node
->GetData(); 
7397         if (handler
->GetType() == type
) return handler
; 
7398         node 
= node
->GetNext(); 
7403 void wxRichTextBuffer::InitStandardHandlers() 
7405     if (!FindHandler(wxRICHTEXT_TYPE_TEXT
)) 
7406         AddHandler(new wxRichTextPlainTextHandler
); 
7409 void wxRichTextBuffer::CleanUpHandlers() 
7411     wxList::compatibility_iterator node 
= sm_handlers
.GetFirst(); 
7414         wxRichTextFileHandler
* handler 
= (wxRichTextFileHandler
*)node
->GetData(); 
7415         wxList::compatibility_iterator next 
= node
->GetNext(); 
7420     sm_handlers
.Clear(); 
7423 wxString 
wxRichTextBuffer::GetExtWildcard(bool combine
, bool save
, wxArrayInt
* types
) 
7430     wxList::compatibility_iterator node 
= GetHandlers().GetFirst(); 
7434         wxRichTextFileHandler
* handler 
= (wxRichTextFileHandler
*) node
->GetData(); 
7435         if (handler
->IsVisible() && ((save 
&& handler
->CanSave()) || (!save 
&& handler
->CanLoad()))) 
7440                     wildcard 
+= wxT(";"); 
7441                 wildcard 
+= wxT("*.") + handler
->GetExtension(); 
7446                     wildcard 
+= wxT("|"); 
7447                 wildcard 
+= handler
->GetName(); 
7448                 wildcard 
+= wxT(" "); 
7449                 wildcard 
+= _("files"); 
7450                 wildcard 
+= wxT(" (*."); 
7451                 wildcard 
+= handler
->GetExtension(); 
7452                 wildcard 
+= wxT(")|*."); 
7453                 wildcard 
+= handler
->GetExtension(); 
7455                     types
->Add(handler
->GetType()); 
7460         node 
= node
->GetNext(); 
7464         wildcard 
= wxT("(") + wildcard 
+ wxT(")|") + wildcard
; 
7469 bool wxRichTextBuffer::LoadFile(const wxString
& filename
, wxRichTextFileType type
) 
7471     wxRichTextFileHandler
* handler 
= FindHandlerFilenameOrType(filename
, type
); 
7474         SetDefaultStyle(wxRichTextAttr()); 
7475         handler
->SetFlags(GetHandlerFlags()); 
7476         bool success 
= handler
->LoadFile(this, filename
); 
7477         Invalidate(wxRICHTEXT_ALL
); 
7485 bool wxRichTextBuffer::SaveFile(const wxString
& filename
, wxRichTextFileType type
) 
7487     wxRichTextFileHandler
* handler 
= FindHandlerFilenameOrType(filename
, type
); 
7490         handler
->SetFlags(GetHandlerFlags()); 
7491         return handler
->SaveFile(this, filename
); 
7497 /// Load from a stream 
7498 bool wxRichTextBuffer::LoadFile(wxInputStream
& stream
, wxRichTextFileType type
) 
7500     wxRichTextFileHandler
* handler 
= FindHandler(type
); 
7503         SetDefaultStyle(wxRichTextAttr()); 
7504         handler
->SetFlags(GetHandlerFlags()); 
7505         bool success 
= handler
->LoadFile(this, stream
); 
7506         Invalidate(wxRICHTEXT_ALL
); 
7513 /// Save to a stream 
7514 bool wxRichTextBuffer::SaveFile(wxOutputStream
& stream
, wxRichTextFileType type
) 
7516     wxRichTextFileHandler
* handler 
= FindHandler(type
); 
7519         handler
->SetFlags(GetHandlerFlags()); 
7520         return handler
->SaveFile(this, stream
); 
7526 /// Copy the range to the clipboard 
7527 bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange
& range
) 
7529     bool success 
= false; 
7530     wxRichTextParagraphLayoutBox
* container 
= this; 
7531     if (GetRichTextCtrl()) 
7532         container 
= GetRichTextCtrl()->GetFocusObject(); 
7534 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
7536     if (!wxTheClipboard
->IsOpened() && wxTheClipboard
->Open()) 
7538         wxTheClipboard
->Clear(); 
7540         // Add composite object 
7542         wxDataObjectComposite
* compositeObject 
= new wxDataObjectComposite(); 
7545             wxString text 
= container
->GetTextForRange(range
); 
7548             text 
= wxTextFile::Translate(text
, wxTextFileType_Dos
); 
7551             compositeObject
->Add(new wxTextDataObject(text
), false /* not preferred */); 
7554         // Add rich text buffer data object. This needs the XML handler to be present. 
7556         if (FindHandler(wxRICHTEXT_TYPE_XML
)) 
7558             wxRichTextBuffer
* richTextBuf 
= new wxRichTextBuffer
; 
7559             container
->CopyFragment(range
, *richTextBuf
); 
7561             compositeObject
->Add(new wxRichTextBufferDataObject(richTextBuf
), true /* preferred */); 
7564         if (wxTheClipboard
->SetData(compositeObject
)) 
7567         wxTheClipboard
->Close(); 
7576 /// Paste the clipboard content to the buffer 
7577 bool wxRichTextBuffer::PasteFromClipboard(long position
) 
7579     bool success 
= false; 
7580     wxRichTextParagraphLayoutBox
* container 
= this; 
7581     if (GetRichTextCtrl()) 
7582         container 
= GetRichTextCtrl()->GetFocusObject(); 
7584 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
7585     if (CanPasteFromClipboard()) 
7587         if (wxTheClipboard
->Open()) 
7589             if (wxTheClipboard
->IsSupported(wxDataFormat(wxRichTextBufferDataObject::GetRichTextBufferFormatId()))) 
7591                 wxRichTextBufferDataObject data
; 
7592                 wxTheClipboard
->GetData(data
); 
7593                 wxRichTextBuffer
* richTextBuffer 
= data
.GetRichTextBuffer(); 
7596                     container
->InsertParagraphsWithUndo(position
+1, *richTextBuffer
, GetRichTextCtrl(), this, 0); 
7597                     if (GetRichTextCtrl()) 
7598                         GetRichTextCtrl()->ShowPosition(position 
+ richTextBuffer
->GetOwnRange().GetEnd()); 
7599                     delete richTextBuffer
; 
7602             else if (wxTheClipboard
->IsSupported(wxDF_TEXT
) 
7604                      || wxTheClipboard
->IsSupported(wxDF_UNICODETEXT
) 
7608                 wxTextDataObject data
; 
7609                 wxTheClipboard
->GetData(data
); 
7610                 wxString 
text(data
.GetText()); 
7613                 text2
.Alloc(text
.Length()+1); 
7615                 for (i 
= 0; i 
< text
.Length(); i
++) 
7617                     wxChar ch 
= text
[i
]; 
7618                     if (ch 
!= wxT('\r')) 
7622                 wxString text2 
= text
; 
7624                 container
->InsertTextWithUndo(position
+1, text2
, GetRichTextCtrl(), this, wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE
); 
7626                 if (GetRichTextCtrl()) 
7627                     GetRichTextCtrl()->ShowPosition(position 
+ text2
.Length()); 
7631             else if (wxTheClipboard
->IsSupported(wxDF_BITMAP
)) 
7633                 wxBitmapDataObject data
; 
7634                 wxTheClipboard
->GetData(data
); 
7635                 wxBitmap 
bitmap(data
.GetBitmap()); 
7636                 wxImage 
image(bitmap
.ConvertToImage()); 
7638                 wxRichTextAction
* action 
= new wxRichTextAction(NULL
, _("Insert Image"), wxRICHTEXT_INSERT
, this, container
, GetRichTextCtrl(), false); 
7640                 action
->GetNewParagraphs().AddImage(image
); 
7642                 if (action
->GetNewParagraphs().GetChildCount() == 1) 
7643                     action
->GetNewParagraphs().SetPartialParagraph(true); 
7645                 action
->SetPosition(position
+1); 
7647                 // Set the range we'll need to delete in Undo 
7648                 action
->SetRange(wxRichTextRange(position
+1, position
+1)); 
7650                 SubmitAction(action
); 
7654             wxTheClipboard
->Close(); 
7658     wxUnusedVar(position
); 
7663 /// Can we paste from the clipboard? 
7664 bool wxRichTextBuffer::CanPasteFromClipboard() const 
7666     bool canPaste 
= false; 
7667 #if wxUSE_CLIPBOARD && wxUSE_DATAOBJ 
7668     if (!wxTheClipboard
->IsOpened() && wxTheClipboard
->Open()) 
7670         if (wxTheClipboard
->IsSupported(wxDF_TEXT
) 
7672             || wxTheClipboard
->IsSupported(wxDF_UNICODETEXT
) 
7674             || wxTheClipboard
->IsSupported(wxDataFormat(wxRichTextBufferDataObject::GetRichTextBufferFormatId())) || 
7675             wxTheClipboard
->IsSupported(wxDF_BITMAP
)) 
7679         wxTheClipboard
->Close(); 
7685 /// Dumps contents of buffer for debugging purposes 
7686 void wxRichTextBuffer::Dump() 
7690         wxStringOutputStream 
stream(& text
); 
7691         wxTextOutputStream 
textStream(stream
); 
7698 /// Add an event handler 
7699 bool wxRichTextBuffer::AddEventHandler(wxEvtHandler
* handler
) 
7701     m_eventHandlers
.Append(handler
); 
7705 /// Remove an event handler 
7706 bool wxRichTextBuffer::RemoveEventHandler(wxEvtHandler
* handler
, bool deleteHandler
) 
7708     wxList::compatibility_iterator node 
= m_eventHandlers
.Find(handler
); 
7711         m_eventHandlers
.Erase(node
); 
7721 /// Clear event handlers 
7722 void wxRichTextBuffer::ClearEventHandlers() 
7724     m_eventHandlers
.Clear(); 
7727 /// Send event to event handlers. If sendToAll is true, will send to all event handlers, 
7728 /// otherwise will stop at the first successful one. 
7729 bool wxRichTextBuffer::SendEvent(wxEvent
& event
, bool sendToAll
) 
7731     bool success 
= false; 
7732     for (wxList::compatibility_iterator node 
= m_eventHandlers
.GetFirst(); node
; node 
= node
->GetNext()) 
7734         wxEvtHandler
* handler 
= (wxEvtHandler
*) node
->GetData(); 
7735         if (handler
->ProcessEvent(event
)) 
7745 /// Set style sheet and notify of the change 
7746 bool wxRichTextBuffer::SetStyleSheetAndNotify(wxRichTextStyleSheet
* sheet
) 
7748     wxRichTextStyleSheet
* oldSheet 
= GetStyleSheet(); 
7750     wxWindowID winid 
= wxID_ANY
; 
7751     if (GetRichTextCtrl()) 
7752         winid 
= GetRichTextCtrl()->GetId(); 
7754     wxRichTextEvent 
event(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACING
, winid
); 
7755     event
.SetEventObject(GetRichTextCtrl()); 
7756     event
.SetContainer(GetRichTextCtrl()->GetFocusObject()); 
7757     event
.SetOldStyleSheet(oldSheet
); 
7758     event
.SetNewStyleSheet(sheet
); 
7761     if (SendEvent(event
) && !event
.IsAllowed()) 
7763         if (sheet 
!= oldSheet
) 
7769     if (oldSheet 
&& oldSheet 
!= sheet
) 
7772     SetStyleSheet(sheet
); 
7774     event
.SetEventType(wxEVT_COMMAND_RICHTEXT_STYLESHEET_REPLACED
); 
7775     event
.SetOldStyleSheet(NULL
); 
7778     return SendEvent(event
); 
7781 /// Set renderer, deleting old one 
7782 void wxRichTextBuffer::SetRenderer(wxRichTextRenderer
* renderer
) 
7786     sm_renderer 
= renderer
; 
7789 /// Hit-testing: returns a flag indicating hit test details, plus 
7790 /// information about position 
7791 int wxRichTextBuffer::HitTest(wxDC
& dc
, const wxPoint
& pt
, long& textPosition
, wxRichTextObject
** obj
, wxRichTextObject
** contextObj
, int flags
) 
7793     int ret 
= wxRichTextParagraphLayoutBox::HitTest(dc
, pt
, textPosition
, obj
, contextObj
, flags
); 
7794     if (ret 
!= wxRICHTEXT_HITTEST_NONE
) 
7800         textPosition 
= m_ownRange
.GetEnd()-1; 
7803         return wxRICHTEXT_HITTEST_AFTER
|wxRICHTEXT_HITTEST_OUTSIDE
; 
7807 bool wxRichTextStdRenderer::DrawStandardBullet(wxRichTextParagraph
* paragraph
, wxDC
& dc
, const wxRichTextAttr
& bulletAttr
, const wxRect
& rect
) 
7809     if (bulletAttr
.GetTextColour().IsOk()) 
7811         wxCheckSetPen(dc
, wxPen(bulletAttr
.GetTextColour())); 
7812         wxCheckSetBrush(dc
, wxBrush(bulletAttr
.GetTextColour())); 
7816         wxCheckSetPen(dc
, *wxBLACK_PEN
); 
7817         wxCheckSetBrush(dc
, *wxBLACK_BRUSH
); 
7821     if (bulletAttr
.HasFont()) 
7823         font 
= paragraph
->GetBuffer()->GetFontTable().FindFont(bulletAttr
); 
7826         font 
= (*wxNORMAL_FONT
); 
7828     wxCheckSetFont(dc
, font
); 
7830     int charHeight 
= dc
.GetCharHeight(); 
7832     int bulletWidth 
= (int) (((float) charHeight
) * wxRichTextBuffer::GetBulletProportion()); 
7833     int bulletHeight 
= bulletWidth
; 
7837     // Calculate the top position of the character (as opposed to the whole line height) 
7838     int y 
= rect
.y 
+ (rect
.height 
- charHeight
); 
7840     // Calculate where the bullet should be positioned 
7841     y 
= y 
+ (charHeight
+1)/2 - (bulletHeight
+1)/2; 
7843     // The margin between a bullet and text. 
7844     int margin 
= paragraph
->ConvertTenthsMMToPixels(dc
, wxRichTextBuffer::GetBulletRightMargin()); 
7846     if (bulletAttr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT
) 
7847         x 
= rect
.x 
+ rect
.width 
- bulletWidth 
- margin
; 
7848     else if (bulletAttr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ALIGN_CENTRE
) 
7849         x 
= x 
+ (rect
.width
)/2 - bulletWidth
/2; 
7851     if (bulletAttr
.GetBulletName() == wxT("standard/square")) 
7853         dc
.DrawRectangle(x
, y
, bulletWidth
, bulletHeight
); 
7855     else if (bulletAttr
.GetBulletName() == wxT("standard/diamond")) 
7858         pts
[0].x 
= x
;                   pts
[0].y 
= y 
+ bulletHeight
/2; 
7859         pts
[1].x 
= x 
+ bulletWidth
/2;   pts
[1].y 
= y
; 
7860         pts
[2].x 
= x 
+ bulletWidth
;     pts
[2].y 
= y 
+ bulletHeight
/2; 
7861         pts
[3].x 
= x 
+ bulletWidth
/2;   pts
[3].y 
= y 
+ bulletHeight
; 
7863         dc
.DrawPolygon(4, pts
); 
7865     else if (bulletAttr
.GetBulletName() == wxT("standard/triangle")) 
7868         pts
[0].x 
= x
;                   pts
[0].y 
= y
; 
7869         pts
[1].x 
= x 
+ bulletWidth
;     pts
[1].y 
= y 
+ bulletHeight
/2; 
7870         pts
[2].x 
= x
;                   pts
[2].y 
= y 
+ bulletHeight
; 
7872         dc
.DrawPolygon(3, pts
); 
7874     else if (bulletAttr
.GetBulletName() == wxT("standard/circle-outline")) 
7876         wxCheckSetBrush(dc
, *wxTRANSPARENT_BRUSH
); 
7877         dc
.DrawEllipse(x
, y
, bulletWidth
, bulletHeight
); 
7879     else // "standard/circle", and catch-all 
7881         dc
.DrawEllipse(x
, y
, bulletWidth
, bulletHeight
); 
7887 bool wxRichTextStdRenderer::DrawTextBullet(wxRichTextParagraph
* paragraph
, wxDC
& dc
, const wxRichTextAttr
& attr
, const wxRect
& rect
, const wxString
& text
) 
7892         if ((attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_SYMBOL
) && !attr
.GetBulletFont().IsEmpty() && attr
.HasFont()) 
7894             wxRichTextAttr fontAttr
; 
7895             fontAttr
.SetFontSize(attr
.GetFontSize()); 
7896             fontAttr
.SetFontStyle(attr
.GetFontStyle()); 
7897             fontAttr
.SetFontWeight(attr
.GetFontWeight()); 
7898             fontAttr
.SetFontUnderlined(attr
.GetFontUnderlined()); 
7899             fontAttr
.SetFontFaceName(attr
.GetBulletFont()); 
7900             font 
= paragraph
->GetBuffer()->GetFontTable().FindFont(fontAttr
); 
7902         else if (attr
.HasFont()) 
7903             font 
= paragraph
->GetBuffer()->GetFontTable().FindFont(attr
); 
7905             font 
= (*wxNORMAL_FONT
); 
7907         wxCheckSetFont(dc
, font
); 
7909         if (attr
.GetTextColour().IsOk()) 
7910             dc
.SetTextForeground(attr
.GetTextColour()); 
7912         dc
.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT
); 
7914         int charHeight 
= dc
.GetCharHeight(); 
7916         dc
.GetTextExtent(text
, & tw
, & th
); 
7920         // Calculate the top position of the character (as opposed to the whole line height) 
7921         int y 
= rect
.y 
+ (rect
.height 
- charHeight
); 
7923         // The margin between a bullet and text. 
7924         int margin 
= paragraph
->ConvertTenthsMMToPixels(dc
, wxRichTextBuffer::GetBulletRightMargin()); 
7926         if (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ALIGN_RIGHT
) 
7927             x 
= (rect
.x 
+ rect
.width
) - tw 
- margin
; 
7928         else if (attr
.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_ALIGN_CENTRE
) 
7929             x 
= x 
+ (rect
.width
)/2 - tw
/2; 
7931         dc
.DrawText(text
, x
, y
); 
7939 bool wxRichTextStdRenderer::DrawBitmapBullet(wxRichTextParagraph
* WXUNUSED(paragraph
), wxDC
& WXUNUSED(dc
), const wxRichTextAttr
& WXUNUSED(attr
), const wxRect
& WXUNUSED(rect
)) 
7941     // Currently unimplemented. The intention is to store bitmaps by name in a media store associated 
7942     // with the buffer. The store will allow retrieval from memory, disk or other means. 
7946 /// Enumerate the standard bullet names currently supported 
7947 bool wxRichTextStdRenderer::EnumerateStandardBulletNames(wxArrayString
& bulletNames
) 
7949     bulletNames
.Add(wxTRANSLATE("standard/circle")); 
7950     bulletNames
.Add(wxTRANSLATE("standard/circle-outline")); 
7951     bulletNames
.Add(wxTRANSLATE("standard/square")); 
7952     bulletNames
.Add(wxTRANSLATE("standard/diamond")); 
7953     bulletNames
.Add(wxTRANSLATE("standard/triangle")); 
7962 IMPLEMENT_DYNAMIC_CLASS(wxRichTextBox
, wxRichTextParagraphLayoutBox
) 
7964 wxRichTextBox::wxRichTextBox(wxRichTextObject
* parent
): 
7965     wxRichTextParagraphLayoutBox(parent
) 
7970 bool wxRichTextBox::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
7975     // TODO: if the active object in the control, draw an indication. 
7976     // We need to add the concept of active object, and not just focus object, 
7977     // so we can apply commands (properties, delete, ...) to objects such as text boxes and images. 
7978     // Ultimately we would like to be able to interactively resize an active object 
7979     // using drag handles. 
7980     return wxRichTextParagraphLayoutBox::Draw(dc
, range
, selection
, rect
, descent
, style
); 
7984 void wxRichTextBox::Copy(const wxRichTextBox
& obj
) 
7986     wxRichTextParagraphLayoutBox::Copy(obj
); 
7989 // Edit properties via a GUI 
7990 bool wxRichTextBox::EditProperties(wxWindow
* parent
, wxRichTextBuffer
* buffer
) 
7992     wxRichTextObjectPropertiesDialog 
boxDlg(this, wxGetTopLevelParent(parent
), wxID_ANY
, _("Box Properties")); 
7993     boxDlg
.SetAttributes(GetAttributes()); 
7995     if (boxDlg
.ShowModal() == wxID_OK
) 
7997         // By passing wxRICHTEXT_SETSTYLE_RESET, indeterminate attributes set by the user will be set as 
7998         // indeterminate in the object. 
7999         boxDlg
.ApplyStyle(buffer
->GetRichTextCtrl(), wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_RESET
); 
8006 IMPLEMENT_DYNAMIC_CLASS(wxRichTextCell
, wxRichTextBox
) 
8008 wxRichTextCell::wxRichTextCell(wxRichTextObject
* parent
): 
8009     wxRichTextBox(parent
) 
8014 bool wxRichTextCell::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
8016     return wxRichTextBox::Draw(dc
, range
, selection
, rect
, descent
, style
); 
8020 void wxRichTextCell::Copy(const wxRichTextCell
& obj
) 
8022     wxRichTextBox::Copy(obj
); 
8025 // Edit properties via a GUI 
8026 bool wxRichTextCell::EditProperties(wxWindow
* parent
, wxRichTextBuffer
* buffer
) 
8028     // We need to gather common attributes for all selected cells. 
8030     wxRichTextTable
* table 
= wxDynamicCast(GetParent(), wxRichTextTable
); 
8031     bool multipleCells 
= false; 
8032     wxRichTextAttr attr
; 
8034     if (table 
&& buffer 
&& buffer
->GetRichTextCtrl() && buffer
->GetRichTextCtrl()->GetSelection().IsValid() && 
8035         buffer
->GetRichTextCtrl()->GetSelection().GetContainer() == GetParent()) 
8037         wxRichTextAttr clashingAttr
, absentAttr
; 
8038         const wxRichTextSelection
& sel 
= buffer
->GetRichTextCtrl()->GetSelection(); 
8040         int selectedCellCount 
= 0; 
8041         for (i 
= 0; i 
< sel
.GetCount(); i
++) 
8043             const wxRichTextRange
& range 
= sel
[i
]; 
8044             wxRichTextCell
* cell 
= table
->GetCell(range
.GetStart()); 
8047                 wxRichTextAttr cellStyle 
= cell
->GetAttributes(); 
8049                 CollectStyle(attr
, cellStyle
, clashingAttr
, absentAttr
); 
8051                 selectedCellCount 
++; 
8054         multipleCells 
= selectedCellCount 
> 1; 
8058         attr 
= GetAttributes(); 
8063         caption 
= _("Multiple Cell Properties"); 
8065         caption 
= _("Cell Properties"); 
8067     wxRichTextObjectPropertiesDialog 
cellDlg(this, wxGetTopLevelParent(parent
), wxID_ANY
, caption
); 
8068     cellDlg
.SetAttributes(attr
); 
8070     wxRichTextSizePage
* sizePage 
= wxDynamicCast(cellDlg
.FindPage(CLASSINFO(wxRichTextSizePage
)), wxRichTextSizePage
); 
8073         // We don't want position and floating controls for a cell. 
8074         sizePage
->ShowPositionControls(false); 
8075         sizePage
->ShowFloatingControls(false); 
8078     if (cellDlg
.ShowModal() == wxID_OK
) 
8082             const wxRichTextSelection
& sel 
= buffer
->GetRichTextCtrl()->GetSelection(); 
8083             // Apply the style; we interpret indeterminate attributes as 'don't touch this attribute' 
8084             // since it may represent clashing attributes across multiple objects. 
8085             table
->SetCellStyle(sel
, attr
); 
8088             // For a single object, indeterminate attributes set by the user should be reflected in the 
8089             // actual object style, so pass the wxRICHTEXT_SETSTYLE_RESET flag to assign 
8090             // the style directly instead of applying (which ignores indeterminate attributes, 
8091             // leaving them as they were). 
8092             cellDlg
.ApplyStyle(buffer
->GetRichTextCtrl(), wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_RESET
); 
8099 WX_DEFINE_OBJARRAY(wxRichTextObjectPtrArrayArray
) 
8101 IMPLEMENT_DYNAMIC_CLASS(wxRichTextTable
, wxRichTextBox
) 
8103 wxRichTextTable::wxRichTextTable(wxRichTextObject
* parent
): wxRichTextBox(parent
) 
8109 // Draws the object. 
8110 bool wxRichTextTable::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int descent
, int style
) 
8112     return wxRichTextBox::Draw(dc
, range
, selection
, rect
, descent
, style
); 
8115 WX_DECLARE_OBJARRAY(wxRect
, wxRichTextRectArray
); 
8116 WX_DEFINE_OBJARRAY(wxRichTextRectArray
); 
8118 // Lays the object out. rect is the space available for layout. Often it will 
8119 // be the specified overall space for this object, if trying to constrain 
8120 // layout to a particular size, or it could be the total space available in the 
8121 // parent. rect is the overall size, so we must subtract margins and padding. 
8122 // to get the actual available space. 
8123 bool wxRichTextTable::Layout(wxDC
& dc
, const wxRect
& rect
, int style
) 
8125     SetPosition(rect
.GetPosition()); 
8127     // TODO: the meaty bit. Calculate sizes of all cells and rows. Try to use 
8128     // minimum size if within alloted size, then divide up remaining size 
8129     // between rows/cols. 
8132     wxRichTextBuffer
* buffer 
= GetBuffer(); 
8133     if (buffer
) scale 
= buffer
->GetScale(); 
8135     wxRect availableSpace 
= GetAvailableContentArea(dc
, rect
); 
8136     wxTextAttrDimensionConverter 
converter(dc
, scale
, availableSpace
.GetSize()); 
8138     // If we have no fixed table size, and assuming we're not pushed for 
8139     // space, then we don't have to try to stretch the table to fit the contents. 
8140     bool stretchToFitTableWidth 
= false; 
8142     int tableWidth 
= rect
.width
; 
8143     if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid()) 
8145         tableWidth 
= converter
.GetPixels(GetAttributes().GetTextBoxAttr().GetWidth()); 
8147         // Fixed table width, so we do want to stretch columns out if necessary. 
8148         stretchToFitTableWidth 
= true; 
8150         // Shouldn't be able to exceed the size passed to this function 
8151         tableWidth 
= wxMin(rect
.width
, tableWidth
); 
8154     // Get internal padding 
8155     int paddingLeft 
= 0, paddingRight 
= 0, paddingTop 
= 0, paddingBottom 
= 0; 
8156     if (GetAttributes().GetTextBoxAttr().GetPadding().GetLeft().IsValid()) 
8157         paddingLeft 
= converter
.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetLeft()); 
8158     if (GetAttributes().GetTextBoxAttr().GetPadding().GetRight().IsValid()) 
8159         paddingRight 
= converter
.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetRight()); 
8160     if (GetAttributes().GetTextBoxAttr().GetPadding().GetTop().IsValid()) 
8161         paddingTop 
= converter
.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetTop()); 
8162     if (GetAttributes().GetTextBoxAttr().GetPadding().GetLeft().IsValid()) 
8163         paddingBottom 
= converter
.GetPixels(GetAttributes().GetTextBoxAttr().GetPadding().GetBottom()); 
8165     // Assume that left and top padding are also used for inter-cell padding. 
8166     int paddingX 
= paddingLeft
; 
8167     int paddingY 
= paddingTop
; 
8169     int totalLeftMargin 
= 0, totalRightMargin 
= 0, totalTopMargin 
= 0, totalBottomMargin 
= 0; 
8170     GetTotalMargin(dc
, buffer
, GetAttributes(), totalLeftMargin
, totalRightMargin
, totalTopMargin
, totalBottomMargin
); 
8172     // Internal table width - the area for content 
8173     int internalTableWidth 
= tableWidth 
- totalLeftMargin 
- totalRightMargin
; 
8175     int rowCount 
= m_cells
.GetCount(); 
8176     if (m_colCount 
== 0 || rowCount 
== 0) 
8178         wxRect 
overallRect(rect
.x
, rect
.y
, totalLeftMargin 
+ totalRightMargin
, totalTopMargin 
+ totalBottomMargin
); 
8179         SetCachedSize(overallRect
.GetSize()); 
8181         // Zero content size 
8182         SetMinSize(overallRect
.GetSize()); 
8183         SetMaxSize(GetMinSize()); 
8187     // The final calculated widths 
8188     wxArrayInt 
colWidths(m_colCount
); 
8190     wxArrayInt 
absoluteColWidths(m_colCount
); 
8191     // wxArrayInt absoluteColWidthsSpanning(m_colCount); 
8192     wxArrayInt 
percentageColWidths(m_colCount
); 
8193     // wxArrayInt percentageColWidthsSpanning(m_colCount); 
8194     // These are only relevant when the first column contains spanning information. 
8195     // wxArrayInt columnSpans(m_colCount); // Each contains 1 for non-spanning cell, > 1 for spanning cell. 
8196     wxArrayInt 
maxColWidths(m_colCount
); 
8197     wxArrayInt 
minColWidths(m_colCount
); 
8199     wxSize 
tableSize(tableWidth
, 0); 
8203     for (i 
= 0; i 
< m_colCount
; i
++) 
8205         absoluteColWidths
[i
] = 0; 
8206         // absoluteColWidthsSpanning[i] = 0; 
8207         percentageColWidths
[i
] = -1; 
8208         // percentageColWidthsSpanning[i] = -1; 
8210         maxColWidths
[i
] = 0; 
8211         minColWidths
[i
] = 0; 
8212         // columnSpans[i] = 1; 
8215     // (0) Determine which cells are visible according to spans 
8217     //  __________________ 
8222     // |------------------| 
8223     // |__________________| 4 
8225     // To calculate cell visibility: 
8226     // First find all spanning cells. Build an array of span records with start x, y and end x, y. 
8227     // Then for each cell, test whether we're within one of those cells, and unless we're at the start of 
8228     // that cell, hide the cell. 
8230     // We can also use this array to match the size of spanning cells to the grid. Or just do 
8231     // this when we iterate through all cells. 
8233     // 0.1: add spanning cells to an array 
8234     wxRichTextRectArray rectArray
; 
8235     for (j 
= 0; j 
< m_rowCount
; j
++) 
8237         for (i 
= 0; i 
< m_colCount
; i
++) 
8239             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8240             int colSpan 
= 1, rowSpan 
= 1; 
8241             if (cell
->GetProperties().HasProperty(wxT("colspan"))) 
8242                 colSpan 
= cell
->GetProperties().GetPropertyLong(wxT("colspan")); 
8243             if (cell
->GetProperties().HasProperty(wxT("rowspan"))) 
8244                 rowSpan 
= cell
->GetProperties().GetPropertyLong(wxT("rowspan")); 
8245             if (colSpan 
> 1 || rowSpan 
> 1) 
8247                 rectArray
.Add(wxRect(i
, j
, colSpan
, rowSpan
)); 
8251     // 0.2: find which cells are subsumed by a spanning cell 
8252     for (j 
= 0; j 
< m_rowCount
; j
++) 
8254         for (i 
= 0; i 
< m_colCount
; i
++) 
8256             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8257             if (rectArray
.GetCount() == 0) 
8263                 int colSpan 
= 1, rowSpan 
= 1; 
8264                 if (cell
->GetProperties().HasProperty(wxT("colspan"))) 
8265                     colSpan 
= cell
->GetProperties().GetPropertyLong(wxT("colspan")); 
8266                 if (cell
->GetProperties().HasProperty(wxT("rowspan"))) 
8267                     rowSpan 
= cell
->GetProperties().GetPropertyLong(wxT("rowspan")); 
8268                 if (colSpan 
> 1 || rowSpan 
> 1) 
8270                     // Assume all spanning cells are shown 
8276                     for (k 
= 0; k 
< (int) rectArray
.GetCount(); k
++) 
8278                         if (rectArray
[k
].Contains(wxPoint(i
, j
))) 
8290     // TODO: find the first spanned cell in each row that spans the most columns and doesn't 
8291     // overlap with a spanned cell starting at a previous column position. 
8292     // This means we need to keep an array of rects so we can check. However 
8293     // it does also mean that some spans simply may not be taken into account 
8294     // where there are different spans happening on different rows. In these cases, 
8295     // they will simply be as wide as their constituent columns. 
8297     // (1) Do an initial layout for all cells to get minimum and maximum size, and get 
8298     // the absolute or percentage width of each column. 
8300     for (j 
= 0; j 
< m_rowCount
; j
++) 
8302         // First get the overall margins so we can calculate percentage widths based on 
8303         // the available content space for all cells on the row 
8305         int overallRowContentMargin 
= 0; 
8306         int visibleCellCount 
= 0; 
8308         for (i 
= 0; i 
< m_colCount
; i
++) 
8310             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8311             if (cell
->IsShown()) 
8313                 int cellTotalLeftMargin 
= 0, cellTotalRightMargin 
= 0, cellTotalTopMargin 
= 0, cellTotalBottomMargin 
= 0; 
8314                 GetTotalMargin(dc
, buffer
, cell
->GetAttributes(), cellTotalLeftMargin
, cellTotalRightMargin
, cellTotalTopMargin
, cellTotalBottomMargin
); 
8316                 overallRowContentMargin 
+= (cellTotalLeftMargin 
+ cellTotalRightMargin
); 
8317                 visibleCellCount 
++; 
8321         // Add in inter-cell padding 
8322         overallRowContentMargin 
+= ((visibleCellCount
-1) * paddingX
); 
8324         int rowContentWidth 
= internalTableWidth 
- overallRowContentMargin
; 
8325         wxSize 
rowTableSize(rowContentWidth
, 0); 
8326         wxTextAttrDimensionConverter 
converter(dc
, scale
, rowTableSize
); 
8328         for (i 
= 0; i 
< m_colCount
; i
++) 
8330             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8331             if (cell
->IsShown()) 
8334                 if (cell
->GetProperties().HasProperty(wxT("colspan"))) 
8335                     colSpan 
= cell
->GetProperties().GetPropertyLong(wxT("colspan")); 
8337                 // Lay out cell to find min/max widths 
8338                 cell
->Invalidate(wxRICHTEXT_ALL
); 
8339                 cell
->Layout(dc
, availableSpace
, style
); 
8343                     int absoluteCellWidth 
= -1; 
8344                     int percentageCellWidth 
= -1; 
8346                     // I think we need to calculate percentages from the internal table size, 
8347                     // minus the padding between cells which we'll need to calculate from the 
8348                     // (number of VISIBLE cells - 1)*paddingX. Then percentages that add up to 100% 
8349                     // will add up to 100%. In CSS, the width specifies the cell's content rect width, 
8350                     // so if we want to conform to that we'll need to add in the overall cell margins. 
8351                     // However, this will make it difficult to specify percentages that add up to 
8352                     // 100% and still fit within the table width. 
8353                     // Let's say two cells have 50% width. They have 10 pixels of overall margin each. 
8354                     // The table content rect is 500 pixels and the inter-cell padding is 20 pixels. 
8355                     // If we're using internal content size for the width, we would calculate the 
8356                     // the overall cell width for n cells as: 
8357                     // (500 - 20*(n-1) - overallCellMargin1 - overallCellMargin2 - ...) * percentage / 100 
8358                     // + thisOverallCellMargin 
8359                     // = 500 - 20 - 10 - 10) * 0.5 + 10 = 240 pixels overall cell width. 
8360                     // Adding this back, we get 240 + 240 + 20 = 500 pixels. 
8362                     if (cell
->GetAttributes().GetTextBoxAttr().GetWidth().IsValid()) 
8364                         int w 
= converter
.GetPixels(cell
->GetAttributes().GetTextBoxAttr().GetWidth()); 
8365                         if (cell
->GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE
) 
8367                             percentageCellWidth 
= w
; 
8371                             absoluteCellWidth 
= w
; 
8373                         // Override absolute width with minimum width if necessary 
8374                         if (cell
->GetMinSize().x 
> 0 && absoluteCellWidth 
!=1 && cell
->GetMinSize().x 
> absoluteCellWidth
) 
8375                             absoluteCellWidth 
= cell
->GetMinSize().x
; 
8378                     if (absoluteCellWidth 
!= -1) 
8380                         if (absoluteCellWidth 
> absoluteColWidths
[i
]) 
8381                             absoluteColWidths
[i
] = absoluteCellWidth
; 
8384                     if (percentageCellWidth 
!= -1) 
8386                         if (percentageCellWidth 
> percentageColWidths
[i
]) 
8387                             percentageColWidths
[i
] = percentageCellWidth
; 
8390                     if (colSpan 
== 1 && cell
->GetMinSize().x 
&& cell
->GetMinSize().x 
> minColWidths
[i
]) 
8391                         minColWidths
[i
] = cell
->GetMinSize().x
; 
8392                     if (colSpan 
== 1 && cell
->GetMaxSize().x 
&& cell
->GetMaxSize().x 
> maxColWidths
[i
]) 
8393                         maxColWidths
[i
] = cell
->GetMaxSize().x
; 
8399     // (2) Allocate initial column widths from minimum widths, absolute values and proportions 
8400     // TODO: simply merge this into (1). 
8401     for (i 
= 0; i 
< m_colCount
; i
++) 
8403         if (absoluteColWidths
[i
] > 0) 
8405             colWidths
[i
] = absoluteColWidths
[i
]; 
8407         else if (percentageColWidths
[i
] > 0) 
8409             colWidths
[i
] = percentageColWidths
[i
]; 
8411             // This is rubbish - we calculated the absolute widths from percentages, so 
8412             // we can't do it again here. 
8413             //colWidths[i] = (int) (double(percentageColWidths[i]) * double(tableWidth) / 100.0 + 0.5); 
8417     // (3) Process absolute or proportional widths of spanning columns, 
8418     // now that we know what our fixed column widths are going to be. 
8419     // Spanned cells will try to adjust columns so the span will fit. 
8420     // Even existing fixed column widths can be expanded if necessary. 
8421     // Actually, currently fixed columns widths aren't adjusted; instead, 
8422     // the algorithm favours earlier rows and adjusts unspecified column widths 
8423     // the first time only. After that, we can't know whether the column has been 
8424     // specified explicitly or not. (We could make a note if necessary.) 
8425     for (j 
= 0; j 
< m_rowCount
; j
++) 
8427         // First get the overall margins so we can calculate percentage widths based on 
8428         // the available content space for all cells on the row 
8430         int overallRowContentMargin 
= 0; 
8431         int visibleCellCount 
= 0; 
8433         for (i 
= 0; i 
< m_colCount
; i
++) 
8435             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8436             if (cell
->IsShown()) 
8438                 int cellTotalLeftMargin 
= 0, cellTotalRightMargin 
= 0, cellTotalTopMargin 
= 0, cellTotalBottomMargin 
= 0; 
8439                 GetTotalMargin(dc
, buffer
, cell
->GetAttributes(), cellTotalLeftMargin
, cellTotalRightMargin
, cellTotalTopMargin
, cellTotalBottomMargin
); 
8441                 overallRowContentMargin 
+= (cellTotalLeftMargin 
+ cellTotalRightMargin
); 
8442                 visibleCellCount 
++; 
8446         // Add in inter-cell padding 
8447         overallRowContentMargin 
+= ((visibleCellCount
-1) * paddingX
); 
8449         int rowContentWidth 
= internalTableWidth 
- overallRowContentMargin
; 
8450         wxSize 
rowTableSize(rowContentWidth
, 0); 
8451         wxTextAttrDimensionConverter 
converter(dc
, scale
, rowTableSize
); 
8453         for (i 
= 0; i 
< m_colCount
; i
++) 
8455             wxRichTextBox
* cell 
= GetCell(j
, i
); 
8456             if (cell
->IsShown()) 
8459                 if (cell
->GetProperties().HasProperty(wxT("colspan"))) 
8460                     colSpan 
= cell
->GetProperties().GetPropertyLong(wxT("colspan")); 
8464                     int spans 
= wxMin(colSpan
, m_colCount 
- i
); 
8468                         if (cell
->GetAttributes().GetTextBoxAttr().GetWidth().IsValid()) 
8470                             cellWidth 
= converter
.GetPixels(cell
->GetAttributes().GetTextBoxAttr().GetWidth()); 
8471                             // Override absolute width with minimum width if necessary 
8472                             if (cell
->GetMinSize().x 
> 0 && cellWidth 
!=1 && cell
->GetMinSize().x 
> cellWidth
) 
8473                                 cellWidth 
= cell
->GetMinSize().x
; 
8477                             // Do we want to do this? It's the only chance we get to 
8478                             // use the cell's min/max sizes, so we need to work out 
8479                             // how we're going to balance the unspecified spanning cell 
8480                             // width with the possibility more-constrained constituent cell widths. 
8481                             // Say there's a tiny bitmap giving it a max width of 10 pixels. We 
8482                             // don't want to constraint all the spanned columns to fit into this cell. 
8483                             // OK, let's say that if any of the constituent columns don't fit, 
8484                             // then we simply stop constraining the columns; instead, we'll just fit the spanning 
8485                             // cells to the columns later. 
8486                             cellWidth 
= cell
->GetMinSize().x
; 
8487                             if (cell
->GetMaxSize().x 
> cellWidth
) 
8488                                 cellWidth 
= cell
->GetMaxSize().x
; 
8491                         // Subtract the padding between cells 
8492                         int spanningWidth 
= cellWidth
; 
8493                         spanningWidth 
-= paddingX 
* (spans
-1); 
8495                         if (spanningWidth 
> 0) 
8497                             // Now share the spanning width between columns within that span 
8498                             // TODO: take into account min widths of columns within the span 
8499                             int spanningWidthLeft 
= spanningWidth
; 
8500                             int stretchColCount 
= 0; 
8501                             for (k 
= i
; k 
< (i
+spans
); k
++) 
8503                                 if (colWidths
[k
] > 0) // absolute or proportional width has been specified 
8504                                     spanningWidthLeft 
-= colWidths
[k
]; 
8508                             // Now divide what's left between the remaining columns 
8510                             if (stretchColCount 
> 0) 
8511                                 colShare 
= spanningWidthLeft 
/ stretchColCount
; 
8512                             int colShareRemainder 
= spanningWidthLeft 
- (colShare 
* stretchColCount
); 
8514                             // If fixed-width columns are currently too big, then we'll later 
8515                             // stretch the spanned cell to fit. 
8517                             if (spanningWidthLeft 
> 0) 
8519                                 for (k 
= i
; k 
< (i
+spans
); k
++) 
8521                                     if (colWidths
[k
] <= 0) // absolute or proportional width has not been specified 
8523                                         int newWidth 
= colShare
; 
8524                                         if (k 
== (i
+spans
-1)) 
8525                                             newWidth 
+= colShareRemainder
; // ensure all pixels are filled 
8526                                         colWidths
[k
] = newWidth
; 
8537     // (4) Next, share any remaining space out between columns that have not yet been calculated. 
8538     // TODO: take into account min widths of columns within the span 
8539     int tableWidthMinusPadding 
= internalTableWidth 
- (m_colCount
-1)*paddingX
; 
8540     int widthLeft 
= tableWidthMinusPadding
; 
8541     int stretchColCount 
= 0; 
8542     for (i 
= 0; i 
< m_colCount
; i
++) 
8544         // TODO: we need to take into account min widths. 
8545         // Subtract min width from width left, then 
8546         // add the colShare to the min width 
8547         if (colWidths
[i
] > 0) // absolute or proportional width has been specified 
8548             widthLeft 
-= colWidths
[i
]; 
8551             if (minColWidths
[i
] > 0) 
8552                 widthLeft 
-= minColWidths
[i
]; 
8558     // Now divide what's left between the remaining columns 
8560     if (stretchColCount 
> 0) 
8561         colShare 
= widthLeft 
/ stretchColCount
; 
8562     int colShareRemainder 
= widthLeft 
- (colShare 
* stretchColCount
); 
8564     // Check we don't have enough space, in which case shrink all columns, overriding 
8565     // any absolute/proportional widths 
8566     // TODO: actually we would like to divide up the shrinkage according to size. 
8567     // How do we calculate the proportions that will achieve this? 
8568     // Could first choose an arbitrary value for stretching cells, and then calculate 
8569     // factors to multiply each width by. 
8570     // TODO: want to record this fact and pass to an iteration that tries e.g. min widths 
8571     if (widthLeft 
< 0 || (stretchToFitTableWidth 
&& (stretchColCount 
== 0))) 
8573         colShare 
= tableWidthMinusPadding 
/ m_colCount
; 
8574         colShareRemainder 
= tableWidthMinusPadding 
- (colShare 
* m_colCount
); 
8575         for (i 
= 0; i 
< m_colCount
; i
++) 
8578             minColWidths
[i
] = 0; 
8582     // We have to adjust the columns if either we need to shrink the 
8583     // table to fit the parent/table width, or we explicitly set the 
8584     // table width and need to stretch out the table. 
8585     if (widthLeft 
< 0 || stretchToFitTableWidth
) 
8587         for (i 
= 0; i 
< m_colCount
; i
++) 
8589             if (colWidths
[i
] <= 0) // absolute or proportional width has not been specified 
8591                 if (minColWidths
[i
] > 0) 
8592                     colWidths
[i
] = minColWidths
[i
] + colShare
; 
8594                     colWidths
[i
] = colShare
; 
8595                 if (i 
== (m_colCount
-1)) 
8596                     colWidths
[i
] += colShareRemainder
; // ensure all pixels are filled 
8601     // TODO: if spanned cells have no specified or max width, make them the 
8602     // as big as the columns they span. Do this for all spanned cells in all 
8603     // rows, of course. Size any spanned cells left over at the end - even if they 
8604     // have width > 0, make sure they're limited to the appropriate column edge. 
8608     Sort out confusion between content width 
8609     and overall width later. For now, assume we specify overall width. 
8611     So, now we've laid out the table to fit into the given space 
8612     and have used specified widths and minimum widths. 
8614     Now we need to consider how we will try to take maximum width into account. 
8618     // (??) TODO: take max width into account 
8620     // (6) Lay out all cells again with the current values 
8623     int y 
= availableSpace
.y
; 
8624     for (j 
= 0; j 
< m_rowCount
; j
++) 
8626         int x 
= availableSpace
.x
; // TODO: take into account centering etc. 
8627         int maxCellHeight 
= 0; 
8628         int maxSpecifiedCellHeight 
= 0; 
8630         wxArrayInt 
actualWidths(m_colCount
); 
8632         wxTextAttrDimensionConverter 
converter(dc
, scale
); 
8633         for (i 
= 0; i 
< m_colCount
; i
++) 
8635             wxRichTextCell
* cell 
= GetCell(j
, i
); 
8636             if (cell
->IsShown()) 
8638                 // Get max specified cell height 
8639                 // Don't handle percentages for height 
8640                 if (cell
->GetAttributes().GetTextBoxAttr().GetHeight().IsValid() && cell
->GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() != wxTEXT_ATTR_UNITS_PERCENTAGE
) 
8642                     int h 
= converter
.GetPixels(cell
->GetAttributes().GetTextBoxAttr().GetHeight()); 
8643                     if (h 
> maxSpecifiedCellHeight
) 
8644                         maxSpecifiedCellHeight 
= h
; 
8647                 if (colWidths
[i
] > 0) // absolute or proportional width has been specified 
8650                     if (cell
->GetProperties().HasProperty(wxT("colspan"))) 
8651                         colSpan 
= cell
->GetProperties().GetPropertyLong(wxT("colspan")); 
8653                     wxRect availableCellSpace
; 
8655                     // TODO: take into acount spans 
8658                         // Calculate the size of this spanning cell from its constituent columns 
8660                         int spans 
= wxMin(colSpan
, m_colCount 
- i
); 
8661                         for (k 
= i
; k 
< spans
; k
++) 
8667                         availableCellSpace 
= wxRect(x
, y
, xx
, -1); 
8670                         availableCellSpace 
= wxRect(x
, y
, colWidths
[i
], -1); 
8672                     // Store actual width so we can force cell to be the appropriate width on the final loop 
8673                     actualWidths
[i
] = availableCellSpace
.GetWidth(); 
8676                     cell
->Invalidate(wxRICHTEXT_ALL
); 
8677                     cell
->Layout(dc
, availableCellSpace
, style
); 
8679                     // TODO: use GetCachedSize().x to compute 'natural' size 
8681                     x 
+= (availableCellSpace
.GetWidth() + paddingX
); 
8682                     if (cell
->GetCachedSize().y 
> maxCellHeight
) 
8683                         maxCellHeight 
= cell
->GetCachedSize().y
; 
8688         maxCellHeight 
= wxMax(maxCellHeight
, maxSpecifiedCellHeight
); 
8690         for (i 
= 0; i 
< m_colCount
; i
++) 
8692             wxRichTextCell
* cell 
= GetCell(j
, i
); 
8693             if (cell
->IsShown()) 
8695                 wxRect availableCellSpace 
= wxRect(cell
->GetPosition(), wxSize(actualWidths
[i
], maxCellHeight
)); 
8696                 // Lay out cell with new height 
8697                 cell
->Invalidate(wxRICHTEXT_ALL
); 
8698                 cell
->Layout(dc
, availableCellSpace
, style
); 
8700                 // Make sure the cell size really is the appropriate size, 
8701                 // not the calculated box size 
8702                 cell
->SetCachedSize(wxSize(actualWidths
[i
], maxCellHeight
)); 
8704                 maxRight 
= wxMax(maxRight
, cell
->GetPosition().x 
+ cell
->GetCachedSize().x
); 
8709         if (j 
< (m_rowCount
-1)) 
8713     // We need to add back the margins etc. 
8715         wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
8716         contentRect 
= wxRect(wxPoint(0, 0), wxSize(maxRight 
- availableSpace
.x
, y 
- availableSpace
.y
)); 
8717         GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
8718         SetCachedSize(marginRect
.GetSize()); 
8721     // TODO: calculate max size 
8723         SetMaxSize(GetCachedSize()); 
8726     // TODO: calculate min size 
8728         SetMinSize(GetCachedSize()); 
8731     // TODO: currently we use either a fixed table width or the parent's size. 
8732     // We also want to be able to calculate the table width from its content, 
8733     // whether using fixed column widths or cell content min/max width. 
8734     // Probably need a boolean flag to say whether we need to stretch cells 
8735     // to fit the table width, or to simply use min/max cell widths. The 
8736     // trouble with this is that if cell widths are not specified, they 
8737     // will be tiny; we could use arbitrary defaults but this seems unsatisfactory. 
8738     // Anyway, ignoring that problem, we probably need to factor layout into a function 
8739     // that can can calculate the maximum unconstrained layout in case table size is 
8740     // not specified. Then LayoutToBestSize() can choose to use either parent size to 
8741     // constrain Layout(), or the previously-calculated max size to constraint layout. 
8746 // Finds the absolute position and row height for the given character position 
8747 bool wxRichTextTable::FindPosition(wxDC
& dc
, long index
, wxPoint
& pt
, int* height
, bool forceLineStart
) 
8749     wxRichTextCell
* child 
= GetCell(index
+1); 
8752         // Find the position at the start of the child cell, since the table doesn't 
8753         // have any caret position of its own. 
8754         return child
->FindPosition(dc
, -1, pt
, height
, forceLineStart
); 
8760 // Get the cell at the given character position (in the range of the table). 
8761 wxRichTextCell
* wxRichTextTable::GetCell(long pos
) const 
8763     int row 
= 0, col 
= 0; 
8764     if (GetCellRowColumnPosition(pos
, row
, col
)) 
8766         return GetCell(row
, col
); 
8772 // Get the row/column for a given character position 
8773 bool wxRichTextTable::GetCellRowColumnPosition(long pos
, int& row
, int& col
) const 
8775     if (m_colCount 
== 0 || m_rowCount 
== 0) 
8778     row 
= (int) (pos 
/ m_colCount
); 
8779     col 
= pos 
- (row 
* m_colCount
); 
8781     wxASSERT(row 
< m_rowCount 
&& col 
< m_colCount
); 
8783     if (row 
< m_rowCount 
&& col 
< m_colCount
) 
8789 // Calculate range, taking row/cell ordering into account instead of relying 
8790 // on list ordering. 
8791 void wxRichTextTable::CalculateRange(long start
, long& end
) 
8793     long current 
= start
; 
8794     long lastEnd 
= current
; 
8803     for (i 
= 0; i 
< m_rowCount
; i
++) 
8805         for (j 
= 0; j 
< m_colCount
; j
++) 
8807             wxRichTextCell
* child 
= GetCell(i
, j
); 
8812                 child
->CalculateRange(current
, childEnd
); 
8815                 current 
= childEnd 
+ 1; 
8820     // A top-level object always has a range of size 1, 
8821     // because its children don't count at this level. 
8823     m_range
.SetRange(start
, start
); 
8825     // An object with no children has zero length 
8826     if (m_children
.GetCount() == 0) 
8828     m_ownRange
.SetRange(0, lastEnd
); 
8831 // Gets the range size. 
8832 bool wxRichTextTable::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& descent
, wxDC
& dc
, int flags
, wxPoint position
, wxArrayInt
* partialExtents
) const 
8834     return wxRichTextBox::GetRangeSize(range
, size
, descent
, dc
, flags
, position
, partialExtents
); 
8837 // Deletes content in the given range. 
8838 bool wxRichTextTable::DeleteRange(const wxRichTextRange
& WXUNUSED(range
)) 
8840     // TODO: implement deletion of cells 
8844 // Gets any text in this object for the given range. 
8845 wxString 
wxRichTextTable::GetTextForRange(const wxRichTextRange
& range
) const 
8847     return wxRichTextBox::GetTextForRange(range
); 
8850 // Copies this object. 
8851 void wxRichTextTable::Copy(const wxRichTextTable
& obj
) 
8853     wxRichTextBox::Copy(obj
); 
8857     m_rowCount 
= obj
.m_rowCount
; 
8858     m_colCount 
= obj
.m_colCount
; 
8860     m_cells
.Add(wxRichTextObjectPtrArray(), m_rowCount
); 
8863     for (i 
= 0; i 
< m_rowCount
; i
++) 
8865         wxRichTextObjectPtrArray
& colArray 
= m_cells
[i
]; 
8866         for (j 
= 0; j 
< m_colCount
; j
++) 
8868             wxRichTextCell
* cell 
= wxDynamicCast(obj
.GetCell(i
, j
)->Clone(), wxRichTextCell
); 
8876 void wxRichTextTable::ClearTable() 
8882 bool wxRichTextTable::CreateTable(int rows
, int cols
) 
8889     m_cells
.Add(wxRichTextObjectPtrArray(), rows
); 
8892     for (i 
= 0; i 
< rows
; i
++) 
8894         wxRichTextObjectPtrArray
& colArray 
= m_cells
[i
]; 
8895         for (j 
= 0; j 
< cols
; j
++) 
8897             wxRichTextCell
* cell 
= new wxRichTextCell
; 
8899             cell
->AddParagraph(wxEmptyString
); 
8908 wxRichTextCell
* wxRichTextTable::GetCell(int row
, int col
) const 
8910     wxASSERT(row 
< m_rowCount
); 
8911     wxASSERT(col 
< m_colCount
); 
8913     if (row 
< m_rowCount 
&& col 
< m_colCount
) 
8915         wxRichTextObjectPtrArray
& colArray 
= m_cells
[row
]; 
8916         wxRichTextObject
* obj 
= colArray
[col
]; 
8917         return wxDynamicCast(obj
, wxRichTextCell
); 
8923 // Returns a selection object specifying the selections between start and end character positions. 
8924 // For example, a table would deduce what cells (of range length 1) are selected when dragging across the table. 
8925 wxRichTextSelection 
wxRichTextTable::GetSelection(long start
, long end
) const 
8927     wxRichTextSelection selection
; 
8928     selection
.SetContainer((wxRichTextTable
*) this); 
8937     wxASSERT( start 
>= 0 && end 
< (m_colCount 
* m_rowCount
)); 
8939     if (end 
>= (m_colCount 
* m_rowCount
)) 
8942     // We need to find the rectangle of cells that is described by the rectangle 
8943     // with start, end as the diagonal. Make sure we don't add cells that are 
8944     // not currenty visible because they are overlapped by spanning cells. 
8946     -------------------------- 
8947     | 0  | 1  | 2  | 3  | 4  | 
8948     -------------------------- 
8949     | 5  | 6  | 7  | 8  | 9  | 
8950     -------------------------- 
8951     | 10 | 11 | 12 | 13 | 14 | 
8952     -------------------------- 
8953     | 15 | 16 | 17 | 18 | 19 | 
8954     -------------------------- 
8956     Let's say we select 6 -> 18. 
8958     Left and right edge cols of rectangle are 1 and 3 inclusive. Find least/greatest to find 
8959     which is left and which is right. 
8961     Top and bottom edge rows are 1 and 3 inclusive. Again, find least/greatest to find top and bottom. 
8963     Now go through rows from 1 to 3 and only add cells that are (a) within above column range 
8969     int leftCol 
= start 
- m_colCount 
* int(start
/m_colCount
); 
8970     int rightCol 
= end 
- m_colCount 
* int(end
/m_colCount
); 
8972     int topRow 
= int(start
/m_colCount
); 
8973     int bottomRow 
= int(end
/m_colCount
); 
8975     if (leftCol 
> rightCol
) 
8982     if (topRow 
> bottomRow
) 
8984         int tmp 
= bottomRow
; 
8990     for (i 
= topRow
; i 
<= bottomRow
; i
++) 
8992         for (j 
= leftCol
; j 
<= rightCol
; j
++) 
8994             wxRichTextCell
* cell 
= GetCell(i
, j
); 
8995             if (cell 
&& cell
->IsShown()) 
8996                 selection
.Add(cell
->GetRange()); 
9003 // Sets the attributes for the cells specified by the selection. 
9004 bool wxRichTextTable::SetCellStyle(const wxRichTextSelection
& selection
, const wxRichTextAttr
& style
, int flags
) 
9006     if (selection
.GetContainer() != this) 
9009     wxRichTextBuffer
* buffer 
= GetBuffer(); 
9010     bool haveControl 
= (buffer 
&& buffer
->GetRichTextCtrl() != NULL
); 
9011     bool withUndo 
= haveControl 
&& ((flags 
& wxRICHTEXT_SETSTYLE_WITH_UNDO
) != 0); 
9014         buffer
->BeginBatchUndo(_("Set Cell Style")); 
9016     wxRichTextObjectList::compatibility_iterator node 
= m_children
.GetFirst(); 
9019         wxRichTextCell
* cell 
= wxDynamicCast(node
->GetData(), wxRichTextCell
); 
9020         if (cell 
&& selection
.WithinSelection(cell
->GetRange().GetStart())) 
9021             SetStyle(cell
, style
, flags
); 
9022         node 
= node
->GetNext(); 
9025     // Do action, or delay it until end of batch. 
9027         buffer
->EndBatchUndo(); 
9032 bool wxRichTextTable::DeleteRows(int startRow
, int noRows
) 
9034     wxASSERT((startRow 
+ noRows
) < m_rowCount
); 
9035     if ((startRow 
+ noRows
) >= m_rowCount
) 
9039     for (i 
= startRow
; i 
< (startRow
+noRows
); i
++) 
9041         wxRichTextObjectPtrArray
& colArray 
= m_cells
[startRow
]; 
9042         for (j 
= 0; j 
< (int) colArray
.GetCount(); j
++) 
9044             wxRichTextObject
* cell 
= colArray
[j
]; 
9045             RemoveChild(cell
, true); 
9048         // Keep deleting at the same position, since we move all 
9050         m_cells
.RemoveAt(startRow
); 
9053     m_rowCount 
= m_rowCount 
- noRows
; 
9058 bool wxRichTextTable::DeleteColumns(int startCol
, int noCols
) 
9060     wxASSERT((startCol 
+ noCols
) < m_colCount
); 
9061     if ((startCol 
+ noCols
) >= m_colCount
) 
9064     bool deleteRows 
= (noCols 
== m_colCount
); 
9067     for (i 
= 0; i 
< m_rowCount
; i
++) 
9069         wxRichTextObjectPtrArray
& colArray 
= m_cells
[deleteRows 
? 0 : i
]; 
9070         for (j 
= startCol
; j 
< (startCol
+noCols
); j
++) 
9072             wxRichTextObject
* cell 
= colArray
[j
]; 
9073             RemoveChild(cell
, true); 
9077             m_cells
.RemoveAt(0); 
9082     m_colCount 
= m_colCount 
- noCols
; 
9087 bool wxRichTextTable::AddRows(int startRow
, int noRows
, const wxRichTextAttr
& attr
) 
9089     wxASSERT(startRow 
<= m_rowCount
); 
9090     if (startRow 
> m_rowCount
) 
9094     for (i 
= 0; i 
< noRows
; i
++) 
9097         if (startRow 
== m_rowCount
) 
9099             m_cells
.Add(wxRichTextObjectPtrArray()); 
9100             idx 
= m_cells
.GetCount() - 1; 
9104             m_cells
.Insert(wxRichTextObjectPtrArray(), startRow
+i
); 
9108         wxRichTextObjectPtrArray
& colArray 
= m_cells
[idx
]; 
9109         for (j 
= 0; j 
< m_colCount
; j
++) 
9111             wxRichTextCell
* cell 
= new wxRichTextCell
; 
9112             cell
->GetAttributes() = attr
; 
9119     m_rowCount 
= m_rowCount 
+ noRows
; 
9123 bool wxRichTextTable::AddColumns(int startCol
, int noCols
, const wxRichTextAttr
& attr
) 
9125     wxASSERT(startCol 
<= m_colCount
); 
9126     if (startCol 
> m_colCount
) 
9130     for (i 
= 0; i 
< m_rowCount
; i
++) 
9132         wxRichTextObjectPtrArray
& colArray 
= m_cells
[i
]; 
9133         for (j 
= 0; j 
< noCols
; j
++) 
9135             wxRichTextCell
* cell 
= new wxRichTextCell
; 
9136             cell
->GetAttributes() = attr
; 
9140             if (startCol 
== m_colCount
) 
9143                 colArray
.Insert(cell
, startCol
+j
); 
9147     m_colCount 
= m_colCount 
+ noCols
; 
9152 // Edit properties via a GUI 
9153 bool wxRichTextTable::EditProperties(wxWindow
* parent
, wxRichTextBuffer
* buffer
) 
9155     wxRichTextObjectPropertiesDialog 
boxDlg(this, wxGetTopLevelParent(parent
), wxID_ANY
, _("Table Properties")); 
9156     boxDlg
.SetAttributes(GetAttributes()); 
9158     if (boxDlg
.ShowModal() == wxID_OK
) 
9160         boxDlg
.ApplyStyle(buffer
->GetRichTextCtrl(), wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_RESET
); 
9168  * Module to initialise and clean up handlers 
9171 class wxRichTextModule
: public wxModule
 
9173 DECLARE_DYNAMIC_CLASS(wxRichTextModule
) 
9175     wxRichTextModule() {} 
9178         wxRichTextBuffer::SetRenderer(new wxRichTextStdRenderer
); 
9179         wxRichTextBuffer::InitStandardHandlers(); 
9180         wxRichTextParagraph::InitDefaultTabs(); 
9185         wxRichTextBuffer::CleanUpHandlers(); 
9186         wxRichTextDecimalToRoman(-1); 
9187         wxRichTextParagraph::ClearDefaultTabs(); 
9188         wxRichTextCtrl::ClearAvailableFontNames(); 
9189         wxRichTextBuffer::SetRenderer(NULL
); 
9193 IMPLEMENT_DYNAMIC_CLASS(wxRichTextModule
, wxModule
) 
9196 // If the richtext lib is dynamically loaded after the app has already started 
9197 // (such as from wxPython) then the built-in module system will not init this 
9198 // module.  Provide this function to do it manually. 
9199 void wxRichTextModuleInit() 
9201     wxModule
* module = new wxRichTextModule
; 
9203     wxModule::RegisterModule(module); 
9208  * Commands for undo/redo 
9212 wxRichTextCommand::wxRichTextCommand(const wxString
& name
, wxRichTextCommandId id
, wxRichTextBuffer
* buffer
, 
9213                                      wxRichTextParagraphLayoutBox
* container
, wxRichTextCtrl
* ctrl
, bool ignoreFirstTime
): wxCommand(true, name
) 
9215     /* wxRichTextAction* action = */ new wxRichTextAction(this, name
, id
, buffer
, container
, ctrl
, ignoreFirstTime
); 
9218 wxRichTextCommand::wxRichTextCommand(const wxString
& name
): wxCommand(true, name
) 
9222 wxRichTextCommand::~wxRichTextCommand() 
9227 void wxRichTextCommand::AddAction(wxRichTextAction
* action
) 
9229     if (!m_actions
.Member(action
)) 
9230         m_actions
.Append(action
); 
9233 bool wxRichTextCommand::Do() 
9235     for (wxList::compatibility_iterator node 
= m_actions
.GetFirst(); node
; node 
= node
->GetNext()) 
9237         wxRichTextAction
* action 
= (wxRichTextAction
*) node
->GetData(); 
9244 bool wxRichTextCommand::Undo() 
9246     for (wxList::compatibility_iterator node 
= m_actions
.GetLast(); node
; node 
= node
->GetPrevious()) 
9248         wxRichTextAction
* action 
= (wxRichTextAction
*) node
->GetData(); 
9255 void wxRichTextCommand::ClearActions() 
9257     WX_CLEAR_LIST(wxList
, m_actions
); 
9265 wxRichTextAction::wxRichTextAction(wxRichTextCommand
* cmd
, const wxString
& name
, wxRichTextCommandId id
, 
9266                                    wxRichTextBuffer
* buffer
, wxRichTextParagraphLayoutBox
* container
, 
9267                                    wxRichTextCtrl
* ctrl
, bool ignoreFirstTime
) 
9271     m_containerAddress
.Create(buffer
, container
); 
9272     m_ignoreThis 
= ignoreFirstTime
; 
9277     m_newParagraphs
.SetDefaultStyle(buffer
->GetDefaultStyle()); 
9278     m_newParagraphs
.SetBasicStyle(buffer
->GetBasicStyle()); 
9280         cmd
->AddAction(this); 
9283 wxRichTextAction::~wxRichTextAction() 
9289 // Returns the container that this action refers to, using the container address and top-level buffer. 
9290 wxRichTextParagraphLayoutBox
* wxRichTextAction::GetContainer() const 
9292     wxRichTextParagraphLayoutBox
* container 
= wxDynamicCast(GetContainerAddress().GetObject(m_buffer
), wxRichTextParagraphLayoutBox
); 
9297 void wxRichTextAction::CalculateRefreshOptimizations(wxArrayInt
& optimizationLineCharPositions
, wxArrayInt
& optimizationLineYPositions
) 
9299     // Store a list of line start character and y positions so we can figure out which area 
9300     // we need to refresh 
9302 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9303     wxRichTextParagraphLayoutBox
* container 
= GetContainer(); 
9304     wxASSERT(container 
!= NULL
); 
9308     // NOTE: we're assuming that the buffer is laid out correctly at this point. 
9309     // If we had several actions, which only invalidate and leave layout until the 
9310     // paint handler is called, then this might not be true. So we may need to switch 
9311     // optimisation on only when we're simply adding text and not simultaneously 
9312     // deleting a selection, for example. Or, we make sure the buffer is laid out correctly 
9313     // first, but of course this means we'll be doing it twice. 
9314     if (!m_buffer
->IsDirty() && m_ctrl
) // can only do optimisation if the buffer is already laid out correctly 
9316         wxSize clientSize 
= m_ctrl
->GetClientSize(); 
9317         wxPoint firstVisiblePt 
= m_ctrl
->GetFirstVisiblePoint(); 
9318         int lastY 
= firstVisiblePt
.y 
+ clientSize
.y
; 
9320         wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(GetRange().GetStart()); 
9321         wxRichTextObjectList::compatibility_iterator node 
= container
->GetChildren().Find(para
); 
9324             wxRichTextParagraph
* child 
= (wxRichTextParagraph
*) node
->GetData(); 
9325             wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
9328                 wxRichTextLine
* line 
= node2
->GetData(); 
9329                 wxPoint pt 
= line
->GetAbsolutePosition(); 
9330                 wxRichTextRange range 
= line
->GetAbsoluteRange(); 
9334                     node2 
= wxRichTextLineList::compatibility_iterator(); 
9335                     node 
= wxRichTextObjectList::compatibility_iterator(); 
9337                 else if (range
.GetStart() > GetPosition() && pt
.y 
>= firstVisiblePt
.y
) 
9339                     optimizationLineCharPositions
.Add(range
.GetStart()); 
9340                     optimizationLineYPositions
.Add(pt
.y
); 
9344                     node2 
= node2
->GetNext(); 
9348                 node 
= node
->GetNext(); 
9354 bool wxRichTextAction::Do() 
9356     m_buffer
->Modify(true); 
9358     wxRichTextParagraphLayoutBox
* container 
= GetContainer(); 
9359     wxASSERT(container 
!= NULL
); 
9365     case wxRICHTEXT_INSERT
: 
9367             // Store a list of line start character and y positions so we can figure out which area 
9368             // we need to refresh 
9369             wxArrayInt optimizationLineCharPositions
; 
9370             wxArrayInt optimizationLineYPositions
; 
9372 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9373             CalculateRefreshOptimizations(optimizationLineCharPositions
, optimizationLineYPositions
); 
9376             container
->InsertFragment(GetRange().GetStart(), m_newParagraphs
); 
9377             container
->UpdateRanges(); 
9379             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9380             // Layout() would stop prematurely at the top level. 
9381             container
->InvalidateHierarchy(wxRichTextRange(wxMax(0, GetRange().GetStart()-1), GetRange().GetEnd())); 
9383             long newCaretPosition 
= GetPosition() + m_newParagraphs
.GetOwnRange().GetLength(); 
9385             // Character position to caret position 
9386             newCaretPosition 
--; 
9388             // Don't take into account the last newline 
9389             if (m_newParagraphs
.GetPartialParagraph()) 
9390                 newCaretPosition 
--; 
9392                 if (m_newParagraphs
.GetChildren().GetCount() > 1) 
9394                     wxRichTextObject
* p 
= (wxRichTextObject
*) m_newParagraphs
.GetChildren().GetLast()->GetData(); 
9395                     if (p
->GetRange().GetLength() == 1) 
9396                         newCaretPosition 
--; 
9399             newCaretPosition 
= wxMin(newCaretPosition
, (container
->GetOwnRange().GetEnd()-1)); 
9401             UpdateAppearance(newCaretPosition
, true /* send update event */, & optimizationLineCharPositions
, & optimizationLineYPositions
, true /* do */); 
9403             wxRichTextEvent 
cmdEvent( 
9404                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED
, 
9405                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9406             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9407             cmdEvent
.SetRange(GetRange()); 
9408             cmdEvent
.SetPosition(GetRange().GetStart()); 
9409             cmdEvent
.SetContainer(container
); 
9411             m_buffer
->SendEvent(cmdEvent
); 
9415     case wxRICHTEXT_DELETE
: 
9417             wxArrayInt optimizationLineCharPositions
; 
9418             wxArrayInt optimizationLineYPositions
; 
9420 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9421             CalculateRefreshOptimizations(optimizationLineCharPositions
, optimizationLineYPositions
); 
9424             container
->DeleteRange(GetRange()); 
9425             container
->UpdateRanges(); 
9426             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9427             // Layout() would stop prematurely at the top level. 
9428             container
->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); 
9430             long caretPos 
= GetRange().GetStart()-1; 
9431             if (caretPos 
>= container
->GetOwnRange().GetEnd()) 
9434             UpdateAppearance(caretPos
, true /* send update event */, & optimizationLineCharPositions
, & optimizationLineYPositions
, true /* do */); 
9436             wxRichTextEvent 
cmdEvent( 
9437                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED
, 
9438                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9439             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9440             cmdEvent
.SetRange(GetRange()); 
9441             cmdEvent
.SetPosition(GetRange().GetStart()); 
9442             cmdEvent
.SetContainer(container
); 
9444             m_buffer
->SendEvent(cmdEvent
); 
9448     case wxRICHTEXT_CHANGE_STYLE
: 
9450             ApplyParagraphs(GetNewParagraphs()); 
9452             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9453             // Layout() would stop prematurely at the top level. 
9454             container
->InvalidateHierarchy(GetRange()); 
9456             UpdateAppearance(GetPosition()); 
9458             wxRichTextEvent 
cmdEvent( 
9459                 wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
, 
9460                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9461             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9462             cmdEvent
.SetRange(GetRange()); 
9463             cmdEvent
.SetPosition(GetRange().GetStart()); 
9464             cmdEvent
.SetContainer(container
); 
9466             m_buffer
->SendEvent(cmdEvent
); 
9470     case wxRICHTEXT_CHANGE_ATTRIBUTES
: 
9472             wxRichTextObject
* obj 
= m_objectAddress
.GetObject(m_buffer
); // container->GetChildAtPosition(GetRange().GetStart()); 
9475                 wxRichTextAttr oldAttr 
= obj
->GetAttributes(); 
9476                 obj
->GetAttributes() = m_attributes
; 
9477                 m_attributes 
= oldAttr
; 
9480             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9481             // Layout() would stop prematurely at the top level. 
9482             container
->InvalidateHierarchy(GetRange()); 
9484             UpdateAppearance(GetPosition()); 
9486             wxRichTextEvent 
cmdEvent( 
9487                 wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
, 
9488                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9489             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9490             cmdEvent
.SetRange(GetRange()); 
9491             cmdEvent
.SetPosition(GetRange().GetStart()); 
9492             cmdEvent
.SetContainer(container
); 
9494             m_buffer
->SendEvent(cmdEvent
); 
9498     case wxRICHTEXT_CHANGE_OBJECT
: 
9500             wxRichTextObject
* obj 
= m_objectAddress
.GetObject(m_buffer
); 
9501             // wxRichTextObject* obj = container->GetChildAtPosition(GetRange().GetStart()); 
9502             if (obj 
&& m_object
) 
9504                 wxRichTextObjectList::compatibility_iterator node 
= container
->GetChildren().Find(obj
); 
9507                     wxRichTextObject
* obj 
= node
->GetData(); 
9508                     node
->SetData(m_object
); 
9513             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9514             // Layout() would stop prematurely at the top level. 
9515             container
->InvalidateHierarchy(GetRange()); 
9517             UpdateAppearance(GetPosition()); 
9519             // TODO: send new kind of modification event 
9530 bool wxRichTextAction::Undo() 
9532     m_buffer
->Modify(true); 
9534     wxRichTextParagraphLayoutBox
* container 
= GetContainer(); 
9535     wxASSERT(container 
!= NULL
); 
9541     case wxRICHTEXT_INSERT
: 
9543             wxArrayInt optimizationLineCharPositions
; 
9544             wxArrayInt optimizationLineYPositions
; 
9546 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9547             CalculateRefreshOptimizations(optimizationLineCharPositions
, optimizationLineYPositions
); 
9550             container
->DeleteRange(GetRange()); 
9551             container
->UpdateRanges(); 
9552             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9553             // Layout() would stop prematurely at the top level. 
9554             container
->InvalidateHierarchy(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); 
9556             long newCaretPosition 
= GetPosition() - 1; 
9558             UpdateAppearance(newCaretPosition
, true, /* send update event */ & optimizationLineCharPositions
, & optimizationLineYPositions
, false /* undo */); 
9560             wxRichTextEvent 
cmdEvent( 
9561                 wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED
, 
9562                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9563             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9564             cmdEvent
.SetRange(GetRange()); 
9565             cmdEvent
.SetPosition(GetRange().GetStart()); 
9566             cmdEvent
.SetContainer(container
); 
9568             m_buffer
->SendEvent(cmdEvent
); 
9572     case wxRICHTEXT_DELETE
: 
9574             wxArrayInt optimizationLineCharPositions
; 
9575             wxArrayInt optimizationLineYPositions
; 
9577 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9578             CalculateRefreshOptimizations(optimizationLineCharPositions
, optimizationLineYPositions
); 
9581             container
->InsertFragment(GetRange().GetStart(), m_oldParagraphs
); 
9582             container
->UpdateRanges(); 
9583             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9584             // Layout() would stop prematurely at the top level. 
9585             container
->InvalidateHierarchy(GetRange()); 
9587             UpdateAppearance(GetPosition(), true, /* send update event */ & optimizationLineCharPositions
, & optimizationLineYPositions
, false /* undo */); 
9589             wxRichTextEvent 
cmdEvent( 
9590                 wxEVT_COMMAND_RICHTEXT_CONTENT_INSERTED
, 
9591                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9592             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9593             cmdEvent
.SetRange(GetRange()); 
9594             cmdEvent
.SetPosition(GetRange().GetStart()); 
9595             cmdEvent
.SetContainer(container
); 
9597             m_buffer
->SendEvent(cmdEvent
); 
9601     case wxRICHTEXT_CHANGE_STYLE
: 
9603             ApplyParagraphs(GetOldParagraphs()); 
9604             // InvalidateHierarchy goes up the hierarchy as well as down, otherwise with a nested object, 
9605             // Layout() would stop prematurely at the top level. 
9606             container
->InvalidateHierarchy(GetRange()); 
9608             UpdateAppearance(GetPosition()); 
9610             wxRichTextEvent 
cmdEvent( 
9611                 wxEVT_COMMAND_RICHTEXT_STYLE_CHANGED
, 
9612                 m_ctrl 
? m_ctrl
->GetId() : -1); 
9613             cmdEvent
.SetEventObject(m_ctrl 
? (wxObject
*) m_ctrl 
: (wxObject
*) m_buffer
); 
9614             cmdEvent
.SetRange(GetRange()); 
9615             cmdEvent
.SetPosition(GetRange().GetStart()); 
9616             cmdEvent
.SetContainer(container
); 
9618             m_buffer
->SendEvent(cmdEvent
); 
9622     case wxRICHTEXT_CHANGE_ATTRIBUTES
: 
9623     case wxRICHTEXT_CHANGE_OBJECT
: 
9634 /// Update the control appearance 
9635 void wxRichTextAction::UpdateAppearance(long caretPosition
, bool sendUpdateEvent
, wxArrayInt
* optimizationLineCharPositions
, wxArrayInt
* optimizationLineYPositions
, bool isDoCmd
) 
9637     wxRichTextParagraphLayoutBox
* container 
= GetContainer(); 
9638     wxASSERT(container 
!= NULL
); 
9644         m_ctrl
->SetFocusObject(container
); 
9645         m_ctrl
->SetCaretPosition(caretPosition
); 
9647         if (!m_ctrl
->IsFrozen()) 
9649             wxRect containerRect 
= container
->GetRect(); 
9651             m_ctrl
->LayoutContent(); 
9653             // Refresh everything if there were floating objects or the container changed size 
9654             // (we can't yet optimize in these cases, since more complex interaction with other content occurs) 
9655             if (container
->GetFloatingObjectCount() > 0 || (container
->GetParent() && containerRect 
!= container
->GetRect())) 
9657                 m_ctrl
->Refresh(false); 
9661 #if wxRICHTEXT_USE_OPTIMIZED_DRAWING 
9662             // Find refresh rectangle if we are in a position to optimise refresh 
9663             if ((m_cmdId 
== wxRICHTEXT_INSERT 
|| m_cmdId 
== wxRICHTEXT_DELETE
) && optimizationLineCharPositions
) 
9667                 wxSize clientSize 
= m_ctrl
->GetClientSize(); 
9668                 wxPoint firstVisiblePt 
= m_ctrl
->GetFirstVisiblePoint(); 
9670                 // Start/end positions 
9672                 int lastY 
= firstVisiblePt
.y 
+ clientSize
.y
; 
9674                 bool foundEnd 
= false; 
9676                 // position offset - how many characters were inserted 
9677                 int positionOffset 
= GetRange().GetLength(); 
9679                 // Determine whether this is Do or Undo, and adjust positionOffset accordingly 
9680                 if ((m_cmdId 
== wxRICHTEXT_DELETE 
&& isDoCmd
) || (m_cmdId 
== wxRICHTEXT_INSERT 
&& !isDoCmd
)) 
9681                     positionOffset 
= - positionOffset
; 
9683                 // find the first line which is being drawn at the same position as it was 
9684                 // before. Since we're talking about a simple insertion, we can assume 
9685                 // that the rest of the window does not need to be redrawn. 
9687                 wxRichTextParagraph
* para 
= container
->GetParagraphAtPosition(GetPosition()); 
9688                 // Since we support floating layout, we should redraw the whole para instead of just 
9689                 // the first line touching the invalid range. 
9692                     firstY 
= para
->GetPosition().y
; 
9695                 wxRichTextObjectList::compatibility_iterator node 
= container
->GetChildren().Find(para
); 
9698                     wxRichTextParagraph
* child 
= (wxRichTextParagraph
*) node
->GetData(); 
9699                     wxRichTextLineList::compatibility_iterator node2 
= child
->GetLines().GetFirst(); 
9702                         wxRichTextLine
* line 
= node2
->GetData(); 
9703                         wxPoint pt 
= line
->GetAbsolutePosition(); 
9704                         wxRichTextRange range 
= line
->GetAbsoluteRange(); 
9706                         // we want to find the first line that is in the same position 
9707                         // as before. This will mean we're at the end of the changed text. 
9709                         if (pt
.y 
> lastY
) // going past the end of the window, no more info 
9711                             node2 
= wxRichTextLineList::compatibility_iterator(); 
9712                             node 
= wxRichTextObjectList::compatibility_iterator(); 
9714                         // Detect last line in the buffer 
9715                         else if (!node2
->GetNext() && para
->GetRange().Contains(container
->GetOwnRange().GetEnd())) 
9717                             // If deleting text, make sure we refresh below as well as above 
9718                             if (positionOffset 
>= 0) 
9721                                 lastY 
= pt
.y 
+ line
->GetSize().y
; 
9724                             node2 
= wxRichTextLineList::compatibility_iterator(); 
9725                             node 
= wxRichTextObjectList::compatibility_iterator(); 
9731                             // search for this line being at the same position as before 
9732                             for (i 
= 0; i 
< optimizationLineCharPositions
->GetCount(); i
++) 
9734                                 if (((*optimizationLineCharPositions
)[i
] + positionOffset 
== range
.GetStart()) && 
9735                                     ((*optimizationLineYPositions
)[i
] == pt
.y
)) 
9737                                     // Stop, we're now the same as we were 
9742                                     node2 
= wxRichTextLineList::compatibility_iterator(); 
9743                                     node 
= wxRichTextObjectList::compatibility_iterator(); 
9751                             node2 
= node2
->GetNext(); 
9755                         node 
= node
->GetNext(); 
9758                 firstY 
= wxMax(firstVisiblePt
.y
, firstY
); 
9760                     lastY 
= firstVisiblePt
.y 
+ clientSize
.y
; 
9762                 // Convert to device coordinates 
9763                 wxRect 
rect(m_ctrl
->GetPhysicalPoint(wxPoint(firstVisiblePt
.x
, firstY
)), wxSize(clientSize
.x
, lastY 
- firstY
)); 
9764                 m_ctrl
->RefreshRect(rect
); 
9768                 m_ctrl
->Refresh(false); 
9770             m_ctrl
->PositionCaret(); 
9772             // This causes styles to persist when doing programmatic 
9773             // content creation except when Freeze/Thaw is used, so 
9774             // disable this and check for the consequences. 
9775             // m_ctrl->SetDefaultStyleToCursorStyle(); 
9777             if (sendUpdateEvent
) 
9778                 wxTextCtrl::SendTextUpdatedEvent(m_ctrl
); 
9783 /// Replace the buffer paragraphs with the new ones. 
9784 void wxRichTextAction::ApplyParagraphs(const wxRichTextParagraphLayoutBox
& fragment
) 
9786     wxRichTextParagraphLayoutBox
* container 
= GetContainer(); 
9787     wxASSERT(container 
!= NULL
); 
9791     wxRichTextObjectList::compatibility_iterator node 
= fragment
.GetChildren().GetFirst(); 
9794         wxRichTextParagraph
* para 
= wxDynamicCast(node
->GetData(), wxRichTextParagraph
); 
9795         wxASSERT (para 
!= NULL
); 
9797         // We'll replace the existing paragraph by finding the paragraph at this position, 
9798         // delete its node data, and setting a copy as the new node data. 
9799         // TODO: make more efficient by simply swapping old and new paragraph objects. 
9801         wxRichTextParagraph
* existingPara 
= container
->GetParagraphAtPosition(para
->GetRange().GetStart()); 
9804             wxRichTextObjectList::compatibility_iterator bufferParaNode 
= container
->GetChildren().Find(existingPara
); 
9807                 wxRichTextParagraph
* newPara 
= new wxRichTextParagraph(*para
); 
9808                 newPara
->SetParent(container
); 
9810                 bufferParaNode
->SetData(newPara
); 
9812                 delete existingPara
; 
9816         node 
= node
->GetNext(); 
9823  * This stores beginning and end positions for a range of data. 
9826 WX_DEFINE_OBJARRAY(wxRichTextRangeArray
); 
9828 /// Limit this range to be within 'range' 
9829 bool wxRichTextRange::LimitTo(const wxRichTextRange
& range
) 
9831     if (m_start 
< range
.m_start
) 
9832         m_start 
= range
.m_start
; 
9834     if (m_end 
> range
.m_end
) 
9835         m_end 
= range
.m_end
; 
9841  * wxRichTextImage implementation 
9842  * This object represents an image. 
9845 IMPLEMENT_DYNAMIC_CLASS(wxRichTextImage
, wxRichTextObject
) 
9847 wxRichTextImage::wxRichTextImage(const wxImage
& image
, wxRichTextObject
* parent
, wxRichTextAttr
* charStyle
): 
9848     wxRichTextObject(parent
) 
9850     m_imageBlock
.MakeImageBlockDefaultQuality(image
, wxBITMAP_TYPE_PNG
); 
9852         SetAttributes(*charStyle
); 
9855 wxRichTextImage::wxRichTextImage(const wxRichTextImageBlock
& imageBlock
, wxRichTextObject
* parent
, wxRichTextAttr
* charStyle
): 
9856     wxRichTextObject(parent
) 
9858     m_imageBlock 
= imageBlock
; 
9860         SetAttributes(*charStyle
); 
9863 /// Create a cached image at the required size 
9864 bool wxRichTextImage::LoadImageCache(wxDC
& dc
, bool resetCache
) 
9866     if (resetCache 
|| !m_imageCache
.IsOk() /* || m_imageCache.GetWidth() != size.x || m_imageCache.GetHeight() != size.y */) 
9868         if (!m_imageBlock
.IsOk()) 
9872         m_imageBlock
.Load(image
); 
9876         int width 
= image
.GetWidth(); 
9877         int height 
= image
.GetHeight(); 
9879         if (GetAttributes().GetTextBoxAttr().GetWidth().IsValid() && GetAttributes().GetTextBoxAttr().GetWidth().GetValue() > 0) 
9881             if (GetAttributes().GetTextBoxAttr().GetWidth().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
9882                 width 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetTextBoxAttr().GetWidth().GetValue()); 
9884                 width 
= GetAttributes().GetTextBoxAttr().GetWidth().GetValue(); 
9886         if (GetAttributes().GetTextBoxAttr().GetHeight().IsValid() && GetAttributes().GetTextBoxAttr().GetHeight().GetValue() > 0) 
9888             if (GetAttributes().GetTextBoxAttr().GetHeight().GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
9889                 height 
= ConvertTenthsMMToPixels(dc
, GetAttributes().GetTextBoxAttr().GetHeight().GetValue()); 
9891                 height 
= GetAttributes().GetTextBoxAttr().GetHeight().GetValue(); 
9894         if (image
.GetWidth() == width 
&& image
.GetHeight() == height
) 
9895             m_imageCache 
= wxBitmap(image
); 
9898             // If the original width and height is small, e.g. 400 or below, 
9899             // scale up and then down to improve image quality. This can make 
9900             // a big difference, with not much performance hit. 
9901             int upscaleThreshold 
= 400; 
9903             if (image
.GetWidth() <= upscaleThreshold 
|| image
.GetHeight() <= upscaleThreshold
) 
9905                 img 
= image
.Scale(image
.GetWidth()*2, image
.GetHeight()*2); 
9906                 img
.Rescale(width
, height
, wxIMAGE_QUALITY_HIGH
); 
9909                 img 
= image
.Scale(width
, height
, wxIMAGE_QUALITY_HIGH
); 
9910             m_imageCache 
= wxBitmap(img
); 
9914     return m_imageCache
.IsOk(); 
9918 bool wxRichTextImage::Draw(wxDC
& dc
, const wxRichTextRange
& range
, const wxRichTextSelection
& selection
, const wxRect
& rect
, int WXUNUSED(descent
), int WXUNUSED(style
)) 
9923     // Don't need cached size AFAIK 
9924     // wxSize size = GetCachedSize(); 
9925     if (!LoadImageCache(dc
)) 
9928     DrawBoxAttributes(dc
, GetBuffer(), GetAttributes(), wxRect(GetPosition(), GetCachedSize())); 
9931     int y 
= rect
.y 
+ (rect
.height 
- m_imageCache
.GetHeight()); 
9933     dc
.DrawBitmap(m_imageCache
, rect
.x
, y
, true); 
9936     wxSize 
imageSize(m_imageCache
.GetWidth(), m_imageCache
.GetHeight()); 
9937     wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
9938     marginRect 
= rect
; // outer rectangle, will calculate contentRect 
9939     GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
9941     dc
.DrawBitmap(m_imageCache
, contentRect
.x
, contentRect
.y
, true); 
9943     if (selection
.WithinSelection(range
.GetStart(), this)) 
9945         wxCheckSetBrush(dc
, *wxBLACK_BRUSH
); 
9946         wxCheckSetPen(dc
, *wxBLACK_PEN
); 
9947         dc
.SetLogicalFunction(wxINVERT
); 
9948         dc
.DrawRectangle(contentRect
); 
9949         dc
.SetLogicalFunction(wxCOPY
); 
9955 /// Lay the item out 
9956 bool wxRichTextImage::Layout(wxDC
& dc
, const wxRect
& rect
, int WXUNUSED(style
)) 
9958     if (!LoadImageCache(dc
)) 
9961     wxSize 
imageSize(m_imageCache
.GetWidth(), m_imageCache
.GetHeight()); 
9962     wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
9963     contentRect 
= wxRect(wxPoint(0,0), imageSize
); 
9964     GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
9966     wxSize overallSize 
= marginRect
.GetSize(); 
9968     SetCachedSize(overallSize
); 
9969     SetMaxSize(overallSize
); 
9970     SetMinSize(overallSize
); 
9971     SetPosition(rect
.GetPosition()); 
9976 /// Get/set the object size for the given range. Returns false if the range 
9977 /// is invalid for this object. 
9978 bool wxRichTextImage::GetRangeSize(const wxRichTextRange
& range
, wxSize
& size
, int& WXUNUSED(descent
), wxDC
& dc
, int WXUNUSED(flags
), wxPoint 
WXUNUSED(position
), wxArrayInt
* partialExtents
) const 
9980     if (!range
.IsWithin(GetRange())) 
9983     if (!((wxRichTextImage
*)this)->LoadImageCache(dc
)) 
9985         size
.x 
= 0; size
.y 
= 0; 
9987             partialExtents
->Add(0); 
9991     wxSize 
imageSize(m_imageCache
.GetWidth(), m_imageCache
.GetHeight()); 
9992     wxRect marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
; 
9993     contentRect 
= wxRect(wxPoint(0,0), imageSize
); 
9994     GetBoxRects(dc
, GetBuffer(), GetAttributes(), marginRect
, borderRect
, contentRect
, paddingRect
, outlineRect
); 
9996     wxSize overallSize 
= marginRect
.GetSize(); 
9999         partialExtents
->Add(overallSize
.x
); 
10001     size 
= overallSize
; 
10006 // Get the 'natural' size for an object. For an image, it would be the 
10008 wxTextAttrSize 
wxRichTextImage::GetNaturalSize() const 
10010     wxTextAttrSize size
; 
10011     if (GetImageCache().IsOk()) 
10013         size
.SetWidth(GetImageCache().GetWidth(), wxTEXT_ATTR_UNITS_PIXELS
); 
10014         size
.SetHeight(GetImageCache().GetHeight(), wxTEXT_ATTR_UNITS_PIXELS
); 
10021 void wxRichTextImage::Copy(const wxRichTextImage
& obj
) 
10023     wxRichTextObject::Copy(obj
); 
10025     m_imageBlock 
= obj
.m_imageBlock
; 
10028 /// Edit properties via a GUI 
10029 bool wxRichTextImage::EditProperties(wxWindow
* parent
, wxRichTextBuffer
* buffer
) 
10031     wxRichTextObjectPropertiesDialog 
imageDlg(this, wxGetTopLevelParent(parent
), wxID_ANY
, _("Picture Properties")); 
10032     imageDlg
.SetAttributes(GetAttributes()); 
10034     if (imageDlg
.ShowModal() == wxID_OK
) 
10036         // By passing wxRICHTEXT_SETSTYLE_RESET, indeterminate attributes set by the user will be set as 
10037         // indeterminate in the object. 
10038         imageDlg
.ApplyStyle(buffer
->GetRichTextCtrl(), wxRICHTEXT_SETSTYLE_WITH_UNDO
|wxRICHTEXT_SETSTYLE_RESET
); 
10050 /// Compare two attribute objects 
10051 bool wxTextAttrEq(const wxRichTextAttr
& attr1
, const wxRichTextAttr
& attr2
) 
10053     return (attr1 
== attr2
); 
10056 // Partial equality test taking flags into account 
10057 bool wxTextAttrEqPartial(const wxRichTextAttr
& attr1
, const wxRichTextAttr
& attr2
) 
10059     return attr1
.EqPartial(attr2
); 
10063 bool wxRichTextTabsEq(const wxArrayInt
& tabs1
, const wxArrayInt
& tabs2
) 
10065     if (tabs1
.GetCount() != tabs2
.GetCount()) 
10069     for (i 
= 0; i 
< tabs1
.GetCount(); i
++) 
10071         if (tabs1
[i
] != tabs2
[i
]) 
10077 bool wxRichTextApplyStyle(wxRichTextAttr
& destStyle
, const wxRichTextAttr
& style
, wxRichTextAttr
* compareWith
) 
10079     return destStyle
.Apply(style
, compareWith
); 
10082 // Remove attributes 
10083 bool wxRichTextRemoveStyle(wxRichTextAttr
& destStyle
, const wxRichTextAttr
& style
) 
10085     return destStyle
.RemoveStyle(style
); 
10088 /// Combine two bitlists, specifying the bits of interest with separate flags. 
10089 bool wxRichTextCombineBitlists(int& valueA
, int valueB
, int& flagsA
, int flagsB
) 
10091     return wxRichTextAttr::CombineBitlists(valueA
, valueB
, flagsA
, flagsB
); 
10094 /// Compare two bitlists 
10095 bool wxRichTextBitlistsEqPartial(int valueA
, int valueB
, int flags
) 
10097     return wxRichTextAttr::BitlistsEqPartial(valueA
, valueB
, flags
); 
10100 /// Split into paragraph and character styles 
10101 bool wxRichTextSplitParaCharStyles(const wxRichTextAttr
& style
, wxRichTextAttr
& parStyle
, wxRichTextAttr
& charStyle
) 
10103     return wxRichTextAttr::SplitParaCharStyles(style
, parStyle
, charStyle
); 
10106 /// Convert a decimal to Roman numerals 
10107 wxString 
wxRichTextDecimalToRoman(long n
) 
10109     static wxArrayInt decimalNumbers
; 
10110     static wxArrayString romanNumbers
; 
10115         decimalNumbers
.Clear(); 
10116         romanNumbers
.Clear(); 
10117         return wxEmptyString
; 
10120     if (decimalNumbers
.GetCount() == 0) 
10122         #define wxRichTextAddDecRom(n, r) decimalNumbers.Add(n); romanNumbers.Add(r); 
10124         wxRichTextAddDecRom(1000, wxT("M")); 
10125         wxRichTextAddDecRom(900, wxT("CM")); 
10126         wxRichTextAddDecRom(500, wxT("D")); 
10127         wxRichTextAddDecRom(400, wxT("CD")); 
10128         wxRichTextAddDecRom(100, wxT("C")); 
10129         wxRichTextAddDecRom(90, wxT("XC")); 
10130         wxRichTextAddDecRom(50, wxT("L")); 
10131         wxRichTextAddDecRom(40, wxT("XL")); 
10132         wxRichTextAddDecRom(10, wxT("X")); 
10133         wxRichTextAddDecRom(9, wxT("IX")); 
10134         wxRichTextAddDecRom(5, wxT("V")); 
10135         wxRichTextAddDecRom(4, wxT("IV")); 
10136         wxRichTextAddDecRom(1, wxT("I")); 
10142     while (n 
> 0 && i 
< 13) 
10144         if (n 
>= decimalNumbers
[i
]) 
10146             n 
-= decimalNumbers
[i
]; 
10147             roman 
+= romanNumbers
[i
]; 
10154     if (roman
.IsEmpty()) 
10160  * wxRichTextFileHandler 
10161  * Base class for file handlers 
10164 IMPLEMENT_CLASS(wxRichTextFileHandler
, wxObject
) 
10166 #if wxUSE_FFILE && wxUSE_STREAMS 
10167 bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer 
*buffer
, const wxString
& filename
) 
10169     wxFFileInputStream 
stream(filename
); 
10171         return LoadFile(buffer
, stream
); 
10176 bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer 
*buffer
, const wxString
& filename
) 
10178     wxFFileOutputStream 
stream(filename
); 
10180         return SaveFile(buffer
, stream
); 
10184 #endif // wxUSE_FFILE && wxUSE_STREAMS 
10186 /// Can we handle this filename (if using files)? By default, checks the extension. 
10187 bool wxRichTextFileHandler::CanHandle(const wxString
& filename
) const 
10189     wxString path
, file
, ext
; 
10190     wxFileName::SplitPath(filename
, & path
, & file
, & ext
); 
10192     return (ext
.Lower() == GetExtension()); 
10196  * wxRichTextTextHandler 
10197  * Plain text handler 
10200 IMPLEMENT_CLASS(wxRichTextPlainTextHandler
, wxRichTextFileHandler
) 
10203 bool wxRichTextPlainTextHandler::DoLoadFile(wxRichTextBuffer 
*buffer
, wxInputStream
& stream
) 
10205     if (!stream
.IsOk()) 
10211     while (!stream
.Eof()) 
10213         int ch 
= stream
.GetC(); 
10217             if (ch 
== 10 && lastCh 
!= 13) 
10220             if (ch 
> 0 && ch 
!= 10) 
10227     buffer
->ResetAndClearCommands(); 
10229     buffer
->AddParagraphs(str
); 
10230     buffer
->UpdateRanges(); 
10235 bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer 
*buffer
, wxOutputStream
& stream
) 
10237     if (!stream
.IsOk()) 
10240     wxString text 
= buffer
->GetText(); 
10242     wxString newLine 
= wxRichTextLineBreakChar
; 
10243     text
.Replace(newLine
, wxT("\n")); 
10245     wxCharBuffer buf 
= text
.ToAscii(); 
10247     stream
.Write((const char*) buf
, text
.length()); 
10250 #endif // wxUSE_STREAMS 
10253  * Stores information about an image, in binary in-memory form 
10256 wxRichTextImageBlock::wxRichTextImageBlock() 
10261 wxRichTextImageBlock::wxRichTextImageBlock(const wxRichTextImageBlock
& block
):wxObject() 
10267 wxRichTextImageBlock::~wxRichTextImageBlock() 
10272 void wxRichTextImageBlock::Init() 
10276     m_imageType 
= wxBITMAP_TYPE_INVALID
; 
10279 void wxRichTextImageBlock::Clear() 
10283     m_imageType 
= wxBITMAP_TYPE_INVALID
; 
10287 // Load the original image into a memory block. 
10288 // If the image is not a JPEG, we must convert it into a JPEG 
10289 // to conserve space. 
10290 // If it's not a JPEG we can make use of 'image', already scaled, so we don't have to 
10291 // load the image a 2nd time. 
10293 bool wxRichTextImageBlock::MakeImageBlock(const wxString
& filename
, wxBitmapType imageType
, 
10294                                           wxImage
& image
, bool convertToJPEG
) 
10296     m_imageType 
= imageType
; 
10298     wxString 
filenameToRead(filename
); 
10299     bool removeFile 
= false; 
10301     if (imageType 
== wxBITMAP_TYPE_INVALID
) 
10302         return false; // Could not determine image type 
10304     if ((imageType 
!= wxBITMAP_TYPE_JPEG
) && convertToJPEG
) 
10306         wxString tempFile 
= 
10307             wxFileName::CreateTempFileName(_("image")); 
10309         wxASSERT(!tempFile
.IsEmpty()); 
10311         image
.SaveFile(tempFile
, wxBITMAP_TYPE_JPEG
); 
10312         filenameToRead 
= tempFile
; 
10315         m_imageType 
= wxBITMAP_TYPE_JPEG
; 
10318     if (!file
.Open(filenameToRead
)) 
10321     m_dataSize 
= (size_t) file
.Length(); 
10326     m_data 
= ReadBlock(filenameToRead
, m_dataSize
); 
10329         wxRemoveFile(filenameToRead
); 
10331     return (m_data 
!= NULL
); 
10334 // Make an image block from the wxImage in the given 
10336 bool wxRichTextImageBlock::MakeImageBlock(wxImage
& image
, wxBitmapType imageType
, int quality
) 
10338     image
.SetOption(wxT("quality"), quality
); 
10340     if (imageType 
== wxBITMAP_TYPE_INVALID
) 
10341         return false; // Could not determine image type 
10343     return DoMakeImageBlock(image
, imageType
); 
10346 // Uses a const wxImage for efficiency, but can't set quality (only relevant for JPEG) 
10347 bool wxRichTextImageBlock::MakeImageBlockDefaultQuality(const wxImage
& image
, wxBitmapType imageType
) 
10349     if (imageType 
== wxBITMAP_TYPE_INVALID
) 
10350         return false; // Could not determine image type 
10352     return DoMakeImageBlock(image
, imageType
); 
10355 // Makes the image block 
10356 bool wxRichTextImageBlock::DoMakeImageBlock(const wxImage
& image
, wxBitmapType imageType
) 
10358     wxMemoryOutputStream memStream
; 
10359     if (!image
.SaveFile(memStream
, imageType
)) 
10364     unsigned char* block 
= new unsigned char[memStream
.GetSize()]; 
10372     m_imageType 
= imageType
; 
10373     m_dataSize 
= memStream
.GetSize(); 
10375     memStream
.CopyTo(m_data
, m_dataSize
); 
10377     return (m_data 
!= NULL
); 
10381 bool wxRichTextImageBlock::Write(const wxString
& filename
) 
10383     return WriteBlock(filename
, m_data
, m_dataSize
); 
10386 void wxRichTextImageBlock::Copy(const wxRichTextImageBlock
& block
) 
10388     m_imageType 
= block
.m_imageType
; 
10390     m_dataSize 
= block
.m_dataSize
; 
10391     if (m_dataSize 
== 0) 
10394     m_data 
= new unsigned char[m_dataSize
]; 
10396     for (i 
= 0; i 
< m_dataSize
; i
++) 
10397         m_data
[i
] = block
.m_data
[i
]; 
10401 void wxRichTextImageBlock::operator=(const wxRichTextImageBlock
& block
) 
10406 // Load a wxImage from the block 
10407 bool wxRichTextImageBlock::Load(wxImage
& image
) 
10412     // Read in the image. 
10414     wxMemoryInputStream 
mstream(m_data
, m_dataSize
); 
10415     bool success 
= image
.LoadFile(mstream
, GetImageType()); 
10417     wxString tempFile 
= wxFileName::CreateTempFileName(_("image")); 
10418     wxASSERT(!tempFile
.IsEmpty()); 
10420     if (!WriteBlock(tempFile
, m_data
, m_dataSize
)) 
10424     success 
= image
.LoadFile(tempFile
, GetImageType()); 
10425     wxRemoveFile(tempFile
); 
10431 // Write data in hex to a stream 
10432 bool wxRichTextImageBlock::WriteHex(wxOutputStream
& stream
) 
10434     if (m_dataSize 
== 0) 
10437     int bufSize 
= 100000; 
10438     if (int(2*m_dataSize
) < bufSize
) 
10439         bufSize 
= 2*m_dataSize
; 
10440     char* buf 
= new char[bufSize
+1]; 
10442     int left 
= m_dataSize
; 
10447         if (left
*2 > bufSize
) 
10449             n 
= bufSize
; left 
-= (bufSize
/2); 
10453             n 
= left
*2; left 
= 0; 
10457         for (i 
= 0; i 
< (n
/2); i
++) 
10459             wxDecToHex(m_data
[j
], b
, b
+1); 
10464         stream
.Write((const char*) buf
, n
); 
10470 // Read data in hex from a stream 
10471 bool wxRichTextImageBlock::ReadHex(wxInputStream
& stream
, int length
, wxBitmapType imageType
) 
10473     int dataSize 
= length
/2; 
10478     // create a null terminated temporary string: 
10482     m_data 
= new unsigned char[dataSize
]; 
10484     for (i 
= 0; i 
< dataSize
; i 
++) 
10486         str
[0] = (char)stream
.GetC(); 
10487         str
[1] = (char)stream
.GetC(); 
10489         m_data
[i
] = (unsigned char)wxHexToDec(str
); 
10492     m_dataSize 
= dataSize
; 
10493     m_imageType 
= imageType
; 
10498 // Allocate and read from stream as a block of memory 
10499 unsigned char* wxRichTextImageBlock::ReadBlock(wxInputStream
& stream
, size_t size
) 
10501     unsigned char* block 
= new unsigned char[size
]; 
10505     stream
.Read(block
, size
); 
10510 unsigned char* wxRichTextImageBlock::ReadBlock(const wxString
& filename
, size_t size
) 
10512     wxFileInputStream 
stream(filename
); 
10513     if (!stream
.IsOk()) 
10516     return ReadBlock(stream
, size
); 
10519 // Write memory block to stream 
10520 bool wxRichTextImageBlock::WriteBlock(wxOutputStream
& stream
, unsigned char* block
, size_t size
) 
10522     stream
.Write((void*) block
, size
); 
10523     return stream
.IsOk(); 
10527 // Write memory block to file 
10528 bool wxRichTextImageBlock::WriteBlock(const wxString
& filename
, unsigned char* block
, size_t size
) 
10530     wxFileOutputStream 
outStream(filename
); 
10531     if (!outStream
.IsOk()) 
10534     return WriteBlock(outStream
, block
, size
); 
10537 // Gets the extension for the block's type 
10538 wxString 
wxRichTextImageBlock::GetExtension() const 
10540     wxImageHandler
* handler 
= wxImage::FindHandler(GetImageType()); 
10542         return handler
->GetExtension(); 
10544         return wxEmptyString
; 
10550  * The data object for a wxRichTextBuffer 
10553 const wxChar 
*wxRichTextBufferDataObject::ms_richTextBufferFormatId 
= wxT("wxShape"); 
10555 wxRichTextBufferDataObject::wxRichTextBufferDataObject(wxRichTextBuffer
* richTextBuffer
) 
10557     m_richTextBuffer 
= richTextBuffer
; 
10559     // this string should uniquely identify our format, but is otherwise 
10561     m_formatRichTextBuffer
.SetId(GetRichTextBufferFormatId()); 
10563     SetFormat(m_formatRichTextBuffer
); 
10566 wxRichTextBufferDataObject::~wxRichTextBufferDataObject() 
10568     delete m_richTextBuffer
; 
10571 // after a call to this function, the richTextBuffer is owned by the caller and it 
10572 // is responsible for deleting it! 
10573 wxRichTextBuffer
* wxRichTextBufferDataObject::GetRichTextBuffer() 
10575     wxRichTextBuffer
* richTextBuffer 
= m_richTextBuffer
; 
10576     m_richTextBuffer 
= NULL
; 
10578     return richTextBuffer
; 
10581 wxDataFormat 
wxRichTextBufferDataObject::GetPreferredFormat(Direction 
WXUNUSED(dir
)) const 
10583     return m_formatRichTextBuffer
; 
10586 size_t wxRichTextBufferDataObject::GetDataSize() const 
10588     if (!m_richTextBuffer
) 
10594         wxStringOutputStream 
stream(& bufXML
); 
10595         if (!m_richTextBuffer
->SaveFile(stream
, wxRICHTEXT_TYPE_XML
)) 
10597             wxLogError(wxT("Could not write the buffer to an XML stream.\nYou may have forgotten to add the XML file handler.")); 
10603     wxCharBuffer buffer 
= bufXML
.mb_str(wxConvUTF8
); 
10604     return strlen(buffer
) + 1; 
10606     return bufXML
.Length()+1; 
10610 bool wxRichTextBufferDataObject::GetDataHere(void *pBuf
) const 
10612     if (!pBuf 
|| !m_richTextBuffer
) 
10618         wxStringOutputStream 
stream(& bufXML
); 
10619         if (!m_richTextBuffer
->SaveFile(stream
, wxRICHTEXT_TYPE_XML
)) 
10621             wxLogError(wxT("Could not write the buffer to an XML stream.\nYou may have forgotten to add the XML file handler.")); 
10627     wxCharBuffer buffer 
= bufXML
.mb_str(wxConvUTF8
); 
10628     size_t len 
= strlen(buffer
); 
10629     memcpy((char*) pBuf
, (const char*) buffer
, len
); 
10630     ((char*) pBuf
)[len
] = 0; 
10632     size_t len 
= bufXML
.Length(); 
10633     memcpy((char*) pBuf
, (const char*) bufXML
.c_str(), len
); 
10634     ((char*) pBuf
)[len
] = 0; 
10640 bool wxRichTextBufferDataObject::SetData(size_t WXUNUSED(len
), const void *buf
) 
10642     wxDELETE(m_richTextBuffer
); 
10644     wxString 
bufXML((const char*) buf
, wxConvUTF8
); 
10646     m_richTextBuffer 
= new wxRichTextBuffer
; 
10648     wxStringInputStream 
stream(bufXML
); 
10649     if (!m_richTextBuffer
->LoadFile(stream
, wxRICHTEXT_TYPE_XML
)) 
10651         wxLogError(wxT("Could not read the buffer from an XML stream.\nYou may have forgotten to add the XML file handler.")); 
10653         wxDELETE(m_richTextBuffer
); 
10665  * wxRichTextFontTable 
10666  * Manages quick access to a pool of fonts for rendering rich text 
10669 WX_DECLARE_STRING_HASH_MAP_WITH_DECL(wxFont
, wxRichTextFontTableHashMap
, class WXDLLIMPEXP_RICHTEXT
); 
10671 class wxRichTextFontTableData
: public wxObjectRefData
 
10674     wxRichTextFontTableData() {} 
10676     wxFont 
FindFont(const wxRichTextAttr
& fontSpec
); 
10678     wxRichTextFontTableHashMap  m_hashMap
; 
10681 wxFont 
wxRichTextFontTableData::FindFont(const wxRichTextAttr
& fontSpec
) 
10683     wxString 
facename(fontSpec
.GetFontFaceName()); 
10684     wxString 
spec(wxString::Format(wxT("%d-%d-%d-%d-%s-%d"), fontSpec
.GetFontSize(), fontSpec
.GetFontStyle(), fontSpec
.GetFontWeight(), (int) fontSpec
.GetFontUnderlined(), facename
.c_str(), (int) fontSpec
.GetFontEncoding())); 
10685     wxRichTextFontTableHashMap::iterator entry 
= m_hashMap
.find(spec
); 
10687     if ( entry 
== m_hashMap
.end() ) 
10689         wxFont 
font(fontSpec
.GetFontSize(), wxDEFAULT
, fontSpec
.GetFontStyle(), fontSpec
.GetFontWeight(), fontSpec
.GetFontUnderlined(), facename
.c_str()); 
10690         m_hashMap
[spec
] = font
; 
10695         return entry
->second
; 
10699 IMPLEMENT_DYNAMIC_CLASS(wxRichTextFontTable
, wxObject
) 
10701 wxRichTextFontTable::wxRichTextFontTable() 
10703     m_refData 
= new wxRichTextFontTableData
; 
10706 wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable
& table
) 
10712 wxRichTextFontTable::~wxRichTextFontTable() 
10717 bool wxRichTextFontTable::operator == (const wxRichTextFontTable
& table
) const 
10719     return (m_refData 
== table
.m_refData
); 
10722 void wxRichTextFontTable::operator= (const wxRichTextFontTable
& table
) 
10727 wxFont 
wxRichTextFontTable::FindFont(const wxRichTextAttr
& fontSpec
) 
10729     wxRichTextFontTableData
* data 
= (wxRichTextFontTableData
*) m_refData
; 
10731         return data
->FindFont(fontSpec
); 
10736 void wxRichTextFontTable::Clear() 
10738     wxRichTextFontTableData
* data 
= (wxRichTextFontTableData
*) m_refData
; 
10740         data
->m_hashMap
.clear(); 
10746 void wxTextBoxAttr::Reset() 
10749     m_floatMode 
= wxTEXT_BOX_ATTR_FLOAT_NONE
; 
10750     m_clearMode 
= wxTEXT_BOX_ATTR_CLEAR_NONE
; 
10751     m_collapseMode 
= wxTEXT_BOX_ATTR_COLLAPSE_NONE
; 
10752     m_verticalAlignment 
= wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT_NONE
; 
10756     m_position
.Reset(); 
10765 bool wxTextBoxAttr::operator== (const wxTextBoxAttr
& attr
) const 
10768         m_flags 
== attr
.m_flags 
&& 
10769         m_floatMode 
== attr
.m_floatMode 
&& 
10770         m_clearMode 
== attr
.m_clearMode 
&& 
10771         m_collapseMode 
== attr
.m_collapseMode 
&& 
10772         m_verticalAlignment 
== attr
.m_verticalAlignment 
&& 
10774         m_margins 
== attr
.m_margins 
&& 
10775         m_padding 
== attr
.m_padding 
&& 
10776         m_position 
== attr
.m_position 
&& 
10778         m_size 
== attr
.m_size 
&& 
10780         m_border 
== attr
.m_border 
&& 
10781         m_outline 
== attr
.m_outline
 
10785 // Partial equality test 
10786 bool wxTextBoxAttr::EqPartial(const wxTextBoxAttr
& attr
) const 
10788     if (attr
.HasFloatMode() && HasFloatMode() && (GetFloatMode() != attr
.GetFloatMode())) 
10791     if (attr
.HasClearMode() && HasClearMode() && (GetClearMode() != attr
.GetClearMode())) 
10794     if (attr
.HasCollapseBorders() && HasCollapseBorders() && (attr
.GetCollapseBorders() != GetCollapseBorders())) 
10797     if (attr
.HasVerticalAlignment() && HasVerticalAlignment() && (attr
.GetVerticalAlignment() != GetVerticalAlignment())) 
10802     if (!m_position
.EqPartial(attr
.m_position
)) 
10807     if (!m_margins
.EqPartial(attr
.m_margins
)) 
10812     if (!m_padding
.EqPartial(attr
.m_padding
)) 
10817     if (!GetBorder().EqPartial(attr
.GetBorder())) 
10822     if (!GetOutline().EqPartial(attr
.GetOutline())) 
10828 // Merges the given attributes. If compareWith 
10829 // is non-NULL, then it will be used to mask out those attributes that are the same in style 
10830 // and compareWith, for situations where we don't want to explicitly set inherited attributes. 
10831 bool wxTextBoxAttr::Apply(const wxTextBoxAttr
& attr
, const wxTextBoxAttr
* compareWith
) 
10833     if (attr
.HasFloatMode()) 
10835         if (!(compareWith 
&& compareWith
->HasFloatMode() && compareWith
->GetFloatMode() == attr
.GetFloatMode())) 
10836             SetFloatMode(attr
.GetFloatMode()); 
10839     if (attr
.HasClearMode()) 
10841         if (!(compareWith 
&& compareWith
->HasClearMode() && compareWith
->GetClearMode() == attr
.GetClearMode())) 
10842             SetClearMode(attr
.GetClearMode()); 
10845     if (attr
.HasCollapseBorders()) 
10847         if (!(compareWith 
&& compareWith
->HasCollapseBorders() && compareWith
->GetCollapseBorders() == attr
.GetCollapseBorders())) 
10848             SetCollapseBorders(attr
.GetCollapseBorders()); 
10851     if (attr
.HasVerticalAlignment()) 
10853         if (!(compareWith 
&& compareWith
->HasVerticalAlignment() && compareWith
->GetVerticalAlignment() == attr
.GetVerticalAlignment())) 
10854             SetVerticalAlignment(attr
.GetVerticalAlignment()); 
10857     m_margins
.Apply(attr
.m_margins
, compareWith 
? (& attr
.m_margins
) : (const wxTextAttrDimensions
*) NULL
); 
10858     m_padding
.Apply(attr
.m_padding
, compareWith 
? (& attr
.m_padding
) : (const wxTextAttrDimensions
*) NULL
); 
10859     m_position
.Apply(attr
.m_position
, compareWith 
? (& attr
.m_position
) : (const wxTextAttrDimensions
*) NULL
); 
10861     m_size
.Apply(attr
.m_size
, compareWith 
? (& attr
.m_size
) : (const wxTextAttrSize
*) NULL
); 
10863     m_border
.Apply(attr
.m_border
, compareWith 
? (& attr
.m_border
) : (const wxTextAttrBorders
*) NULL
); 
10864     m_outline
.Apply(attr
.m_outline
, compareWith 
? (& attr
.m_outline
) : (const wxTextAttrBorders
*) NULL
); 
10869 // Remove specified attributes from this object 
10870 bool wxTextBoxAttr::RemoveStyle(const wxTextBoxAttr
& attr
) 
10872     if (attr
.HasFloatMode()) 
10873         RemoveFlag(wxTEXT_BOX_ATTR_FLOAT
); 
10875     if (attr
.HasClearMode()) 
10876         RemoveFlag(wxTEXT_BOX_ATTR_CLEAR
); 
10878     if (attr
.HasCollapseBorders()) 
10879         RemoveFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS
); 
10881     if (attr
.HasVerticalAlignment()) 
10882         RemoveFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT
); 
10884     m_margins
.RemoveStyle(attr
.m_margins
); 
10885     m_padding
.RemoveStyle(attr
.m_padding
); 
10886     m_position
.RemoveStyle(attr
.m_position
); 
10888     m_size
.RemoveStyle(attr
.m_size
); 
10890     m_border
.RemoveStyle(attr
.m_border
); 
10891     m_outline
.RemoveStyle(attr
.m_outline
); 
10896 // Collects the attributes that are common to a range of content, building up a note of 
10897 // which attributes are absent in some objects and which clash in some objects. 
10898 void wxTextBoxAttr::CollectCommonAttributes(const wxTextBoxAttr
& attr
, wxTextBoxAttr
& clashingAttr
, wxTextBoxAttr
& absentAttr
) 
10900     if (attr
.HasFloatMode()) 
10902         if (!clashingAttr
.HasFloatMode() && !absentAttr
.HasFloatMode()) 
10904             if (HasFloatMode()) 
10906                 if (GetFloatMode() != attr
.GetFloatMode()) 
10908                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_FLOAT
); 
10909                     RemoveFlag(wxTEXT_BOX_ATTR_FLOAT
); 
10913                 SetFloatMode(attr
.GetFloatMode()); 
10917         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_FLOAT
); 
10919     if (attr
.HasClearMode()) 
10921         if (!clashingAttr
.HasClearMode() && !absentAttr
.HasClearMode()) 
10923             if (HasClearMode()) 
10925                 if (GetClearMode() != attr
.GetClearMode()) 
10927                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_CLEAR
); 
10928                     RemoveFlag(wxTEXT_BOX_ATTR_CLEAR
); 
10932                 SetClearMode(attr
.GetClearMode()); 
10936         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_CLEAR
); 
10938     if (attr
.HasCollapseBorders()) 
10940         if (!clashingAttr
.HasCollapseBorders() && !absentAttr
.HasCollapseBorders()) 
10942             if (HasCollapseBorders()) 
10944                 if (GetCollapseBorders() != attr
.GetCollapseBorders()) 
10946                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS
); 
10947                     RemoveFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS
); 
10951                 SetCollapseBorders(attr
.GetCollapseBorders()); 
10955         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_COLLAPSE_BORDERS
); 
10957     if (attr
.HasVerticalAlignment()) 
10959         if (!clashingAttr
.HasVerticalAlignment() && !absentAttr
.HasVerticalAlignment()) 
10961             if (HasVerticalAlignment()) 
10963                 if (GetVerticalAlignment() != attr
.GetVerticalAlignment()) 
10965                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT
); 
10966                     RemoveFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT
); 
10970                 SetVerticalAlignment(attr
.GetVerticalAlignment()); 
10974         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_VERTICAL_ALIGNMENT
); 
10976     m_margins
.CollectCommonAttributes(attr
.m_margins
, clashingAttr
.m_margins
, absentAttr
.m_margins
); 
10977     m_padding
.CollectCommonAttributes(attr
.m_padding
, clashingAttr
.m_padding
, absentAttr
.m_padding
); 
10978     m_position
.CollectCommonAttributes(attr
.m_position
, clashingAttr
.m_position
, absentAttr
.m_position
); 
10980     m_size
.CollectCommonAttributes(attr
.m_size
, clashingAttr
.m_size
, absentAttr
.m_size
); 
10982     m_border
.CollectCommonAttributes(attr
.m_border
, clashingAttr
.m_border
, absentAttr
.m_border
); 
10983     m_outline
.CollectCommonAttributes(attr
.m_outline
, clashingAttr
.m_outline
, absentAttr
.m_outline
); 
10988 void wxRichTextAttr::Copy(const wxRichTextAttr
& attr
) 
10990     wxTextAttr::Copy(attr
); 
10992     m_textBoxAttr 
= attr
.m_textBoxAttr
; 
10995 bool wxRichTextAttr::operator==(const wxRichTextAttr
& attr
) const 
10997     if (!(wxTextAttr::operator==(attr
))) 
11000     return (m_textBoxAttr 
== attr
.m_textBoxAttr
); 
11003 // Partial equality test taking comparison object into account 
11004 bool wxRichTextAttr::EqPartial(const wxRichTextAttr
& attr
) const 
11006     if (!(wxTextAttr::EqPartial(attr
))) 
11009     return m_textBoxAttr
.EqPartial(attr
.m_textBoxAttr
); 
11012 // Merges the given attributes. If compareWith 
11013 // is non-NULL, then it will be used to mask out those attributes that are the same in style 
11014 // and compareWith, for situations where we don't want to explicitly set inherited attributes. 
11015 bool wxRichTextAttr::Apply(const wxRichTextAttr
& style
, const wxRichTextAttr
* compareWith
) 
11017     wxTextAttr::Apply(style
, compareWith
); 
11019     return m_textBoxAttr
.Apply(style
.m_textBoxAttr
, compareWith 
? (& compareWith
->m_textBoxAttr
) : (const wxTextBoxAttr
*) NULL
); 
11022 // Remove specified attributes from this object 
11023 bool wxRichTextAttr::RemoveStyle(const wxRichTextAttr
& attr
) 
11025     wxTextAttr::RemoveStyle(*this, attr
); 
11027     return m_textBoxAttr
.RemoveStyle(attr
.m_textBoxAttr
); 
11030 // Collects the attributes that are common to a range of content, building up a note of 
11031 // which attributes are absent in some objects and which clash in some objects. 
11032 void wxRichTextAttr::CollectCommonAttributes(const wxRichTextAttr
& attr
, wxRichTextAttr
& clashingAttr
, wxRichTextAttr
& absentAttr
) 
11034     wxTextAttrCollectCommonAttributes(*this, attr
, clashingAttr
, absentAttr
); 
11036     m_textBoxAttr
.CollectCommonAttributes(attr
.m_textBoxAttr
, clashingAttr
.m_textBoxAttr
, absentAttr
.m_textBoxAttr
); 
11039 // Partial equality test 
11040 bool wxTextAttrBorder::EqPartial(const wxTextAttrBorder
& border
) const 
11042     if (border
.HasStyle() && !HasStyle() && (border
.GetStyle() != GetStyle())) 
11045     if (border
.HasColour() && !HasColour() && (border
.GetColourLong() != GetColourLong())) 
11048     if (border
.HasWidth() && !HasWidth() && !(border
.GetWidth() == GetWidth())) 
11054 // Apply border to 'this', but not if the same as compareWith 
11055 bool wxTextAttrBorder::Apply(const wxTextAttrBorder
& border
, const wxTextAttrBorder
* compareWith
) 
11057     if (border
.HasStyle()) 
11059         if (!(compareWith 
&& (border
.GetStyle() == compareWith
->GetStyle()))) 
11060             SetStyle(border
.GetStyle()); 
11062     if (border
.HasColour()) 
11064         if (!(compareWith 
&& (border
.GetColourLong() == compareWith
->GetColourLong()))) 
11065             SetColour(border
.GetColourLong()); 
11067     if (border
.HasWidth()) 
11069         if (!(compareWith 
&& (border
.GetWidth() == compareWith
->GetWidth()))) 
11070             SetWidth(border
.GetWidth()); 
11076 // Remove specified attributes from this object 
11077 bool wxTextAttrBorder::RemoveStyle(const wxTextAttrBorder
& attr
) 
11079     if (attr
.HasStyle() && HasStyle()) 
11080         SetFlags(GetFlags() & ~wxTEXT_BOX_ATTR_BORDER_STYLE
); 
11081     if (attr
.HasColour() && HasColour()) 
11082         SetFlags(GetFlags() & ~wxTEXT_BOX_ATTR_BORDER_COLOUR
); 
11083     if (attr
.HasWidth() && HasWidth()) 
11084         m_borderWidth
.Reset(); 
11089 // Collects the attributes that are common to a range of content, building up a note of 
11090 // which attributes are absent in some objects and which clash in some objects. 
11091 void wxTextAttrBorder::CollectCommonAttributes(const wxTextAttrBorder
& attr
, wxTextAttrBorder
& clashingAttr
, wxTextAttrBorder
& absentAttr
) 
11093     if (attr
.HasStyle()) 
11095         if (!clashingAttr
.HasStyle() && !absentAttr
.HasStyle()) 
11099                 if (GetStyle() != attr
.GetStyle()) 
11101                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_BORDER_STYLE
); 
11102                     RemoveFlag(wxTEXT_BOX_ATTR_BORDER_STYLE
); 
11106                 SetStyle(attr
.GetStyle()); 
11110         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_BORDER_STYLE
); 
11112     if (attr
.HasColour()) 
11114         if (!clashingAttr
.HasColour() && !absentAttr
.HasColour()) 
11118                 if (GetColour() != attr
.GetColour()) 
11120                     clashingAttr
.AddFlag(wxTEXT_BOX_ATTR_BORDER_COLOUR
); 
11121                     RemoveFlag(wxTEXT_BOX_ATTR_BORDER_COLOUR
); 
11125                 SetColour(attr
.GetColourLong()); 
11129         absentAttr
.AddFlag(wxTEXT_BOX_ATTR_BORDER_COLOUR
); 
11131     m_borderWidth
.CollectCommonAttributes(attr
.m_borderWidth
, clashingAttr
.m_borderWidth
, absentAttr
.m_borderWidth
); 
11134 // Partial equality test 
11135 bool wxTextAttrBorders::EqPartial(const wxTextAttrBorders
& borders
) const 
11137     return m_left
.EqPartial(borders
.m_left
) && m_right
.EqPartial(borders
.m_right
) && 
11138             m_top
.EqPartial(borders
.m_top
) && m_bottom
.EqPartial(borders
.m_bottom
); 
11141 // Apply border to 'this', but not if the same as compareWith 
11142 bool wxTextAttrBorders::Apply(const wxTextAttrBorders
& borders
, const wxTextAttrBorders
* compareWith
) 
11144     m_left
.Apply(borders
.m_left
, compareWith 
? (& compareWith
->m_left
) : (const wxTextAttrBorder
*) NULL
); 
11145     m_right
.Apply(borders
.m_right
, compareWith 
? (& compareWith
->m_right
) : (const wxTextAttrBorder
*) NULL
); 
11146     m_top
.Apply(borders
.m_top
, compareWith 
? (& compareWith
->m_top
) : (const wxTextAttrBorder
*) NULL
); 
11147     m_bottom
.Apply(borders
.m_bottom
, compareWith 
? (& compareWith
->m_bottom
) : (const wxTextAttrBorder
*) NULL
); 
11151 // Remove specified attributes from this object 
11152 bool wxTextAttrBorders::RemoveStyle(const wxTextAttrBorders
& attr
) 
11154     m_left
.RemoveStyle(attr
.m_left
); 
11155     m_right
.RemoveStyle(attr
.m_right
); 
11156     m_top
.RemoveStyle(attr
.m_top
); 
11157     m_bottom
.RemoveStyle(attr
.m_bottom
); 
11161 // Collects the attributes that are common to a range of content, building up a note of 
11162 // which attributes are absent in some objects and which clash in some objects. 
11163 void wxTextAttrBorders::CollectCommonAttributes(const wxTextAttrBorders
& attr
, wxTextAttrBorders
& clashingAttr
, wxTextAttrBorders
& absentAttr
) 
11165     m_left
.CollectCommonAttributes(attr
.m_left
, clashingAttr
.m_left
, absentAttr
.m_left
); 
11166     m_right
.CollectCommonAttributes(attr
.m_right
, clashingAttr
.m_right
, absentAttr
.m_right
); 
11167     m_top
.CollectCommonAttributes(attr
.m_top
, clashingAttr
.m_top
, absentAttr
.m_top
); 
11168     m_bottom
.CollectCommonAttributes(attr
.m_bottom
, clashingAttr
.m_bottom
, absentAttr
.m_bottom
); 
11171 // Set style of all borders 
11172 void wxTextAttrBorders::SetStyle(int style
) 
11174     m_left
.SetStyle(style
); 
11175     m_right
.SetStyle(style
); 
11176     m_top
.SetStyle(style
); 
11177     m_bottom
.SetStyle(style
); 
11180 // Set colour of all borders 
11181 void wxTextAttrBorders::SetColour(unsigned long colour
) 
11183     m_left
.SetColour(colour
); 
11184     m_right
.SetColour(colour
); 
11185     m_top
.SetColour(colour
); 
11186     m_bottom
.SetColour(colour
); 
11189 void wxTextAttrBorders::SetColour(const wxColour
& colour
) 
11191     m_left
.SetColour(colour
); 
11192     m_right
.SetColour(colour
); 
11193     m_top
.SetColour(colour
); 
11194     m_bottom
.SetColour(colour
); 
11197 // Set width of all borders 
11198 void wxTextAttrBorders::SetWidth(const wxTextAttrDimension
& width
) 
11200     m_left
.SetWidth(width
); 
11201     m_right
.SetWidth(width
); 
11202     m_top
.SetWidth(width
); 
11203     m_bottom
.SetWidth(width
); 
11206 // Partial equality test 
11207 bool wxTextAttrDimension::EqPartial(const wxTextAttrDimension
& dim
) const 
11209     if (dim
.IsValid() && IsValid() && !((*this) == dim
)) 
11215 bool wxTextAttrDimension::Apply(const wxTextAttrDimension
& dim
, const wxTextAttrDimension
* compareWith
) 
11219         if (!(compareWith 
&& dim 
== (*compareWith
))) 
11226 // Collects the attributes that are common to a range of content, building up a note of 
11227 // which attributes are absent in some objects and which clash in some objects. 
11228 void wxTextAttrDimension::CollectCommonAttributes(const wxTextAttrDimension
& attr
, wxTextAttrDimension
& clashingAttr
, wxTextAttrDimension
& absentAttr
) 
11230     if (attr
.IsValid()) 
11232         if (!clashingAttr
.IsValid() && !absentAttr
.IsValid()) 
11236                 if (!((*this) == attr
)) 
11238                     clashingAttr
.SetValid(true); 
11247         absentAttr
.SetValid(true); 
11250 wxTextAttrDimensionConverter::wxTextAttrDimensionConverter(wxDC
& dc
, double scale
, const wxSize
& parentSize
) 
11252     m_ppi 
= dc
.GetPPI().x
; m_scale 
= scale
; m_parentSize 
= parentSize
; 
11255 wxTextAttrDimensionConverter::wxTextAttrDimensionConverter(int ppi
, double scale
, const wxSize
& parentSize
) 
11257     m_ppi 
= ppi
; m_scale 
= scale
; m_parentSize 
= parentSize
; 
11260 int wxTextAttrDimensionConverter::ConvertTenthsMMToPixels(int units
) const 
11262     return wxRichTextObject::ConvertTenthsMMToPixels(m_ppi
, units
, m_scale
); 
11265 int wxTextAttrDimensionConverter::ConvertPixelsToTenthsMM(int pixels
) const 
11267     return wxRichTextObject::ConvertPixelsToTenthsMM(m_ppi
, pixels
, m_scale
); 
11270 int wxTextAttrDimensionConverter::GetPixels(const wxTextAttrDimension
& dim
, int direction
) const 
11272     if (dim
.GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
11273         return ConvertTenthsMMToPixels(dim
.GetValue()); 
11274     else if (dim
.GetUnits() == wxTEXT_ATTR_UNITS_PIXELS
) 
11275         return dim
.GetValue(); 
11276     else if (dim
.GetUnits() == wxTEXT_ATTR_UNITS_PERCENTAGE
) 
11278         wxASSERT(m_parentSize 
!= wxDefaultSize
); 
11279         if (direction 
== wxHORIZONTAL
) 
11280             return (int) (double(m_parentSize
.x
) * double(dim
.GetValue()) / 100.0); 
11282             return (int) (double(m_parentSize
.y
) * double(dim
.GetValue()) / 100.0); 
11291 int wxTextAttrDimensionConverter::GetTenthsMM(const wxTextAttrDimension
& dim
) const 
11293     if (dim
.GetUnits() == wxTEXT_ATTR_UNITS_TENTHS_MM
) 
11294         return dim
.GetValue(); 
11295     else if (dim
.GetUnits() == wxTEXT_ATTR_UNITS_PIXELS
) 
11296         return ConvertPixelsToTenthsMM(dim
.GetValue()); 
11304 // Partial equality test 
11305 bool wxTextAttrDimensions::EqPartial(const wxTextAttrDimensions
& dims
) const 
11307     if (!m_left
.EqPartial(dims
.m_left
)) 
11310     if (!m_right
.EqPartial(dims
.m_right
)) 
11313     if (!m_top
.EqPartial(dims
.m_top
)) 
11316     if (!m_bottom
.EqPartial(dims
.m_bottom
)) 
11322 // Apply border to 'this', but not if the same as compareWith 
11323 bool wxTextAttrDimensions::Apply(const wxTextAttrDimensions
& dims
, const wxTextAttrDimensions
* compareWith
) 
11325     m_left
.Apply(dims
.m_left
, compareWith 
? (& compareWith
->m_left
) : (const wxTextAttrDimension
*) NULL
); 
11326     m_right
.Apply(dims
.m_right
, compareWith 
? (& compareWith
->m_right
): (const wxTextAttrDimension
*) NULL
); 
11327     m_top
.Apply(dims
.m_top
, compareWith 
? (& compareWith
->m_top
): (const wxTextAttrDimension
*) NULL
); 
11328     m_bottom
.Apply(dims
.m_bottom
, compareWith 
? (& compareWith
->m_bottom
): (const wxTextAttrDimension
*) NULL
); 
11333 // Remove specified attributes from this object 
11334 bool wxTextAttrDimensions::RemoveStyle(const wxTextAttrDimensions
& attr
) 
11336     if (attr
.m_left
.IsValid()) 
11338     if (attr
.m_right
.IsValid()) 
11340     if (attr
.m_top
.IsValid()) 
11342     if (attr
.m_bottom
.IsValid()) 
11348 // Collects the attributes that are common to a range of content, building up a note of 
11349 // which attributes are absent in some objects and which clash in some objects. 
11350 void wxTextAttrDimensions::CollectCommonAttributes(const wxTextAttrDimensions
& attr
, wxTextAttrDimensions
& clashingAttr
, wxTextAttrDimensions
& absentAttr
) 
11352     m_left
.CollectCommonAttributes(attr
.m_left
, clashingAttr
.m_left
, absentAttr
.m_left
); 
11353     m_right
.CollectCommonAttributes(attr
.m_right
, clashingAttr
.m_right
, absentAttr
.m_right
); 
11354     m_top
.CollectCommonAttributes(attr
.m_top
, clashingAttr
.m_top
, absentAttr
.m_top
); 
11355     m_bottom
.CollectCommonAttributes(attr
.m_bottom
, clashingAttr
.m_bottom
, absentAttr
.m_bottom
); 
11358 // Partial equality test 
11359 bool wxTextAttrSize::EqPartial(const wxTextAttrSize
& size
) const 
11361     if (!m_width
.EqPartial(size
.m_width
)) 
11364     if (!m_height
.EqPartial(size
.m_height
)) 
11370 // Apply border to 'this', but not if the same as compareWith 
11371 bool wxTextAttrSize::Apply(const wxTextAttrSize
& size
, const wxTextAttrSize
* compareWith
) 
11373     m_width
.Apply(size
.m_width
, compareWith 
? (& compareWith
->m_width
) : (const wxTextAttrDimension
*) NULL
); 
11374     m_height
.Apply(size
.m_height
, compareWith 
? (& compareWith
->m_height
): (const wxTextAttrDimension
*) NULL
); 
11379 // Remove specified attributes from this object 
11380 bool wxTextAttrSize::RemoveStyle(const wxTextAttrSize
& attr
) 
11382     if (attr
.m_width
.IsValid()) 
11384     if (attr
.m_height
.IsValid()) 
11390 // Collects the attributes that are common to a range of content, building up a note of 
11391 // which attributes are absent in some objects and which clash in some objects. 
11392 void wxTextAttrSize::CollectCommonAttributes(const wxTextAttrSize
& attr
, wxTextAttrSize
& clashingAttr
, wxTextAttrSize
& absentAttr
) 
11394     m_width
.CollectCommonAttributes(attr
.m_width
, clashingAttr
.m_width
, absentAttr
.m_width
); 
11395     m_height
.CollectCommonAttributes(attr
.m_height
, clashingAttr
.m_height
, absentAttr
.m_height
); 
11398 // Collects the attributes that are common to a range of content, building up a note of 
11399 // which attributes are absent in some objects and which clash in some objects. 
11400 void wxTextAttrCollectCommonAttributes(wxTextAttr
& currentStyle
, const wxTextAttr
& attr
, wxTextAttr
& clashingAttr
, wxTextAttr
& absentAttr
) 
11402     absentAttr
.SetFlags(absentAttr
.GetFlags() | (~attr
.GetFlags() & wxTEXT_ATTR_ALL
)); 
11403     absentAttr
.SetTextEffectFlags(absentAttr
.GetTextEffectFlags() | (~attr
.GetTextEffectFlags() & 0xFFFF)); 
11405     long forbiddenFlags 
= clashingAttr
.GetFlags()|absentAttr
.GetFlags(); 
11407     if (attr
.HasFont()) 
11409         if (attr
.HasFontSize() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_SIZE
)) 
11411             if (currentStyle
.HasFontSize()) 
11413                 if (currentStyle
.GetFontSize() != attr
.GetFontSize()) 
11415                     // Clash of attr - mark as such 
11416                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_SIZE
); 
11417                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_SIZE
); 
11421                 currentStyle
.SetFontSize(attr
.GetFontSize()); 
11424         if (attr
.HasFontItalic() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_ITALIC
)) 
11426             if (currentStyle
.HasFontItalic()) 
11428                 if (currentStyle
.GetFontStyle() != attr
.GetFontStyle()) 
11430                     // Clash of attr - mark as such 
11431                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_ITALIC
); 
11432                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_ITALIC
); 
11436                 currentStyle
.SetFontStyle(attr
.GetFontStyle()); 
11439         if (attr
.HasFontFamily() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_FAMILY
)) 
11441             if (currentStyle
.HasFontFamily()) 
11443                 if (currentStyle
.GetFontFamily() != attr
.GetFontFamily()) 
11445                     // Clash of attr - mark as such 
11446                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_FAMILY
); 
11447                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_FAMILY
); 
11451                 currentStyle
.SetFontFamily(attr
.GetFontFamily()); 
11454         if (attr
.HasFontWeight() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_WEIGHT
)) 
11456             if (currentStyle
.HasFontWeight()) 
11458                 if (currentStyle
.GetFontWeight() != attr
.GetFontWeight()) 
11460                     // Clash of attr - mark as such 
11461                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_WEIGHT
); 
11462                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_WEIGHT
); 
11466                 currentStyle
.SetFontWeight(attr
.GetFontWeight()); 
11469         if (attr
.HasFontFaceName() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_FACE
)) 
11471             if (currentStyle
.HasFontFaceName()) 
11473                 wxString 
faceName1(currentStyle
.GetFontFaceName()); 
11474                 wxString 
faceName2(attr
.GetFontFaceName()); 
11476                 if (faceName1 
!= faceName2
) 
11478                     // Clash of attr - mark as such 
11479                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_FACE
); 
11480                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_FACE
); 
11484                 currentStyle
.SetFontFaceName(attr
.GetFontFaceName()); 
11487         if (attr
.HasFontUnderlined() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_FONT_UNDERLINE
)) 
11489             if (currentStyle
.HasFontUnderlined()) 
11491                 if (currentStyle
.GetFontUnderlined() != attr
.GetFontUnderlined()) 
11493                     // Clash of attr - mark as such 
11494                     clashingAttr
.AddFlag(wxTEXT_ATTR_FONT_UNDERLINE
); 
11495                     currentStyle
.RemoveFlag(wxTEXT_ATTR_FONT_UNDERLINE
); 
11499                 currentStyle
.SetFontUnderlined(attr
.GetFontUnderlined()); 
11503     if (attr
.HasTextColour() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_TEXT_COLOUR
)) 
11505         if (currentStyle
.HasTextColour()) 
11507             if (currentStyle
.GetTextColour() != attr
.GetTextColour()) 
11509                 // Clash of attr - mark as such 
11510                 clashingAttr
.AddFlag(wxTEXT_ATTR_TEXT_COLOUR
); 
11511                 currentStyle
.RemoveFlag(wxTEXT_ATTR_TEXT_COLOUR
); 
11515             currentStyle
.SetTextColour(attr
.GetTextColour()); 
11518     if (attr
.HasBackgroundColour() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_BACKGROUND_COLOUR
)) 
11520         if (currentStyle
.HasBackgroundColour()) 
11522             if (currentStyle
.GetBackgroundColour() != attr
.GetBackgroundColour()) 
11524                 // Clash of attr - mark as such 
11525                 clashingAttr
.AddFlag(wxTEXT_ATTR_BACKGROUND_COLOUR
); 
11526                 currentStyle
.RemoveFlag(wxTEXT_ATTR_BACKGROUND_COLOUR
); 
11530             currentStyle
.SetBackgroundColour(attr
.GetBackgroundColour()); 
11533     if (attr
.HasAlignment() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_ALIGNMENT
)) 
11535         if (currentStyle
.HasAlignment()) 
11537             if (currentStyle
.GetAlignment() != attr
.GetAlignment()) 
11539                 // Clash of attr - mark as such 
11540                 clashingAttr
.AddFlag(wxTEXT_ATTR_ALIGNMENT
); 
11541                 currentStyle
.RemoveFlag(wxTEXT_ATTR_ALIGNMENT
); 
11545             currentStyle
.SetAlignment(attr
.GetAlignment()); 
11548     if (attr
.HasTabs() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_TABS
)) 
11550         if (currentStyle
.HasTabs()) 
11552             if (!wxRichTextTabsEq(currentStyle
.GetTabs(), attr
.GetTabs())) 
11554                 // Clash of attr - mark as such 
11555                 clashingAttr
.AddFlag(wxTEXT_ATTR_TABS
); 
11556                 currentStyle
.RemoveFlag(wxTEXT_ATTR_TABS
); 
11560             currentStyle
.SetTabs(attr
.GetTabs()); 
11563     if (attr
.HasLeftIndent() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_LEFT_INDENT
)) 
11565         if (currentStyle
.HasLeftIndent()) 
11567             if (currentStyle
.GetLeftIndent() != attr
.GetLeftIndent() || currentStyle
.GetLeftSubIndent() != attr
.GetLeftSubIndent()) 
11569                 // Clash of attr - mark as such 
11570                 clashingAttr
.AddFlag(wxTEXT_ATTR_LEFT_INDENT
); 
11571                 currentStyle
.RemoveFlag(wxTEXT_ATTR_LEFT_INDENT
); 
11575             currentStyle
.SetLeftIndent(attr
.GetLeftIndent(), attr
.GetLeftSubIndent()); 
11578     if (attr
.HasRightIndent() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_RIGHT_INDENT
)) 
11580         if (currentStyle
.HasRightIndent()) 
11582             if (currentStyle
.GetRightIndent() != attr
.GetRightIndent()) 
11584                 // Clash of attr - mark as such 
11585                 clashingAttr
.AddFlag(wxTEXT_ATTR_RIGHT_INDENT
); 
11586                 currentStyle
.RemoveFlag(wxTEXT_ATTR_RIGHT_INDENT
); 
11590             currentStyle
.SetRightIndent(attr
.GetRightIndent()); 
11593     if (attr
.HasParagraphSpacingAfter() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_PARA_SPACING_AFTER
)) 
11595         if (currentStyle
.HasParagraphSpacingAfter()) 
11597             if (currentStyle
.GetParagraphSpacingAfter() != attr
.GetParagraphSpacingAfter()) 
11599                 // Clash of attr - mark as such 
11600                 clashingAttr
.AddFlag(wxTEXT_ATTR_PARA_SPACING_AFTER
); 
11601                 currentStyle
.RemoveFlag(wxTEXT_ATTR_PARA_SPACING_AFTER
); 
11605             currentStyle
.SetParagraphSpacingAfter(attr
.GetParagraphSpacingAfter()); 
11608     if (attr
.HasParagraphSpacingBefore() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_PARA_SPACING_BEFORE
)) 
11610         if (currentStyle
.HasParagraphSpacingBefore()) 
11612             if (currentStyle
.GetParagraphSpacingBefore() != attr
.GetParagraphSpacingBefore()) 
11614                 // Clash of attr - mark as such 
11615                 clashingAttr
.AddFlag(wxTEXT_ATTR_PARA_SPACING_BEFORE
); 
11616                 currentStyle
.RemoveFlag(wxTEXT_ATTR_PARA_SPACING_BEFORE
); 
11620             currentStyle
.SetParagraphSpacingBefore(attr
.GetParagraphSpacingBefore()); 
11623     if (attr
.HasLineSpacing() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_LINE_SPACING
)) 
11625         if (currentStyle
.HasLineSpacing()) 
11627             if (currentStyle
.GetLineSpacing() != attr
.GetLineSpacing()) 
11629                 // Clash of attr - mark as such 
11630                 clashingAttr
.AddFlag(wxTEXT_ATTR_LINE_SPACING
); 
11631                 currentStyle
.RemoveFlag(wxTEXT_ATTR_LINE_SPACING
); 
11635             currentStyle
.SetLineSpacing(attr
.GetLineSpacing()); 
11638     if (attr
.HasCharacterStyleName() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_CHARACTER_STYLE_NAME
)) 
11640         if (currentStyle
.HasCharacterStyleName()) 
11642             if (currentStyle
.GetCharacterStyleName() != attr
.GetCharacterStyleName()) 
11644                 // Clash of attr - mark as such 
11645                 clashingAttr
.AddFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME
); 
11646                 currentStyle
.RemoveFlag(wxTEXT_ATTR_CHARACTER_STYLE_NAME
); 
11650             currentStyle
.SetCharacterStyleName(attr
.GetCharacterStyleName()); 
11653     if (attr
.HasParagraphStyleName() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_PARAGRAPH_STYLE_NAME
)) 
11655         if (currentStyle
.HasParagraphStyleName()) 
11657             if (currentStyle
.GetParagraphStyleName() != attr
.GetParagraphStyleName()) 
11659                 // Clash of attr - mark as such 
11660                 clashingAttr
.AddFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME
); 
11661                 currentStyle
.RemoveFlag(wxTEXT_ATTR_PARAGRAPH_STYLE_NAME
); 
11665             currentStyle
.SetParagraphStyleName(attr
.GetParagraphStyleName()); 
11668     if (attr
.HasListStyleName() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_LIST_STYLE_NAME
)) 
11670         if (currentStyle
.HasListStyleName()) 
11672             if (currentStyle
.GetListStyleName() != attr
.GetListStyleName()) 
11674                 // Clash of attr - mark as such 
11675                 clashingAttr
.AddFlag(wxTEXT_ATTR_LIST_STYLE_NAME
); 
11676                 currentStyle
.RemoveFlag(wxTEXT_ATTR_LIST_STYLE_NAME
); 
11680             currentStyle
.SetListStyleName(attr
.GetListStyleName()); 
11683     if (attr
.HasBulletStyle() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_BULLET_STYLE
)) 
11685         if (currentStyle
.HasBulletStyle()) 
11687             if (currentStyle
.GetBulletStyle() != attr
.GetBulletStyle()) 
11689                 // Clash of attr - mark as such 
11690                 clashingAttr
.AddFlag(wxTEXT_ATTR_BULLET_STYLE
); 
11691                 currentStyle
.RemoveFlag(wxTEXT_ATTR_BULLET_STYLE
); 
11695             currentStyle
.SetBulletStyle(attr
.GetBulletStyle()); 
11698     if (attr
.HasBulletNumber() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_BULLET_NUMBER
)) 
11700         if (currentStyle
.HasBulletNumber()) 
11702             if (currentStyle
.GetBulletNumber() != attr
.GetBulletNumber()) 
11704                 // Clash of attr - mark as such 
11705                 clashingAttr
.AddFlag(wxTEXT_ATTR_BULLET_NUMBER
); 
11706                 currentStyle
.RemoveFlag(wxTEXT_ATTR_BULLET_NUMBER
); 
11710             currentStyle
.SetBulletNumber(attr
.GetBulletNumber()); 
11713     if (attr
.HasBulletText() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_BULLET_TEXT
)) 
11715         if (currentStyle
.HasBulletText()) 
11717             if (currentStyle
.GetBulletText() != attr
.GetBulletText()) 
11719                 // Clash of attr - mark as such 
11720                 clashingAttr
.AddFlag(wxTEXT_ATTR_BULLET_TEXT
); 
11721                 currentStyle
.RemoveFlag(wxTEXT_ATTR_BULLET_TEXT
); 
11726             currentStyle
.SetBulletText(attr
.GetBulletText()); 
11727             currentStyle
.SetBulletFont(attr
.GetBulletFont()); 
11731     if (attr
.HasBulletName() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_BULLET_NAME
)) 
11733         if (currentStyle
.HasBulletName()) 
11735             if (currentStyle
.GetBulletName() != attr
.GetBulletName()) 
11737                 // Clash of attr - mark as such 
11738                 clashingAttr
.AddFlag(wxTEXT_ATTR_BULLET_NAME
); 
11739                 currentStyle
.RemoveFlag(wxTEXT_ATTR_BULLET_NAME
); 
11744             currentStyle
.SetBulletName(attr
.GetBulletName()); 
11748     if (attr
.HasURL() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_URL
)) 
11750         if (currentStyle
.HasURL()) 
11752             if (currentStyle
.GetURL() != attr
.GetURL()) 
11754                 // Clash of attr - mark as such 
11755                 clashingAttr
.AddFlag(wxTEXT_ATTR_URL
); 
11756                 currentStyle
.RemoveFlag(wxTEXT_ATTR_URL
); 
11761             currentStyle
.SetURL(attr
.GetURL()); 
11765     if (attr
.HasTextEffects() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_EFFECTS
)) 
11767         if (currentStyle
.HasTextEffects()) 
11769             // We need to find the bits in the new attr that are different: 
11770             // just look at those bits that are specified by the new attr. 
11772             // We need to remove the bits and flags that are not common between current attr 
11773             // and new attr. In so doing we need to take account of the styles absent from one or more of the 
11774             // previous styles. 
11776             int currentRelevantTextEffects 
= currentStyle
.GetTextEffects() & attr
.GetTextEffectFlags(); 
11777             int newRelevantTextEffects 
= attr
.GetTextEffects() & attr
.GetTextEffectFlags(); 
11779             if (currentRelevantTextEffects 
!= newRelevantTextEffects
) 
11781                 // Find the text effects that were different, using XOR 
11782                 int differentEffects 
= currentRelevantTextEffects 
^ newRelevantTextEffects
; 
11784                 // Clash of attr - mark as such 
11785                 clashingAttr
.SetTextEffectFlags(clashingAttr
.GetTextEffectFlags() | differentEffects
); 
11786                 currentStyle
.SetTextEffectFlags(currentStyle
.GetTextEffectFlags() & ~differentEffects
); 
11791             currentStyle
.SetTextEffects(attr
.GetTextEffects()); 
11792             currentStyle
.SetTextEffectFlags(attr
.GetTextEffectFlags()); 
11795         // Mask out the flags and values that cannot be common because they were absent in one or more objecrs 
11796         // that we've looked at so far 
11797         currentStyle
.SetTextEffects(currentStyle
.GetTextEffects() & ~absentAttr
.GetTextEffectFlags()); 
11798         currentStyle
.SetTextEffectFlags(currentStyle
.GetTextEffectFlags() & ~absentAttr
.GetTextEffectFlags()); 
11800         if (currentStyle
.GetTextEffectFlags() == 0) 
11801             currentStyle
.RemoveFlag(wxTEXT_ATTR_EFFECTS
); 
11804     if (attr
.HasOutlineLevel() && !wxHasStyle(forbiddenFlags
, wxTEXT_ATTR_OUTLINE_LEVEL
)) 
11806         if (currentStyle
.HasOutlineLevel()) 
11808             if (currentStyle
.GetOutlineLevel() != attr
.GetOutlineLevel()) 
11810                 // Clash of attr - mark as such 
11811                 clashingAttr
.AddFlag(wxTEXT_ATTR_OUTLINE_LEVEL
); 
11812                 currentStyle
.RemoveFlag(wxTEXT_ATTR_OUTLINE_LEVEL
); 
11816             currentStyle
.SetOutlineLevel(attr
.GetOutlineLevel()); 
11820 WX_DEFINE_OBJARRAY(wxRichTextVariantArray
); 
11822 IMPLEMENT_DYNAMIC_CLASS(wxRichTextProperties
, wxObject
) 
11824 bool wxRichTextProperties::operator==(const wxRichTextProperties
& props
) const 
11826     if (m_properties
.GetCount() != props
.GetCount()) 
11830     for (i 
= 0; i 
< m_properties
.GetCount(); i
++) 
11832         const wxVariant
& var1 
= m_properties
[i
]; 
11833         int idx 
= props
.Find(var1
.GetName()); 
11836         const wxVariant
& var2 
= props
.m_properties
[idx
]; 
11837         if (!(var1 
== var2
)) 
11844 wxArrayString 
wxRichTextProperties::GetPropertyNames() const 
11848     for (i 
= 0; i 
< m_properties
.GetCount(); i
++) 
11850         arr
.Add(m_properties
[i
].GetName()); 
11855 int wxRichTextProperties::Find(const wxString
& name
) const 
11858     for (i 
= 0; i 
< m_properties
.GetCount(); i
++) 
11860         if (m_properties
[i
].GetName() == name
) 
11866 wxVariant
* wxRichTextProperties::FindOrCreateProperty(const wxString
& name
) 
11868     int idx 
= Find(name
); 
11869     if (idx 
== wxNOT_FOUND
) 
11870         SetProperty(name
, wxString()); 
11872     if (idx 
!= wxNOT_FOUND
) 
11874         return & (*this)[idx
]; 
11880 const wxVariant
& wxRichTextProperties::GetProperty(const wxString
& name
) const 
11882     static const wxVariant nullVariant
; 
11883     int idx 
= Find(name
); 
11885         return m_properties
[idx
]; 
11887         return nullVariant
; 
11890 wxString 
wxRichTextProperties::GetPropertyString(const wxString
& name
) const 
11892     return GetProperty(name
).GetString(); 
11895 long wxRichTextProperties::GetPropertyLong(const wxString
& name
) const 
11897     return GetProperty(name
).GetLong(); 
11900 bool wxRichTextProperties::GetPropertyBool(const wxString
& name
) const 
11902     return GetProperty(name
).GetBool(); 
11905 double wxRichTextProperties::GetPropertyDouble(const wxString
& name
) const 
11907     return GetProperty(name
).GetDouble(); 
11910 void wxRichTextProperties::SetProperty(const wxVariant
& variant
) 
11912     wxASSERT(!variant
.GetName().IsEmpty()); 
11914     int idx 
= Find(variant
.GetName()); 
11917         m_properties
.Add(variant
); 
11919         m_properties
[idx
] = variant
; 
11922 void wxRichTextProperties::SetProperty(const wxString
& name
, const wxVariant
& variant
) 
11924     int idx 
= Find(name
); 
11925     wxVariant 
var(variant
); 
11929         m_properties
.Add(var
); 
11931         m_properties
[idx
] = var
; 
11934 void wxRichTextProperties::SetProperty(const wxString
& name
, const wxString
& value
) 
11936     SetProperty(name
, wxVariant(value
, name
)); 
11939 void wxRichTextProperties::SetProperty(const wxString
& name
, long value
) 
11941     SetProperty(name
, wxVariant(value
, name
)); 
11944 void wxRichTextProperties::SetProperty(const wxString
& name
, double value
) 
11946     SetProperty(name
, wxVariant(value
, name
)); 
11949 void wxRichTextProperties::SetProperty(const wxString
& name
, bool value
) 
11951     SetProperty(name
, wxVariant(value
, name
)); 
11954 wxRichTextObject
* wxRichTextObjectAddress::GetObject(wxRichTextParagraphLayoutBox
* topLevelContainer
) const 
11956     if (m_address
.GetCount() == 0) 
11957         return topLevelContainer
; 
11959     wxRichTextCompositeObject
* p 
= topLevelContainer
; 
11961     while (p 
&& i 
< m_address
.GetCount()) 
11963         int pos 
= m_address
[i
]; 
11964         wxASSERT(pos 
>= 0 && pos 
< (int) p
->GetChildren().GetCount()); 
11965         if (pos 
< 0 || pos 
>= (int) p
->GetChildren().GetCount()) 
11968         wxRichTextObject
* p1 
= p
->GetChild(pos
); 
11969         if (i 
== (m_address
.GetCount()-1)) 
11972         p 
= wxDynamicCast(p1
, wxRichTextCompositeObject
); 
11978 bool wxRichTextObjectAddress::Create(wxRichTextParagraphLayoutBox
* topLevelContainer
, wxRichTextObject
* obj
) 
11982     if (topLevelContainer 
== obj
) 
11985     wxRichTextObject
* o 
= obj
; 
11988         wxRichTextCompositeObject
* p 
= wxDynamicCast(o
->GetParent(), wxRichTextCompositeObject
); 
11992         int pos 
= p
->GetChildren().IndexOf(o
); 
11996         m_address
.Insert(pos
, 0); 
11998         if (p 
== topLevelContainer
) 
12007 bool wxRichTextSelection::operator==(const wxRichTextSelection
& sel
) const 
12009     if (m_container 
!= sel
.m_container
) 
12011     if (m_ranges
.GetCount() != sel
.m_ranges
.GetCount()) 
12014     for (i 
= 0; i 
< m_ranges
.GetCount(); i
++) 
12015         if (!(m_ranges
[i
] == sel
.m_ranges
[i
])) 
12020 // Get the selections appropriate to the specified object, if any; returns wxRICHTEXT_NO_SELECTION if none 
12021 // or none at the level of the object's container. 
12022 wxRichTextRangeArray 
wxRichTextSelection::GetSelectionForObject(wxRichTextObject
* obj
) const 
12026         wxRichTextParagraphLayoutBox
* container 
= obj
->GetParentContainer(); 
12028         if (container 
== m_container
) 
12031         container 
= obj
->GetContainer(); 
12034             if (container
->GetParent()) 
12036                 // If we found that our object's container is within the range of 
12037                 // a selection higher up, then assume the whole original object 
12038                 // is also selected. 
12039                 wxRichTextParagraphLayoutBox
* parentContainer 
= container
->GetParentContainer(); 
12040                 if (parentContainer 
== m_container
) 
12042                     if (WithinSelection(container
->GetRange().GetStart(), m_ranges
)) 
12044                         wxRichTextRangeArray ranges
; 
12045                         ranges
.Add(obj
->GetRange()); 
12050                 container 
= parentContainer
; 
12059     return wxRichTextRangeArray(); 
12062 // Is the given position within the selection? 
12063 bool wxRichTextSelection::WithinSelection(long pos
, wxRichTextObject
* obj
) const 
12069         wxRichTextRangeArray selectionRanges 
= GetSelectionForObject(obj
); 
12070         return WithinSelection(pos
, selectionRanges
); 
12074 // Is the given position within the selection range? 
12075 bool wxRichTextSelection::WithinSelection(long pos
, const wxRichTextRangeArray
& ranges
) 
12078     for (i 
= 0; i 
< ranges
.GetCount(); i
++) 
12080         const wxRichTextRange
& range 
= ranges
[i
]; 
12081         if (pos 
>= range
.GetStart() && pos 
<= range
.GetEnd()) 
12087 // Is the given range completely within the selection range? 
12088 bool wxRichTextSelection::WithinSelection(const wxRichTextRange
& range
, const wxRichTextRangeArray
& ranges
) 
12091     for (i 
= 0; i 
< ranges
.GetCount(); i
++) 
12093         const wxRichTextRange
& eachRange 
= ranges
[i
]; 
12094         if (range
.IsWithin(eachRange
))