+bool wxRichTextPlainText::CanSplit(wxRichTextDrawingContext& context) const
+{
+ // If this object has any virtual attributes at all, whether for the whole object
+ // or individual ones, we should try splitting it by calling Split.
+ // Must be more than one character in order to be able to split.
+ return m_text.Length() > 1 && context.HasVirtualAttributes((wxRichTextObject*) this);
+}
+
+wxRichTextObject* wxRichTextPlainText::Split(wxRichTextDrawingContext& context)
+{
+ int count = context.GetVirtualSubobjectAttributesCount(this);
+ if (count > 0 && GetParent())
+ {
+ wxRichTextCompositeObject* parent = wxDynamicCast(GetParent(), wxRichTextCompositeObject);
+ wxRichTextObjectList::compatibility_iterator node = parent->GetChildren().Find(this);
+ if (node)
+ {
+ const wxRichTextAttr emptyAttr;
+ wxRichTextObjectList::compatibility_iterator next = node->GetNext();
+
+ wxArrayInt positions;
+ wxRichTextAttrArray attributes;
+ if (context.GetVirtualSubobjectAttributes(this, positions, attributes) && positions.GetCount() > 0)
+ {
+ wxASSERT(positions.GetCount() == attributes.GetCount());
+
+ // We will gather up runs of text with the same virtual attributes
+
+ int len = m_text.Length();
+ int i = 0;
+
+ // runStart and runEnd represent the accumulated run with a consistent attribute
+ // that hasn't yet been appended
+ int runStart = -1;
+ int runEnd = -1;
+ wxRichTextAttr currentAttr;
+ wxString text = m_text;
+ wxRichTextPlainText* lastPlainText = this;
+
+ for (i = 0; i < (int) positions.GetCount(); i++)
+ {
+ int pos = positions[i];
+ wxASSERT(pos >= 0 && pos < len);
+ if (pos >= 0 && pos < len)
+ {
+ const wxRichTextAttr& attr = attributes[i];
+
+ if (pos == 0)
+ {
+ runStart = 0;
+ currentAttr = attr;
+ }
+ // Check if there was a gap from the last known attribute and this.
+ // In that case, we need to do something with the span of non-attributed text.
+ else if ((pos-1) > runEnd)
+ {
+ if (runEnd == -1)
+ {
+ // We hadn't processed anything previously, so the previous run is from the text start
+ // to just before this position. The current attribute remains empty.
+ runStart = 0;
+ runEnd = pos-1;
+ }
+ else
+ {
+ // If the previous attribute matches the gap's attribute (i.e., no attributes)
+ // then just extend the run.
+ if (currentAttr.IsDefault())
+ {
+ runEnd = pos-1;
+ }
+ else
+ {
+ // We need to add an object, or reuse the existing one.
+ if (runStart == 0)
+ {
+ lastPlainText = this;
+ SetText(text.Mid(runStart, runEnd - runStart + 1));
+ }
+ else
+ {
+ wxRichTextPlainText* obj = new wxRichTextPlainText;
+ lastPlainText = obj;
+ obj->SetAttributes(GetAttributes());
+ obj->SetProperties(GetProperties());
+ obj->SetParent(parent);
+
+ obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+ if (next)
+ parent->GetChildren().Insert(next, obj);
+ else
+ parent->GetChildren().Append(obj);
+ }
+
+ runStart = runEnd+1;
+ runEnd = pos-1;
+
+ currentAttr = emptyAttr;
+ }
+ }
+ }
+
+ wxASSERT(runEnd == pos-1);
+
+ // Now we only have to deal with the previous run
+ if (currentAttr == attr)
+ {
+ // If we still have the same attributes, then we
+ // simply increase the run size.
+ runEnd = pos;
+ }
+ else
+ {
+ if (runEnd >= 0)
+ {
+ // We need to add an object, or reuse the existing one.
+ if (runStart == 0)
+ {
+ lastPlainText = this;
+ SetText(text.Mid(runStart, runEnd - runStart + 1));
+ }
+ else
+ {
+ wxRichTextPlainText* obj = new wxRichTextPlainText;
+ lastPlainText = obj;
+ obj->SetAttributes(GetAttributes());
+ obj->SetProperties(GetProperties());
+ obj->SetParent(parent);
+
+ obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+ if (next)
+ parent->GetChildren().Insert(next, obj);
+ else
+ parent->GetChildren().Append(obj);
+ }
+ }
+
+ runStart = pos;
+ runEnd = pos;
+
+ currentAttr = attr;
+ }
+ }
+ }
+
+ // We may still have a run to add, and possibly a no-attribute text fragment after that.
+ // If the whole string was already a single attribute (the run covers the whole string), don't split.
+ if ((runStart != -1) && !(runStart == 0 && runEnd == (len-1)))
+ {
+ // If the current attribute is empty, merge the run with the next fragment
+ // which by definition (because it's not specified) has empty attributes.
+ if (currentAttr.IsDefault())
+ runEnd = (len-1);
+
+ if (runEnd < (len-1))
+ {
+ // We need to add an object, or reuse the existing one.
+ if (runStart == 0)
+ {
+ lastPlainText = this;
+ SetText(text.Mid(runStart, runEnd - runStart + 1));
+ }
+ else
+ {
+ wxRichTextPlainText* obj = new wxRichTextPlainText;
+ lastPlainText = obj;
+ obj->SetAttributes(GetAttributes());
+ obj->SetProperties(GetProperties());
+ obj->SetParent(parent);
+
+ obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+ if (next)
+ parent->GetChildren().Insert(next, obj);
+ else
+ parent->GetChildren().Append(obj);
+ }
+
+ runStart = runEnd+1;
+ runEnd = (len-1);
+ }
+
+ // Now the last, non-attributed fragment at the end, if any
+ if ((runStart < len) && !(runStart == 0 && runEnd == (len-1)))
+ {
+ wxASSERT(runStart != 0);
+
+ wxRichTextPlainText* obj = new wxRichTextPlainText;
+ obj->SetAttributes(GetAttributes());
+ obj->SetProperties(GetProperties());
+ obj->SetParent(parent);
+
+ obj->SetText(text.Mid(runStart, runEnd - runStart + 1));
+ if (next)
+ parent->GetChildren().Insert(next, obj);
+ else
+ parent->GetChildren().Append(obj);
+
+ lastPlainText = obj;
+ }
+ }
+
+ return lastPlainText;
+ }
+ }
+ }
+ return this;
+}
+