#include "wx/module.h"
#endif
+#include "wx/settings.h"
#include "wx/filename.h"
#include "wx/clipbrd.h"
#include "wx/wfstream.h"
const wxChar wxRichTextLineBreakChar = (wxChar) 29;
+// Helpers for efficiency
+
+inline void wxCheckSetFont(wxDC& dc, const wxFont& font)
+{
+ const wxFont& font1 = dc.GetFont();
+ if (font1.IsOk() && font.IsOk())
+ {
+ if (font1.GetPointSize() == font.GetPointSize() &&
+ font1.GetFamily() == font.GetFamily() &&
+ font1.GetStyle() == font.GetStyle() &&
+ font1.GetWeight() == font.GetWeight() &&
+ font1.GetUnderlined() == font.GetUnderlined() &&
+ font1.GetFaceName() == font.GetFaceName())
+ return;
+ }
+ dc.SetFont(font);
+}
+
+inline void wxCheckSetPen(wxDC& dc, const wxPen& pen)
+{
+ const wxPen& pen1 = dc.GetPen();
+ if (pen1.IsOk() && pen.IsOk())
+ {
+ if (pen1.GetWidth() == pen.GetWidth() &&
+ pen1.GetStyle() == pen.GetStyle() &&
+ pen1.GetColour() == pen.GetColour())
+ return;
+ }
+ dc.SetPen(pen);
+}
+
+inline void wxCheckSetBrush(wxDC& dc, const wxBrush& brush)
+{
+ const wxBrush& brush1 = dc.GetBrush();
+ if (brush1.IsOk() && brush.IsOk())
+ {
+ if (brush1.GetStyle() == brush.GetStyle() &&
+ brush1.GetColour() == brush.GetColour())
+ return;
+ }
+ dc.SetBrush(brush);
+}
+
/*!
* wxRichTextObject
* This is the base for drawable objects.
node = node->GetNext();
}
- return wxRICHTEXT_HITTEST_NONE;
+ textPosition = GetRange().GetEnd()-1;
+ return wxRICHTEXT_HITTEST_AFTER|wxRICHTEXT_HITTEST_OUTSIDE;
}
/// Finds the absolute position and row height for the given character position
if (invalidRange == wxRICHTEXT_ALL)
layoutAll = true;
else // If we know what range is affected, start laying out from that point on.
- if (invalidRange.GetStart() > GetRange().GetStart())
+ if (invalidRange.GetStart() >= GetRange().GetStart())
{
wxRichTextParagraph* firstParagraph = GetParagraphAtPosition(invalidRange.GetStart());
if (firstParagraph)
wxRichTextObjectList::compatibility_iterator previousNode;
if ( firstNode )
previousNode = firstNode->GetPrevious();
- if (firstNode && previousNode)
+ if (firstNode)
{
- wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
- availableSpace.y = previousParagraph->GetPosition().y + previousParagraph->GetCachedSize().y;
+ if (previousNode)
+ {
+ wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph);
+ availableSpace.y = previousParagraph->GetPosition().y + previousParagraph->GetCachedSize().y;
+ }
// Now we're going to start iterating from the first affected paragraph.
node = firstNode;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxChar ch = text[i];
if (ch == wxT('\n') || ch == wxT('\r'))
{
- wxRichTextPlainText* plainText = (wxRichTextPlainText*) para->GetChildren().GetFirst()->GetData();
- plainText->SetText(line);
+ if (i != (len-1))
+ {
+ wxRichTextPlainText* plainText = (wxRichTextPlainText*) para->GetChildren().GetFirst()->GetData();
+ plainText->SetText(line);
- para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
+ para = new wxRichTextParagraph(wxEmptyString, this, pStyle, cStyle);
- AppendChild(para);
+ AppendChild(para);
- lastPara = para;
- line = wxEmptyString;
+ lastPara = para;
+ line = wxEmptyString;
+ }
}
else
line += ch;
wxTextAttr defaultCharStyle;
wxTextAttr defaultParaStyle;
- wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
+
+ // If the default style is a named paragraph style, don't apply any character formatting
+ // to the initial text string.
+ if (GetDefaultStyle().HasParagraphStyleName() && GetStyleSheet())
+ {
+ wxRichTextParagraphStyleDefinition* def = GetStyleSheet()->FindParagraphStyle(GetDefaultStyle().GetParagraphStyleName());
+ if (def)
+ defaultParaStyle = def->GetStyleMergedWithBase(GetStyleSheet());
+ }
+ else
+ wxRichTextSplitParaCharStyles(GetDefaultStyle(), defaultParaStyle, defaultCharStyle);
wxTextAttr* pStyle = paraStyle ? paraStyle : (wxTextAttr*) & defaultParaStyle;
wxTextAttr* cStyle = & defaultCharStyle;
wxRichTextParagraph* para = GetParagraphAtPosition(position);
if (para)
{
+ wxTextAttrEx originalAttr = para->GetAttributes();
+
wxRichTextObjectList::compatibility_iterator node = m_children.Find(para);
// Now split at this position, returning the object to insert the new
wxRichTextParagraph* firstPara = wxDynamicCast(firstParaNode->GetData(), wxRichTextParagraph);
wxASSERT (firstPara != NULL);
- // Apply the new paragraph attributes to the existing paragraph
- wxTextAttr attr(para->GetAttributes());
- wxRichTextApplyStyle(attr, firstPara->GetAttributes());
- para->SetAttributes(attr);
-
wxRichTextObjectList::compatibility_iterator objectNode = firstPara->GetChildren().GetFirst();
while (objectNode)
{
wxRichTextParagraph* firstPara = wxDynamicCast(firstParaNode->GetData(), wxRichTextParagraph);
wxASSERT(firstPara != NULL);
+ if (!(fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE))
+ para->SetAttributes(firstPara->GetAttributes());
+
+ // Save empty paragraph attributes for appending later
+ // These are character attributes deliberately set for a new paragraph. Without this,
+ // we couldn't pass default attributes when appending a new paragraph.
+ wxTextAttrEx emptyParagraphAttributes;
+
wxRichTextObjectList::compatibility_iterator objectNode = firstPara->GetChildren().GetFirst();
+
+ if (objectNode && firstPara->GetChildren().GetCount() == 1 && objectNode->GetData()->IsEmpty())
+ emptyParagraphAttributes = objectNode->GetData()->GetAttributes();
+
while (objectNode)
{
wxRichTextObject* newObj = objectNode->GetData()->Clone();
wxRichTextObjectList::compatibility_iterator i = fragment.GetChildren().GetFirst()->GetNext();
wxRichTextParagraph* finalPara = para;
+ bool needExtraPara = (!i || !fragment.GetPartialParagraph());
+
// If there was only one paragraph, we need to insert a new one.
- if (!i)
+ while (i)
{
- finalPara = new wxRichTextParagraph;
+ wxRichTextParagraph* para = wxDynamicCast(i->GetData(), wxRichTextParagraph);
+ wxASSERT( para != NULL );
- // TODO: These attributes should come from the subsequent paragraph
- // when originally deleted, since the subsequent para takes on
- // the previous para's attributes.
- finalPara->SetAttributes(firstPara->GetAttributes());
+ finalPara = (wxRichTextParagraph*) para->Clone();
if (nextParagraph)
InsertChild(finalPara, nextParagraph);
else
AppendChild(finalPara);
+
+ i = i->GetNext();
}
- else while (i)
- {
- wxRichTextParagraph* para = wxDynamicCast(i->GetData(), wxRichTextParagraph);
- wxASSERT( para != NULL );
- finalPara = (wxRichTextParagraph*) para->Clone();
+ // If there was only one paragraph, or we have full paragraphs in our fragment,
+ // we need to insert a new one.
+ if (needExtraPara)
+ {
+ finalPara = new wxRichTextParagraph;
if (nextParagraph)
InsertChild(finalPara, nextParagraph);
else
AppendChild(finalPara);
-
- i = i->GetNext();
}
// 4. Add back the remaining content.
if (finalPara)
{
- finalPara->MoveFromList(savedObjects);
+ if (nextObject)
+ finalPara->MoveFromList(savedObjects);
// Ensure there's at least one object
if (finalPara->GetChildCount() == 0)
{
wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
+ text->SetAttributes(emptyParagraphAttributes);
finalPara->AppendChild(text);
}
}
+ if ((fragment.GetAttributes().GetFlags() & wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE) && firstPara)
+ finalPara->SetAttributes(firstPara->GetAttributes());
+ else if (finalPara && finalPara != para)
+ finalPara->SetAttributes(originalAttr);
+
return true;
}
}
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ wxRichTextParagraph* firstPara = NULL;
while (node)
{
wxRichTextParagraph* obj = wxDynamicCast(node->GetData(), wxRichTextParagraph);
// Deletes the content of this object within the given range
obj->DeleteRange(range);
+ wxRichTextRange thisRange = obj->GetRange();
+ wxTextAttrEx thisAttr = obj->GetAttributes();
+
// If the whole paragraph is within the range to delete,
// delete the whole thing.
- if (range.GetStart() <= obj->GetRange().GetStart() && range.GetEnd() >= obj->GetRange().GetEnd())
+ if (range.GetStart() <= thisRange.GetStart() && range.GetEnd() >= thisRange.GetEnd())
{
// Delete the whole object
RemoveChild(obj, true);
+ obj = NULL;
}
+ else if (!firstPara)
+ firstPara = obj;
+
// If the range includes the paragraph end, we need to join this
// and the next paragraph.
- else if (range.Contains(obj->GetRange().GetEnd()))
+ if (range.GetEnd() <= thisRange.GetEnd())
{
// We need to move the objects from the next paragraph
// to this paragraph
- if (next)
+ wxRichTextParagraph* nextParagraph = NULL;
+ if ((range.GetEnd() < thisRange.GetEnd()) && obj)
+ nextParagraph = obj;
+ else
{
- wxRichTextParagraph* nextParagraph = wxDynamicCast(next->GetData(), wxRichTextParagraph);
- next = next->GetNext();
- if (nextParagraph)
- {
- // Delete the stuff we need to delete
- nextParagraph->DeleteRange(range);
+ // We're ending at the end of the paragraph, so merge the _next_ paragraph.
+ if (next)
+ nextParagraph = wxDynamicCast(next->GetData(), wxRichTextParagraph);
+ }
- // Move the objects to the previous para
- wxRichTextObjectList::compatibility_iterator node1 = nextParagraph->GetChildren().GetFirst();
+ bool applyFinalParagraphStyle = firstPara && nextParagraph && nextParagraph != firstPara;
- while (node1)
- {
- wxRichTextObject* obj1 = node1->GetData();
+ wxTextAttrEx nextParaAttr;
+ if (applyFinalParagraphStyle)
+ {
+ // Special case when deleting the end of a paragraph - use _this_ paragraph's style,
+ // not the next one.
+ if (range.GetStart() == range.GetEnd() && range.GetStart() == thisRange.GetEnd())
+ nextParaAttr = thisAttr;
+ else
+ nextParaAttr = nextParagraph->GetAttributes();
+ }
- // If the object is empty, optimise it out
- if (obj1->IsEmpty())
- {
- delete obj1;
- }
- else
- {
- obj->AppendChild(obj1);
- }
+ if (firstPara && nextParagraph && firstPara != nextParagraph)
+ {
+ // Move the objects to the previous para
+ wxRichTextObjectList::compatibility_iterator node1 = nextParagraph->GetChildren().GetFirst();
- wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
- nextParagraph->GetChildren().Erase(node1);
+ while (node1)
+ {
+ wxRichTextObject* obj1 = node1->GetData();
- node1 = next1;
- }
+ firstPara->AppendChild(obj1);
- // Delete the paragraph
- RemoveChild(nextParagraph, true);
+ wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
+ nextParagraph->GetChildren().Erase(node1);
+ node1 = next1;
}
+
+ // Delete the paragraph
+ RemoveChild(nextParagraph, true);
}
+ // Avoid empty paragraphs
+ if (firstPara && firstPara->GetChildren().GetCount() == 0)
+ {
+ wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
+ firstPara->AppendChild(text);
+ }
+
+ if (applyFinalParagraphStyle)
+ firstPara->SetAttributes(nextParaAttr);
+
+ return true;
}
}
splitPoint ++;
// Find last object
- if (splitPoint == newPara->GetRange().GetEnd() || splitPoint == (newPara->GetRange().GetEnd() - 1))
+ if (splitPoint == newPara->GetRange().GetEnd())
lastObject = newPara->GetChildren().GetLast()->GetData();
else
// lastObject is set as a side-effect of splitting. It's
{
Clear();
+ wxRichTextBuffer* buffer = wxDynamicCast(this, wxRichTextBuffer);
+ if (buffer && GetRichTextCtrl())
+ {
+ wxRichTextEvent event(wxEVT_COMMAND_RICHTEXT_BUFFER_RESET, GetRichTextCtrl()->GetId());
+ event.SetEventObject(GetRichTextCtrl());
+
+ buffer->SendEvent(event, true);
+ }
+
AddParagraph(wxEmptyString);
Invalidate(wxRICHTEXT_ALL);
int foundCount = 0;
+ wxRichTextAttr attr(GetBasicStyle());
+ if (GetBasicStyle().HasParagraphStyleName())
+ {
+ wxRichTextParagraphStyleDefinition* paraDef = styleSheet->FindParagraphStyle(GetBasicStyle().GetParagraphStyleName());
+ if (paraDef)
+ {
+ attr.Apply(paraDef->GetStyleMergedWithBase(styleSheet));
+ SetBasicStyle(attr);
+ foundCount ++;
+ }
+ }
+
+ if (GetBasicStyle().HasCharacterStyleName())
+ {
+ wxRichTextCharacterStyleDefinition* charDef = styleSheet->FindCharacterStyle(GetBasicStyle().GetCharacterStyleName());
+ if (charDef)
+ {
+ attr.Apply(charDef->GetStyleMergedWithBase(styleSheet));
+ SetBasicStyle(attr);
+ foundCount ++;
+ }
+ }
+
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight();
linePos = GetPosition();
if (attr.GetLineSpacing() != 10 && GetBuffer())
{
wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineSpacing = (ConvertTenthsMMToPixels(dc, dc.GetCharHeight()) * attr.GetLineSpacing())/10;
}
int lineCount = 0;
+ wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ while (node)
+ {
+ wxRichTextObject* child = node->GetData();
+
+ child->SetCachedSize(wxDefaultSize);
+ child->Layout(dc, rect, style);
+
+ node = node->GetNext();
+ }
+
// Split up lines
// We may need to go back to a previous child, in which case create the new line,
// find the child corresponding to the start position of the string, and
// continue.
- wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+ node = m_children.GetFirst();
while (node)
{
wxRichTextObject* child = node->GetData();
// can't tell the position until the size is determined. So possibly introduce
// another layout phase.
- // TODO: can't this be called only once per child?
- child->Layout(dc, rect, style);
-
// Available width depends on whether we're on the first or subsequent lines
int availableSpaceForText = (lineCount == 0 ? availableTextSpaceFirstLine : availableTextSpaceSubsequentLines);
if (lineHeight == 0 && GetBuffer())
{
wxFont font(GetBuffer()->GetFontTable().FindFont(attr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
lineHeight = dc.GetCharHeight();
}
if (maxDescent == 0)
wxSize lineSize = line->GetSize();
wxRichTextRange lineRange = line->GetAbsoluteRange();
- if (pt.y >= linePos.y && pt.y <= linePos.y + lineSize.y)
+ if (pt.y <= linePos.y + lineSize.y)
{
if (pt.x < linePos.x)
{
{
// Find the first position where the line exceeds the available space.
wxSize sz;
- long i;
long breakPosition = range.GetEnd();
- for (i = range.GetStart(); i <= range.GetEnd(); i++)
+
+ // Binary chop for speed
+ long minPos = range.GetStart();
+ long maxPos = range.GetEnd();
+ while (true)
{
- int descent = 0;
- GetRangeSize(wxRichTextRange(range.GetStart(), i), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ if (minPos == maxPos)
+ {
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
- if (sz.x > availableSpace)
+ if (sz.x > availableSpace)
+ breakPosition = minPos - 1;
+ break;
+ }
+ else if ((maxPos - minPos) == 1)
{
- breakPosition = i-1;
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), minPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+
+ if (sz.x > availableSpace)
+ breakPosition = minPos - 1;
+ else
+ {
+ GetRangeSize(wxRichTextRange(range.GetStart(), maxPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+ if (sz.x > availableSpace)
+ breakPosition = maxPos-1;
+ }
break;
}
+ else
+ {
+ long nextPos = minPos + ((maxPos - minPos) / 2);
+
+ int descent = 0;
+ GetRangeSize(wxRichTextRange(range.GetStart(), nextPos), sz, descent, dc, wxRICHTEXT_UNFORMATTED);
+
+ if (sz.x > availableSpace)
+ {
+ maxPos = nextPos;
+ }
+ else
+ {
+ minPos = nextPos;
+ }
+ }
}
// Now we know the last position on the line.
wxString str = m_text;
wxString toRemove = wxRichTextLineBreakChar;
str.Replace(toRemove, wxT(" "));
+ if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
+ str.MakeUpper();
long len = range.GetLength();
wxString stringChunk = str.Mid(range.GetStart() - offset, (size_t) len);
- if (textAttr.HasTextEffects() && (textAttr.GetTextEffects() & wxTEXT_ATTR_EFFECT_CAPITALS))
- stringChunk.MakeUpper();
int charHeight = dc.GetCharHeight();
// is selected.
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
// (a) All selected.
if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd())
// (c) Part selected, part not
// Let's draw unselected chunk, selected chunk, then unselected chunk.
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
// 1. Initial unselected chunk, if any, up until start of selection.
if (selectionRange.GetStart() > range.GetStart() && selectionRange.GetStart() <= range.GetEnd())
if (selected)
{
- dc.SetBrush(*wxBLACK_BRUSH);
- dc.SetPen(*wxBLACK_PEN);
- dc.SetTextForeground(*wxWHITE);
- dc.SetBackgroundMode(wxTRANSPARENT);
+ wxColour highlightColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHT));
+ wxColour highlightTextColour(wxSystemSettings::GetColour(wxSYS_COLOUR_HIGHLIGHTTEXT));
+
+ wxCheckSetBrush(dc, wxBrush(highlightColour));
+ wxCheckSetPen(dc, wxPen(highlightColour));
+ dc.SetTextForeground(highlightTextColour);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
}
else
{
if (attr.HasFlag(wxTEXT_ATTR_BACKGROUND_COLOUR) && attr.GetBackgroundColour().IsOk())
{
- dc.SetBackgroundMode(wxSOLID);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_SOLID);
dc.SetTextBackground(attr.GetBackgroundColour());
}
else
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
}
while (hasTabs)
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{
wxPen oldPen = dc.GetPen();
- dc.SetPen(wxPen(attr.GetTextColour(), 1));
+ wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
- dc.SetPen(oldPen);
+ wxCheckSetPen(dc, oldPen);
}
x = nextTabPos;
if (attr.HasTextEffects() && (attr.GetTextEffects() & wxTEXT_ATTR_EFFECT_STRIKETHROUGH))
{
wxPen oldPen = dc.GetPen();
- dc.SetPen(wxPen(attr.GetTextColour(), 1));
+ wxCheckSetPen(dc, wxPen(attr.GetTextColour(), 1));
dc.DrawLine(x, (int) (y+(h/2)+0.5), x+w, (int) (y+(h/2)+0.5));
- dc.SetPen(oldPen);
+ wxCheckSetPen(dc, oldPen);
}
x += w;
/// Lay the item out
bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style))
{
- GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0));
+ // Only lay out if we haven't already cached the size
+ if (m_size.x == -1)
+ GetRangeSize(GetRange(), m_size, m_descent, dc, 0, wxPoint(0, 0));
return true;
}
// formatted text by doing it in chunks according to the line ranges
wxFont font(GetBuffer()->GetFontTable().FindFont(textAttr));
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
int startPos = range.GetStart() - GetRange().GetStart();
long len = range.GetLength();
if (textObject)
{
m_text += textObject->GetText();
+ wxRichTextApplyStyle(m_attributes, textObject->GetAttributes());
return true;
}
else
action->GetNewParagraphs() = paragraphs;
- if (p)
- {
- wxRichTextObjectList::compatibility_iterator node = m_children.GetLast();
- while (node)
- {
- wxRichTextParagraph* obj = (wxRichTextParagraph*) node->GetData();
- obj->SetAttributes(*p);
- node = node->GetPrevious();
- }
- }
-
action->SetPosition(pos);
+ wxRichTextRange range = wxRichTextRange(pos, pos + paragraphs.GetRange().GetEnd() - 1);
+ if (!paragraphs.GetPartialParagraph())
+ range.SetEnd(range.GetEnd()+1);
+
// Set the range we'll need to delete in Undo
- action->SetRange(wxRichTextRange(pos, pos + paragraphs.GetRange().GetEnd() - 1));
+ action->SetRange(range);
SubmitAction(action);
action->GetNewParagraphs().AppendChild(newPara);
action->GetNewParagraphs().UpdateRanges();
action->GetNewParagraphs().SetPartialParagraph(false);
- action->SetPosition(pos);
+ wxRichTextParagraph* para = GetParagraphAtPosition(pos, false);
+ long pos1 = pos;
if (p)
newPara->SetAttributes(*p);
+ if (flags & wxRICHTEXT_INSERT_INTERACTIVE)
+ {
+ if (para && para->GetRange().GetEnd() == pos)
+ pos1 ++;
+ if (newPara->GetAttributes().HasBulletNumber())
+ newPara->GetAttributes().SetBulletNumber(newPara->GetAttributes().GetBulletNumber()+1);
+ }
+
+ action->SetPosition(pos);
+
+ // Use the default character style
+ // Use the default character style
+ if (!GetDefaultStyle().IsDefault() && newPara->GetChildren().GetFirst())
+ {
+ // Check whether the default style merely reflects the paragraph/basic style,
+ // in which case don't apply it.
+ wxTextAttrEx defaultStyle(GetDefaultStyle());
+ wxTextAttrEx toApply;
+ if (para)
+ {
+ wxRichTextAttr combinedAttr = para->GetCombinedAttributes();
+ wxTextAttrEx newAttr;
+ // This filters out attributes that are accounted for by the current
+ // paragraph/basic style
+ wxRichTextApplyStyle(toApply, defaultStyle, & combinedAttr);
+ }
+ else
+ toApply = defaultStyle;
+
+ if (!toApply.IsDefault())
+ newPara->GetChildren().GetFirst()->GetData()->SetAttributes(toApply);
+ }
+
// Set the range we'll need to delete in Undo
- action->SetRange(wxRichTextRange(pos, pos));
+ action->SetRange(wxRichTextRange(pos1, pos1));
SubmitAction(action);
wxRichTextParagraphStyleDefinition* paraDef = GetStyleSheet()->FindParagraphStyle(para->GetAttributes().GetParagraphStyleName());
if (paraDef)
{
- if (!paraDef->GetNextStyle().IsEmpty())
+ // If we're not at the end of the paragraph, then we apply THIS style, and not the designated next style.
+ if (para->GetRange().GetEnd() == pos && !paraDef->GetNextStyle().IsEmpty())
{
wxRichTextParagraphStyleDefinition* nextParaDef = GetStyleSheet()->FindParagraphStyle(paraDef->GetNextStyle());
if (nextParaDef)
// Copy the fragment that we'll need to restore in Undo
CopyFragment(range, action->GetOldParagraphs());
- // Special case: if there is only one (non-partial) paragraph,
- // we must save the *next* paragraph's style, because that
- // is the style we must apply when inserting the content back
- // when undoing the delete. (This is because we're merging the
- // paragraph with the previous paragraph and throwing away
- // the style, and we need to restore it.)
- if (!action->GetOldParagraphs().GetPartialParagraph() && action->GetOldParagraphs().GetChildCount() == 1)
+ // See if we're deleting a paragraph marker, in which case we need to
+ // make a note not to copy the attributes from the 2nd paragraph to the 1st.
+ if (range.GetStart() == range.GetEnd())
{
- wxRichTextParagraph* lastPara = GetParagraphAtPosition(range.GetStart());
- if (lastPara)
+ wxRichTextParagraph* para = GetParagraphAtPosition(range.GetStart());
+ if (para && para->GetRange().GetEnd() == range.GetEnd())
{
- wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetEnd()+1);
- if (nextPara)
+ wxRichTextParagraph* nextPara = GetParagraphAtPosition(range.GetStart()+1);
+ if (nextPara && nextPara != para)
{
- wxRichTextParagraph* para = (wxRichTextParagraph*) action->GetOldParagraphs().GetChild(0);
- para->SetAttributes(nextPara->GetAttributes());
+ action->GetOldParagraphs().GetChildren().GetFirst()->GetData()->SetAttributes(nextPara->GetAttributes());
+ action->GetOldParagraphs().GetAttributes().SetFlags(action->GetOldParagraphs().GetAttributes().GetFlags() | wxTEXT_ATTR_KEEP_FIRST_PARA_STYLE);
}
}
}
wxASSERT(m_batchedCommand == NULL);
if (m_batchedCommand)
{
- GetCommandProcessor()->Submit(m_batchedCommand);
+ GetCommandProcessor()->Store(m_batchedCommand);
}
m_batchedCommand = new wxRichTextCommand(cmdName);
}
if (m_batchedCommandDepth == 0)
{
- GetCommandProcessor()->Submit(m_batchedCommand);
+ GetCommandProcessor()->Store(m_batchedCommand);
m_batchedCommand = NULL;
}
bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action)
{
if (BatchingUndo() && m_batchedCommand && !SuppressingUndo())
+ {
+ wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
+ cmd->AddAction(action);
+ cmd->Do();
+ cmd->GetActions().Clear();
+ delete cmd;
+
m_batchedCommand->AddAction(action);
+ }
else
{
wxRichTextCommand* cmd = new wxRichTextCommand(action->GetName());
if (richTextBuffer)
{
InsertParagraphsWithUndo(position+1, *richTextBuffer, GetRichTextCtrl(), wxRICHTEXT_INSERT_WITH_PREVIOUS_PARAGRAPH_STYLE);
+ if (GetRichTextCtrl())
+ GetRichTextCtrl()->ShowPosition(position + richTextBuffer->GetRange().GetEnd());
delete richTextBuffer;
}
}
wxTextDataObject data;
wxTheClipboard->GetData(data);
wxString text(data.GetText());
- text.Replace(_T("\r\n"), _T("\n"));
+#ifdef __WXMSW__
+ wxString text2;
+ text2.Alloc(text.Length()+1);
+ size_t i;
+ for (i = 0; i < text.Length(); i++)
+ {
+ wxChar ch = text[i];
+ if (ch != wxT('\r'))
+ text2 += ch;
+ }
+#else
+ wxString text2 = text;
+#endif
+ InsertTextWithUndo(position+1, text2, GetRichTextCtrl());
- InsertTextWithUndo(position+1, text, GetRichTextCtrl());
+ if (GetRichTextCtrl())
+ GetRichTextCtrl()->ShowPosition(position + text2.Length());
success = true;
}
{
if (bulletAttr.GetTextColour().Ok())
{
- dc.SetPen(wxPen(bulletAttr.GetTextColour()));
- dc.SetBrush(wxBrush(bulletAttr.GetTextColour()));
+ wxCheckSetPen(dc, wxPen(bulletAttr.GetTextColour()));
+ wxCheckSetBrush(dc, wxBrush(bulletAttr.GetTextColour()));
}
else
{
- dc.SetPen(*wxBLACK_PEN);
- dc.SetBrush(*wxBLACK_BRUSH);
+ wxCheckSetPen(dc, *wxBLACK_PEN);
+ wxCheckSetBrush(dc, *wxBLACK_BRUSH);
}
wxFont font;
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
int charHeight = dc.GetCharHeight();
else
font = (*wxNORMAL_FONT);
- dc.SetFont(font);
+ wxCheckSetFont(dc, font);
if (attr.GetTextColour().Ok())
dc.SetTextForeground(attr.GetTextColour());
- dc.SetBackgroundMode(wxTRANSPARENT);
+ dc.SetBackgroundMode(wxBRUSHSTYLE_TRANSPARENT);
int charHeight = dc.GetCharHeight();
wxCoord tw, th;
wxPoint firstVisiblePt = m_ctrl->GetFirstVisiblePoint();
int lastY = firstVisiblePt.y + clientSize.y;
- wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetPosition());
+ wxRichTextParagraph* para = m_buffer->GetParagraphAtPosition(GetRange().GetStart());
wxRichTextObjectList::compatibility_iterator node = m_buffer->GetChildren().Find(para);
while (node)
{
}
#endif
- m_buffer->InsertFragment(GetPosition(), m_newParagraphs);
+ m_buffer->InsertFragment(GetRange().GetStart(), m_newParagraphs);
m_buffer->UpdateRanges();
- m_buffer->Invalidate(GetRange());
+ m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart()-1, GetRange().GetEnd()));
long newCaretPosition = GetPosition() + m_newParagraphs.GetRange().GetLength();
m_buffer->UpdateRanges();
m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
- UpdateAppearance(GetRange().GetStart()-1, true /* send update event */);
+ long caretPos = GetRange().GetStart()-1;
+ if (caretPos >= m_buffer->GetRange().GetEnd())
+ caretPos --;
+
+ UpdateAppearance(caretPos, true /* send update event */);
wxRichTextEvent cmdEvent(
wxEVT_COMMAND_RICHTEXT_CONTENT_DELETED,
if (selectionRange.Contains(range.GetStart()))
{
- dc.SetBrush(*wxBLACK_BRUSH);
- dc.SetPen(*wxBLACK_PEN);
+ wxCheckSetBrush(dc, *wxBLACK_BRUSH);
+ wxCheckSetPen(dc, *wxBLACK_PEN);
dc.SetLogicalFunction(wxINVERT);
dc.DrawRectangle(rect);
dc.SetLogicalFunction(wxCOPY);
* Manages quick access to a pool of fonts for rendering rich text
*/
-WX_DECLARE_EXPORTED_STRING_HASH_MAP(wxFont, wxRichTextFontTableHashMap);
+WX_DECLARE_STRING_HASH_MAP_WITH_DECL(wxFont, wxRichTextFontTableHashMap, class WXDLLIMPEXP_RICHTEXT);
class wxRichTextFontTableData: public wxObjectRefData
{
wxRichTextFontTable::wxRichTextFontTable()
{
m_refData = new wxRichTextFontTableData;
- m_refData->IncRef();
}
wxRichTextFontTable::wxRichTextFontTable(const wxRichTextFontTable& table)