+ // Same level as before, do nothing except increment level's number afterwards
+ if (currentLevel == thisLevel)
+ {
+ }
+ // A deeper level: start renumbering all levels after current level
+ else if (thisLevel > currentLevel)
+ {
+ for (i = currentLevel+1; i <= thisLevel; i++)
+ {
+ levels[i] = 0;
+ }
+ currentLevel = thisLevel;
+ }
+ else if (thisLevel < currentLevel)
+ {
+ currentLevel = thisLevel;
+ }
+
+ // Use the current numbering if -1 and we have a bullet number already
+ if (levels[currentLevel] == -1)
+ {
+ if (newPara->GetAttributes().HasBulletNumber())
+ levels[currentLevel] = newPara->GetAttributes().GetBulletNumber();
+ else
+ levels[currentLevel] = 1;
+ }
+ else
+ {
+ levels[currentLevel] ++;
+ }
+
+ newPara->GetAttributes().SetBulletNumber(levels[currentLevel]);
+
+ // Create the bullet text if an outline list
+ if (listStyle.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE)
+ {
+ wxString text;
+ for (i = 0; i <= currentLevel; i++)
+ {
+ if (!text.IsEmpty())
+ text += wxT(".");
+ text += wxString::Format(wxT("%d"), levels[i]);
+ }
+ newPara->GetAttributes().SetBulletText(text);
+ }
+ }
+ }
+ }
+
+ node = node->GetNext();
+ }
+
+ // Do action, or delay it until end of batch.
+ if (haveControl && withUndo)
+ GetRichTextCtrl()->GetBuffer().SubmitAction(action);
+
+ return true;
+}
+
+bool wxRichTextParagraphLayoutBox::NumberList(const wxRichTextRange& range, const wxString& defName, int flags, int startFrom, int specifiedLevel)
+{
+ if (GetStyleSheet())
+ {
+ wxRichTextListStyleDefinition* def = NULL;
+ if (!defName.IsEmpty())
+ def = GetStyleSheet()->FindListStyle(defName);
+ return NumberList(range, def, flags, startFrom, specifiedLevel);
+ }
+ return false;
+}
+
+/// Promote the list items within the given range. promoteBy can be a positive or negative number, e.g. 1 or -1
+bool wxRichTextParagraphLayoutBox::PromoteList(int promoteBy, const wxRichTextRange& range, wxRichTextListStyleDefinition* def, int flags, int specifiedLevel)
+{
+ // TODO
+ // One strategy is to first work out the range within which renumbering must occur. Then could pass these two ranges
+ // to NumberList with a flag indicating promotion is required within one of the ranges.
+ // Find first and last paragraphs in range. Then for first, calculate new indentation and look back until we find
+ // a paragraph that either has no list style, or has one that is different or whose indentation is less.
+ // We start renumbering from the para after that different para we found. We specify that the numbering of that
+ // list position will start from 1.
+ // Similarly, we look after the last para in the promote range for an indentation that is less (or no list style).
+ // We can end the renumbering at this point.
+
+ // For now, only renumber within the promotion range.
+
+ return DoNumberList(range, range, promoteBy, def, flags, 1, specifiedLevel);
+}
+
+bool wxRichTextParagraphLayoutBox::PromoteList(int promoteBy, const wxRichTextRange& range, const wxString& defName, int flags, int specifiedLevel)
+{
+ if (GetStyleSheet())
+ {
+ wxRichTextListStyleDefinition* def = NULL;
+ if (!defName.IsEmpty())
+ def = GetStyleSheet()->FindListStyle(defName);
+ return PromoteList(promoteBy, range, def, flags, specifiedLevel);
+ }
+ return false;
+}
+
+/// Fills in the attributes for numbering a paragraph after previousParagraph. It also finds the
+/// position of the paragraph that it had to start looking from.
+bool wxRichTextParagraphLayoutBox::FindNextParagraphNumber(wxRichTextParagraph* previousParagraph, wxTextAttr& attr) const
+{
+ if (!previousParagraph->GetAttributes().HasFlag(wxTEXT_ATTR_BULLET_STYLE) || previousParagraph->GetAttributes().GetBulletStyle() == wxTEXT_ATTR_BULLET_STYLE_NONE)
+ return false;
+
+ wxRichTextStyleSheet* styleSheet = GetStyleSheet();
+ if (styleSheet && !previousParagraph->GetAttributes().GetListStyleName().IsEmpty())
+ {
+ wxRichTextListStyleDefinition* def = styleSheet->FindListStyle(previousParagraph->GetAttributes().GetListStyleName());
+ if (def)
+ {
+ // int thisIndent = previousParagraph->GetAttributes().GetLeftIndent();
+ // int thisLevel = def->FindLevelForIndent(thisIndent);
+
+ bool isOutline = (previousParagraph->GetAttributes().GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_OUTLINE) != 0;
+
+ attr.SetFlags(previousParagraph->GetAttributes().GetFlags() & (wxTEXT_ATTR_BULLET_STYLE|wxTEXT_ATTR_BULLET_NUMBER|wxTEXT_ATTR_BULLET_TEXT|wxTEXT_ATTR_BULLET_NAME));
+ if (previousParagraph->GetAttributes().HasBulletName())
+ attr.SetBulletName(previousParagraph->GetAttributes().GetBulletName());
+ attr.SetBulletStyle(previousParagraph->GetAttributes().GetBulletStyle());
+ attr.SetListStyleName(previousParagraph->GetAttributes().GetListStyleName());
+
+ int nextNumber = previousParagraph->GetAttributes().GetBulletNumber() + 1;
+ attr.SetBulletNumber(nextNumber);
+
+ if (isOutline)
+ {
+ wxString text = previousParagraph->GetAttributes().GetBulletText();
+ if (!text.IsEmpty())
+ {
+ int pos = text.Find(wxT('.'), true);
+ if (pos != wxNOT_FOUND)
+ {
+ text = text.Mid(0, text.Length() - pos - 1);
+ }
+ else
+ text = wxEmptyString;
+ if (!text.IsEmpty())
+ text += wxT(".");
+ text += wxString::Format(wxT("%d"), nextNumber);
+ attr.SetBulletText(text);
+ }
+ }
+
+ return true;
+ }
+ else
+ return false;
+ }
+ else
+ return false;
+}
+
+/*!
+ * wxRichTextParagraph
+ * This object represents a single paragraph (or in a straight text editor, a line).
+ */
+
+IMPLEMENT_DYNAMIC_CLASS(wxRichTextParagraph, wxRichTextBox)
+
+wxArrayInt wxRichTextParagraph::sm_defaultTabs;
+
+wxRichTextParagraph::wxRichTextParagraph(wxRichTextObject* parent, wxTextAttr* style):
+ wxRichTextBox(parent)
+{
+ if (style)
+ SetAttributes(*style);
+}
+
+wxRichTextParagraph::wxRichTextParagraph(const wxString& text, wxRichTextObject* parent, wxTextAttr* paraStyle, wxTextAttr* charStyle):
+ wxRichTextBox(parent)
+{
+ if (paraStyle)
+ SetAttributes(*paraStyle);
+
+ AppendChild(new wxRichTextPlainText(text, this, charStyle));
+}
+
+wxRichTextParagraph::~wxRichTextParagraph()
+{
+ ClearLines();
+}
+
+/// Draw the item
+bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int WXUNUSED(descent), int style)
+{
+ wxTextAttr attr = GetCombinedAttributes();
+
+ // Draw the bullet, if any
+ if (attr.GetBulletStyle() != wxTEXT_ATTR_BULLET_STYLE_NONE)
+ {
+ if (attr.GetLeftSubIndent() != 0)
+ {
+ int spaceBeforePara = ConvertTenthsMMToPixels(dc, attr.GetParagraphSpacingBefore());
+ int leftIndent = ConvertTenthsMMToPixels(dc, attr.GetLeftIndent());
+
+ wxTextAttr bulletAttr(GetCombinedAttributes());
+
+ // Combine with the font of the first piece of content, if one is specified
+ if (GetChildren().GetCount() > 0)
+ {
+ wxRichTextObject* firstObj = (wxRichTextObject*) GetChildren().GetFirst()->GetData();
+ if (firstObj->GetAttributes().HasFont())
+ {
+ wxRichTextApplyStyle(bulletAttr, firstObj->GetAttributes());
+ }
+ }
+
+ // Get line height from first line, if any
+ wxRichTextLine* line = m_cachedLines.GetFirst() ? (wxRichTextLine* ) m_cachedLines.GetFirst()->GetData() : (wxRichTextLine*) NULL;
+
+ wxPoint linePos;
+ int lineHeight wxDUMMY_INITIALIZE(0);
+ if (line)
+ {
+ lineHeight = line->GetSize().y;
+ linePos = line->GetPosition() + GetPosition();
+ }
+ else
+ {
+ wxFont font;
+ if (bulletAttr.HasFont() && GetBuffer())
+ font = GetBuffer()->GetFontTable().FindFont(bulletAttr);
+ else
+ font = (*wxNORMAL_FONT);
+
+ wxCheckSetFont(dc, font);
+
+ lineHeight = dc.GetCharHeight();
+ linePos = GetPosition();
+ linePos.y += spaceBeforePara;
+ }
+
+ wxRect bulletRect(GetPosition().x + leftIndent, linePos.y, linePos.x - (GetPosition().x + leftIndent), lineHeight);
+
+ if (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_BITMAP)
+ {
+ if (wxRichTextBuffer::GetRenderer())
+ wxRichTextBuffer::GetRenderer()->DrawBitmapBullet(this, dc, bulletAttr, bulletRect);
+ }
+ else if (attr.GetBulletStyle() & wxTEXT_ATTR_BULLET_STYLE_STANDARD)
+ {
+ if (wxRichTextBuffer::GetRenderer())
+ wxRichTextBuffer::GetRenderer()->DrawStandardBullet(this, dc, bulletAttr, bulletRect);
+ }
+ else
+ {
+ wxString bulletText = GetBulletText();
+
+ if (!bulletText.empty() && wxRichTextBuffer::GetRenderer())
+ wxRichTextBuffer::GetRenderer()->DrawTextBullet(this, dc, bulletAttr, bulletRect, bulletText);
+ }
+ }
+ }
+
+ // Draw the range for each line, one object at a time.
+
+ wxRichTextLineList::compatibility_iterator node = m_cachedLines.GetFirst();
+ while (node)
+ {
+ wxRichTextLine* line = node->GetData();
+ wxRichTextRange lineRange = line->GetAbsoluteRange();