/////////////////////////////////////////////////////////////////////////////
-// Name: richtextbuffer.cpp
+// Name: richtext/richtextbuffer.cpp
// Purpose: Buffer for wxRichTextCtrl
// Author: Julian Smart
-// Modified by:
+// Modified by:
// Created: 2005-09-30
-// RCS-ID:
+// RCS-ID: $Id$
// Copyright: (c) Julian Smart
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#pragma hdrstop
#endif
+#if wxUSE_RICHTEXT
+
+#include "wx/richtext/richtextbuffer.h"
+
#ifndef WX_PRECOMP
#include "wx/wx.h"
#endif
-#include "wx/image.h"
-
-#if wxUSE_RICHTEXT
-
#include "wx/filename.h"
#include "wx/clipbrd.h"
+#include "wx/dataobj.h"
#include "wx/wfstream.h"
#include "wx/module.h"
#include "wx/mstream.h"
#include "wx/sstream.h"
-#include "wx/richtext/richtextbuffer.h"
#include "wx/richtext/richtextctrl.h"
#include "wx/richtext/richtextstyles.h"
wxRichTextObjectList::compatibility_iterator node = m_children.Find(child);
if (node)
{
+ wxRichTextObject* obj = node->GetData();
+ m_children.Erase(node);
if (deleteChild)
- delete node->GetData();
- delete node;
+ delete obj;
return true;
}
child->Dereference(); // Only delete if reference count is zero
node = node->GetNext();
- delete oldNode;
+ m_children.Erase(oldNode);
}
return true;
bool wxRichTextCompositeObject::DeleteRange(const wxRichTextRange& range)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
-
+
while (node)
{
wxRichTextObject* obj = (wxRichTextObject*) node->GetData();
wxRichTextObjectList::compatibility_iterator next = node->GetNext();
-
+
// Delete the range in each paragraph
// When a chunk has been deleted, internally the content does not
// If you may delete content from the same object twice, recalculate
// the ranges inbetween DeleteRange calls by calling CalculateRanges, and
// adjust the range you're deleting accordingly.
-
+
if (!obj->GetRange().IsOutside(range))
{
obj->DeleteRange(range);
{
// An empty paragraph has length 1, so won't be deleted unless the
// whole range is deleted.
- RemoveChild(obj, true);
+ RemoveChild(obj, true);
}
}
-
+
node = next;
}
-
+
return true;
}
if (!child->GetRange().IsOutside(range))
{
childRange.LimitTo(child->GetRange());
-
+
wxString childText = child->GetTextForRange(childRange);
-
+
text += childText;
}
node = node->GetNext();
{
wxRichTextObject* child = node->GetData();
wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject);
- if (composite)
+ if (composite)
composite->Defragment();
if (node->GetNext())
if (child->CanMerge(nextChild) && child->Merge(nextChild))
{
nextChild->Dereference();
- delete node->GetNext();
+ m_children.Erase(node->GetNext());
// Don't set node -- we'll see if we can merge again with the next
// child.
// For now, assume is the only box and has no initial size.
m_range = wxRichTextRange(0, -1);
+ m_invalidRange.SetRange(-1, -1);
m_leftMargin = 4;
m_rightMargin = 4;
m_topMargin = 4;
}
/// Draw the item
-bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& WXUNUSED(rect), int descent, int style)
+bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range, const wxRichTextRange& selectionRange, const wxRect& rect, int descent, int style)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
{
wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (child != NULL);
-
+
if (child && !child->GetRange().IsOutside(range))
{
wxRect childRect(child->GetPosition(), child->GetCachedSize());
- child->Draw(dc, child->GetRange(), selectionRange, childRect, descent, style);
+ if (childRect.GetTop() > rect.GetBottom() || childRect.GetBottom() < rect.GetTop())
+ {
+ // Skip
+ }
+ else
+ child->Draw(dc, child->GetRange(), selectionRange, childRect, descent, style);
}
node = node->GetNext();
/// Lay the item out
bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int style)
{
- wxRect availableSpace(rect.x + m_leftMargin,
+ wxRect availableSpace;
+ bool formatRect = (style & wxRICHTEXT_LAYOUT_SPECIFIED_RECT) == wxRICHTEXT_LAYOUT_SPECIFIED_RECT;
+
+ // If only laying out a specific area, the passed rect has a different meaning:
+ // the visible part of the buffer.
+ if (formatRect)
+ {
+ availableSpace = wxRect(0 + m_leftMargin,
+ 0 + m_topMargin,
+ rect.width - m_leftMargin - m_rightMargin,
+ rect.height);
+
+ // Invalidate the part of the buffer from the first visible line
+ // to the end. If other parts of the buffer are currently invalid,
+ // then they too will be taken into account if they are above
+ // the visible point.
+ long startPos = 0;
+ wxRichTextLine* line = GetLineAtYPosition(rect.y);
+ if (line)
+ startPos = line->GetAbsoluteRange().GetStart();
+
+ Invalidate(wxRichTextRange(startPos, GetRange().GetEnd()));
+ }
+ else
+ availableSpace = wxRect(rect.x + m_leftMargin,
rect.y + m_topMargin,
rect.width - m_leftMargin - m_rightMargin,
rect.height - m_topMargin - m_bottomMargin);
int maxWidth = 0;
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
+
+ bool layoutAll = true;
+
+ // Get invalid range, rounding to paragraph start/end.
+ wxRichTextRange invalidRange = GetInvalidRange(true);
+
+ if (invalidRange == wxRICHTEXT_NONE && !formatRect)
+ return true;
+
+ 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())
+ {
+ wxRichTextParagraph* firstParagraph = GetParagraphAtPosition(invalidRange.GetStart());
+ if (firstParagraph)
+ {
+ wxRichTextObjectList::compatibility_iterator firstNode = m_children.Find(firstParagraph);
+ wxRichTextObjectList::compatibility_iterator previousNode = firstNode ? firstNode->GetPrevious() : wxRichTextObjectList::compatibility_iterator();
+ if (firstNode && 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;
+
+ layoutAll = false;
+ }
+ }
+ }
+
+ // A way to force speedy rest-of-buffer layout (the 'else' below)
+ bool forceQuickLayout = false;
+
while (node)
{
// Assume this box only contains paragraphs
wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (child != NULL);
- child->Layout(dc, availableSpace, style);
+ // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines
+ if (child && !forceQuickLayout && (layoutAll || child->GetLines().GetCount() == 0 || !child->GetRange().IsOutside(invalidRange)))
+ {
+ child->Layout(dc, availableSpace, style);
+
+ // Layout must set the cached size
+ availableSpace.y += child->GetCachedSize().y;
+ maxWidth = wxMax(maxWidth, child->GetCachedSize().x);
+
+ // If we're just formatting the visible part of the buffer,
+ // and we're now past the bottom of the window, start quick
+ // layout.
+ if (formatRect && child->GetPosition().y > rect.GetBottom())
+ forceQuickLayout = true;
+ }
+ else
+ {
+ // We're outside the immediately affected range, so now let's just
+ // move everything up or down. This assumes that all the children have previously
+ // been laid out and have wrapped line lists associated with them.
+ // TODO: check all paragraphs before the affected range.
+
+ int inc = availableSpace.y - child->GetPosition().y;
+
+ while (node)
+ {
+ wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph);
+ if (child)
+ {
+ if (child->GetLines().GetCount() == 0)
+ child->Layout(dc, availableSpace, style);
+ else
+ child->SetPosition(wxPoint(child->GetPosition().x, child->GetPosition().y + inc));
+
+ availableSpace.y += child->GetCachedSize().y;
+ maxWidth = wxMax(maxWidth, child->GetCachedSize().x);
+ }
- // Layout must set the cached size
- availableSpace.y += child->GetCachedSize().y;
- maxWidth = wxMax(maxWidth, child->GetCachedSize().x);
+ node = node->GetNext();
+ }
+ break;
+ }
node = node->GetNext();
}
SetCachedSize(wxSize(maxWidth, availableSpace.y));
m_dirty = false;
+ m_invalidRange = wxRICHTEXT_NONE;
return true;
}
{
wxSize sz;
- wxRichTextObjectList::compatibility_iterator startPara = NULL;
- wxRichTextObjectList::compatibility_iterator endPara = NULL;
+ wxRichTextObjectList::compatibility_iterator startPara = wxRichTextObjectList::compatibility_iterator();
+ wxRichTextObjectList::compatibility_iterator endPara = wxRichTextObjectList::compatibility_iterator();
// First find the first paragraph whose starting position is within the range.
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
{
wxRichTextLine* line = node2->GetData();
- if (line->GetRange().Contains(pos) ||
+ wxRichTextRange range = line->GetAbsoluteRange();
+
+ if (range.Contains(pos) ||
// If the position is end-of-paragraph, then return the last line of
// of the paragraph.
- (line->GetRange().GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd()))
+ (range.GetEnd() == child->GetRange().GetEnd()-1) && (pos == child->GetRange().GetEnd()))
return line;
node2 = node2->GetNext();
- }
+ }
node = node->GetNext();
}
return line;
node2 = node2->GetNext();
- }
+ }
node = node->GetNext();
}
/// Get the paragraph for a given line
wxRichTextParagraph* wxRichTextParagraphLayoutBox::GetParagraphForLine(wxRichTextLine* line) const
{
- return GetParagraphAtPosition(line->GetRange().GetStart());
+ return GetParagraphAtPosition(line->GetAbsoluteRange().GetStart());
}
/// Get the line size at the given position
i ++;
}
- if (!line.IsEmpty())
+ if (!line.empty())
{
lastPara = new wxRichTextParagraph(line, this, & style);
//wxLogDebug("Para Face = %s", lastPara->GetAttributes().GetFont().GetFaceName());
while (objectNode)
{
wxRichTextObject* newObj = objectNode->GetData()->Clone();
-
+
if (!nextObject)
{
// Append
// Insert before nextObject
para->InsertChild(newObj, nextObject);
}
-
+
objectNode = objectNode->GetNext();
}
while (objectNode)
{
wxRichTextObject* newObj = objectNode->GetData()->Clone();
-
+
// Append
para->AppendChild(newObj);
-
+
objectNode = objectNode->GetNext();
}
if (nextParagraph)
InsertChild(finalPara, nextParagraph);
else
- AppendChild(finalPara);
+ AppendChild(finalPara);
}
else while (i)
{
InsertChild(finalPara, nextParagraph);
else
AppendChild(finalPara);
-
+
i = i->GetNext();
}
// Ensure there's at least one object
if (finalPara->GetChildCount() == 0)
{
- wxRichTextPlainText* text = new wxRichTextPlainText(wxT(""));
+ wxRichTextPlainText* text = new wxRichTextPlainText(wxEmptyString);
text->SetAttributes(finalPara->GetAttributes());
finalPara->AppendChild(text);
{
wxRichTextParagraph* para = wxDynamicCast(i->GetData(), wxRichTextParagraph);
wxASSERT( para != NULL );
-
+
AppendChild(para->Clone());
-
+
i = i->GetNext();
}
if (!para->GetRange().IsOutside(range))
{
fragment.AppendChild(para->Clone());
- }
+ }
i = i->GetNext();
}
while (node2)
{
wxRichTextLine* line = node2->GetData();
-
- if (line->GetRange().Contains(pos))
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+
+ if (lineRange.Contains(pos))
{
// If the caret is displayed at the end of the previous wrapped line,
// we want to return the line it's _displayed_ at (not the actual line
// containing the position).
- if (line->GetRange().GetStart() == pos && !startOfLine && child->GetRange().GetStart() != pos)
+ if (lineRange.GetStart() == pos && !startOfLine && child->GetRange().GetStart() != pos)
return lineCount - 1;
else
return lineCount;
}
lineCount ++;
-
+
node2 = node2->GetNext();
}
// If we didn't find it in the lines, it must be
while (node2)
{
wxRichTextLine* line = node2->GetData();
-
+
if (lineCount == lineNumber)
return line;
lineCount ++;
-
+
node2 = node2->GetNext();
- }
+ }
}
else
lineCount += child->GetLines().GetCount();
bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range)
{
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
-
+
while (node)
{
wxRichTextParagraph* obj = wxDynamicCast(node->GetData(), wxRichTextParagraph);
wxASSERT (obj != NULL);
wxRichTextObjectList::compatibility_iterator next = node->GetNext();
-
+
// Delete the range in each paragraph
if (!obj->GetRange().IsOutside(range))
}
wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext();
- delete node1;
+ nextParagraph->GetChildren().Erase(node1);
node1 = next1;
}
RemoveChild(nextParagraph, true);
}
- }
+ }
}
}
-
+
node = next;
}
-
+
return true;
}
text += wxT("\n");
wxRichTextRange childRange = range;
childRange.LimitTo(child->GetRange());
-
+
wxString childText = child->GetTextForRange(childRange);
-
+
text += childText;
lineCount ++;
if (para)
{
wxRichTextObjectList::compatibility_iterator node = para->GetChildren().GetFirst();
-
+
while (node)
{
wxRichTextObject* child = node->GetData();
if (child->GetRange().Contains(position))
return child;
-
+
node = node->GetNext();
}
if (position == para->GetRange().GetEnd() && para->GetChildCount() > 0)
bool haveControl = (GetRichTextCtrl() != NULL);
wxRichTextAction* action = NULL;
-
+
if (haveControl && withUndo)
{
action = new wxRichTextAction(NULL, _("Change Style"), wxRICHTEXT_CHANGE_STYLE, & GetRichTextCtrl()->GetBuffer(), GetRichTextCtrl());
{
// We'll be using a copy of the paragraph to make style changes,
// not updating the buffer directly.
- wxRichTextParagraph* newPara = NULL;
-
+ wxRichTextParagraph* newPara wxDUMMY_INITIALIZE(NULL);
+
if (haveControl && withUndo)
{
newPara = new wxRichTextParagraph(*para);
{
wxRichTextRange childRange(range);
childRange.LimitTo(newPara->GetRange());
-
+
// Find the starting position and if necessary split it so
// we can start applying a different style.
// TODO: check that the style actually changes or is different
// from style outside of range
- wxRichTextObject* firstObject = NULL;
- wxRichTextObject* lastObject = NULL;
-
+ wxRichTextObject* firstObject wxDUMMY_INITIALIZE(NULL);
+ wxRichTextObject* lastObject wxDUMMY_INITIALIZE(NULL);
+
if (childRange.GetStart() == newPara->GetRange().GetStart())
firstObject = newPara->GetChildren().GetFirst()->GetData();
else
firstObject = newPara->SplitAt(range.GetStart());
-
+
// Increment by 1 because we're apply the style one _after_ the split point
long splitPoint = childRange.GetEnd();
if (splitPoint != newPara->GetRange().GetEnd())
splitPoint ++;
-
+
// Find last object
if (splitPoint == newPara->GetRange().GetEnd() || splitPoint == (newPara->GetRange().GetEnd() - 1))
lastObject = newPara->GetChildren().GetLast()->GetData();
// lastObject is set as a side-effect of splitting. It's
// returned as the object before the new object.
(void) newPara->SplitAt(splitPoint, & lastObject);
-
+
wxASSERT(firstObject != NULL);
wxASSERT(lastObject != NULL);
-
+
if (!firstObject || !lastObject)
continue;
-
+
wxRichTextObjectList::compatibility_iterator firstNode = newPara->GetChildren().Find(firstObject);
wxRichTextObjectList::compatibility_iterator lastNode = newPara->GetChildren().Find(lastObject);
-
+
wxASSERT(firstNode != NULL);
wxASSERT(lastNode != NULL);
-
+
wxRichTextObjectList::compatibility_iterator node2 = firstNode;
-
+
while (node2)
{
wxRichTextObject* child = node2->GetData();
-
+
wxRichTextApplyStyle(child->GetAttributes(), style);
if (node2 == lastNode)
break;
-
+
node2 = node2->GetNext();
}
}
/// Get the text attributes for this position.
bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style) const
{
- wxRichTextObject* obj = NULL;
+ wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
+
if (style.IsParagraphStyle())
obj = GetParagraphAtPosition(position);
else
obj = GetLeafObjectAtPosition(position);
+
if (obj)
{
style = obj->GetAttributes();
/// Get the text attributes for this position.
bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style) const
{
- wxRichTextObject* obj = NULL;
+ wxRichTextObject* obj wxDUMMY_INITIALIZE(NULL);
+
if (style.IsParagraphStyle())
obj = GetParagraphAtPosition(position);
else
obj = GetLeafObjectAtPosition(position);
+
if (obj)
{
style = obj->GetAttributes();
{
Clear();
- AddParagraph(wxT(""));
+ AddParagraph(wxEmptyString);
+}
+
+/// Invalidate the buffer. With no argument, invalidates whole buffer.
+void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange& invalidRange)
+{
+ SetDirty(true);
+
+ if (invalidRange == wxRICHTEXT_ALL)
+ {
+ m_invalidRange = wxRICHTEXT_ALL;
+ return;
+ }
+
+ // Already invalidating everything
+ if (m_invalidRange == wxRICHTEXT_ALL)
+ return;
+
+ if ((invalidRange.GetStart() < m_invalidRange.GetStart()) || m_invalidRange.GetStart() == -1)
+ m_invalidRange.SetStart(invalidRange.GetStart());
+ if (invalidRange.GetEnd() > m_invalidRange.GetEnd())
+ m_invalidRange.SetEnd(invalidRange.GetEnd());
+}
+
+/// Get invalid range, rounding to entire paragraphs if argument is true.
+wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagraphs) const
+{
+ if (m_invalidRange == wxRICHTEXT_ALL || m_invalidRange == wxRICHTEXT_NONE)
+ return m_invalidRange;
+
+ wxRichTextRange range = m_invalidRange;
+
+ if (wholeParagraphs)
+ {
+ wxRichTextParagraph* para1 = GetParagraphAtPosition(range.GetStart());
+ wxRichTextParagraph* para2 = GetParagraphAtPosition(range.GetEnd());
+ if (para1)
+ range.SetStart(para1->GetRange().GetStart());
+ if (para2)
+ range.SetEnd(para2->GetRange().GetEnd());
+ }
+ return range;
}
/*!
else
{
wxString bulletText = GetBulletText();
- if (!bulletText.IsEmpty())
+ if (!bulletText.empty())
{
if (GetAttributes().GetFont().Ok())
dc.SetFont(GetAttributes().GetFont());
-
+
if (GetAttributes().GetTextColour().Ok())
dc.SetTextForeground(GetAttributes().GetTextColour());
-
+
dc.SetBackgroundMode(wxTRANSPARENT);
-
+
// Get line height from first line, if any
wxRichTextLine* line = m_cachedLines.GetFirst() ? (wxRichTextLine* ) m_cachedLines.GetFirst()->GetData() : (wxRichTextLine*) NULL;
-
+
wxPoint linePos;
- int lineHeight = 0;
+ int lineHeight wxDUMMY_INITIALIZE(0);
if (line)
{
lineHeight = line->GetSize().y;
linePos = GetPosition();
linePos.y += spaceBeforePara;
}
-
+
int charHeight = dc.GetCharHeight();
-
+
int x = GetPosition().x + leftIndent;
int y = linePos.y + (lineHeight - charHeight);
-
+
dc.DrawText(bulletText, x, y);
}
}
}
}
-
+
// 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();
int maxDescent = line->GetDescent();
while (node2)
{
wxRichTextObject* child = node2->GetData();
- if (!child->GetRange().IsOutside(line->GetRange()))
+ if (!child->GetRange().IsOutside(lineRange))
{
// Draw this part of the line at the correct position
wxRichTextRange objectRange(child->GetRange());
- objectRange.LimitTo(line->GetRange());
+ objectRange.LimitTo(lineRange);
wxSize objectSize;
int descent = 0;
objectPosition.x += objectSize.x;
}
- else if (child->GetRange().GetStart() > line->GetRange().GetEnd())
+ else if (child->GetRange().GetStart() > lineRange.GetEnd())
// Can break out of inner loop now since we've passed this line's range
break;
}
node = node->GetNext();
- }
+ }
return true;
}
/// Lay the item out
bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style)
{
- ClearLines();
+ // ClearLines();
// Increase the size of the paragraph due to spacing
int spaceBeforePara = ConvertTenthsMMToPixels(dc, GetAttributes().GetParagraphSpacingBefore());
wrapPosition = wxMax(lastCompletedEndPos+1,child->GetRange().GetEnd());
// wxLogDebug(wxT("Split at %ld"), wrapPosition);
-
+
// Let's find the actual size of the current line now
wxSize actualSize;
wxRichTextRange actualRange(lastCompletedEndPos+1, wrapPosition);
currentWidth = actualSize.x;
lineHeight = wxMax(lineHeight, actualSize.y);
maxDescent = wxMax(childDescent, maxDescent);
-
+
// Add a new line
- wxRichTextLine* line = new wxRichTextLine(this);
- line->SetRange(actualRange);
+ wxRichTextLine* line = AllocateLine(lineCount);
+
+ // Set relative range so we won't have to change line ranges when paragraphs are moved
+ line->SetRange(wxRichTextRange(actualRange.GetStart() - GetRange().GetStart(), actualRange.GetEnd() - GetRange().GetStart()));
line->SetPosition(currentPosition);
line->SetSize(wxSize(currentWidth, lineHeight));
line->SetDescent(maxDescent);
- m_cachedLines.Append(line);
-
// Now move down a line. TODO: add margins, spacing
currentPosition.y += lineHeight;
currentPosition.y += lineSpacing;
currentWidth = 0;
maxDescent = 0;
- maxWidth = wxMax(maxWidth, currentWidth);
-
+ maxWidth = wxMax(maxWidth, currentWidth);
+
lineCount ++;
// TODO: account for zero-length objects, such as fields
wxASSERT(wrapPosition > lastCompletedEndPos);
-
+
lastEndPos = wrapPosition;
lastCompletedEndPos = lastEndPos;
{
currentPosition.x = (lineCount == 0 ? startPositionFirstLine : startPositionSubsequentLines);
- wxRichTextLine* line = new wxRichTextLine(this);
-
- line->SetRange(lastCompletedEndPos+1, GetRange().GetEnd()-1);
+ wxRichTextLine* line = AllocateLine(lineCount);
+
+ wxRichTextRange actualRange(lastCompletedEndPos+1, GetRange().GetEnd()-1);
+
+ // Set relative range so we won't have to change line ranges when paragraphs are moved
+ line->SetRange(wxRichTextRange(actualRange.GetStart() - GetRange().GetStart(), actualRange.GetEnd() - GetRange().GetStart()));
+
line->SetPosition(currentPosition);
if (lineHeight == 0)
currentPosition.y += lineHeight;
currentPosition.y += lineSpacing;
lineCount ++;
-
- m_cachedLines.Append(line);
}
+ // Remove remaining unused line objects, if any
+ ClearUnusedLines(lineCount);
+
// Apply styles to wrapped lines
ApplyParagraphStyle(rect);
bool wxRichTextParagraph::InsertText(long pos, const wxString& text)
{
wxRichTextObject* childToUse = NULL;
- wxRichTextObjectList::compatibility_iterator nodeToUse = NULL;
+ wxRichTextObjectList::compatibility_iterator nodeToUse = wxRichTextObjectList::compatibility_iterator();
wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst();
while (node)
wxRichTextObject* child = node->GetData();
child->SetRange(wxRichTextRange(textObject->GetRange().GetStart() + textLength,
textObject->GetRange().GetEnd() + textLength));
-
+
node = node->GetNext();
}
if (!child->GetRange().IsOutside(range))
{
wxSize childSize;
-
+
wxRichTextRange rangeToUse = range;
rangeToUse.LimitTo(child->GetRange());
int childDescent = 0;
-
+
if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags))
{
sz.y = wxMax(sz.y, childSize.y);
while (node)
{
wxRichTextLine* line = node->GetData();
- if (!line->GetRange().IsOutside(range))
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+ if (!lineRange.IsOutside(range))
{
wxSize lineSize;
-
+
wxRichTextObjectList::compatibility_iterator node2 = m_children.GetFirst();
while (node2)
{
wxRichTextObject* child = node2->GetData();
-
- if (!child->GetRange().IsOutside(line->GetRange()))
+
+ if (!child->GetRange().IsOutside(lineRange))
{
- wxRichTextRange rangeToUse = line->GetRange();
+ wxRichTextRange rangeToUse = lineRange;
rangeToUse.LimitTo(child->GetRange());
-
+
wxSize childSize;
int childDescent = 0;
if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags))
}
descent = wxMax(descent, childDescent);
}
-
+
node2 = node2->GetNext();
}
while (node)
{
wxRichTextLine* line = node->GetData();
- if (index >= line->GetRange().GetStart() && index <= line->GetRange().GetEnd())
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
+ if (index >= lineRange.GetStart() && index <= lineRange.GetEnd())
{
// If this is the last point in the line, and we're forcing the
// returned value to be the start of the next line, do the required
// thing.
- if (index == line->GetRange().GetEnd() && forceLineStart)
+ if (index == lineRange.GetEnd() && forceLineStart)
{
if (node->GetNext())
{
pt.y = line->GetPosition().y + GetPosition().y;
- wxRichTextRange r(line->GetRange().GetStart(), index);
+ wxRichTextRange r(lineRange.GetStart(), index);
wxSize rangeSize;
int descent = 0;
wxRichTextLine* line = node->GetData();
wxPoint linePos = paraPos + line->GetPosition();
wxSize lineSize = line->GetSize();
+ wxRichTextRange lineRange = line->GetAbsoluteRange();
if (pt.y >= linePos.y && pt.y <= linePos.y + lineSize.y)
{
if (pt.x < linePos.x)
{
- textPosition = line->GetRange().GetStart();
+ textPosition = lineRange.GetStart();
return wxRICHTEXT_HITTEST_BEFORE;
}
else if (pt.x >= (linePos.x + lineSize.x))
{
- textPosition = line->GetRange().GetEnd();
+ textPosition = lineRange.GetEnd();
return wxRICHTEXT_HITTEST_AFTER;
}
else
{
long i;
int lastX = linePos.x;
- for (i = line->GetRange().GetStart(); i <= line->GetRange().GetEnd(); i++)
+ for (i = lineRange.GetStart(); i <= lineRange.GetEnd(); i++)
{
wxSize childSize;
int descent = 0;
-
- wxRichTextRange rangeToUse(line->GetRange().GetStart(), i);
-
+
+ wxRichTextRange rangeToUse(lineRange.GetStart(), i);
+
GetRangeSize(rangeToUse, childSize, descent, dc, wxRICHTEXT_UNFORMATTED);
int nextX = childSize.x + linePos.x;
}
}
}
-
+
node = node->GetNext();
}
if (pos == child->GetRange().GetStart())
{
if (previousObject)
- *previousObject = child;
+ {
+ if (node->GetPrevious())
+ *previousObject = node->GetPrevious()->GetData();
+ else
+ *previousObject = NULL;
+ }
return child;
}
/// Add content back from list
void wxRichTextParagraph::MoveFromList(wxList& list)
{
- for (wxNode* node = list.GetFirst(); node; node = node->GetNext())
+ for (wxList::compatibility_iterator node = list.GetFirst(); node; node = node->GetNext())
{
AppendChild((wxRichTextObject*) node->GetData());
}
wxRichTextObject* obj = node->GetData();
if (obj->GetRange().Contains(position))
return obj;
-
+
node = node->GetNext();
}
return NULL;
return text;
}
+/// Allocate or reuse a line object
+wxRichTextLine* wxRichTextParagraph::AllocateLine(int pos)
+{
+ if (pos < (int) m_cachedLines.GetCount())
+ {
+ wxRichTextLine* line = m_cachedLines.Item(pos)->GetData();
+ line->Init(this);
+ return line;
+ }
+ else
+ {
+ wxRichTextLine* line = new wxRichTextLine(this);
+ m_cachedLines.Append(line);
+ return line;
+ }
+}
+
+/// Clear remaining unused line objects, if any
+bool wxRichTextParagraph::ClearUnusedLines(int lineCount)
+{
+ int cachedLineCount = m_cachedLines.GetCount();
+ if ((int) cachedLineCount > lineCount)
+ {
+ for (int i = 0; i < (int) (cachedLineCount - lineCount); i ++)
+ {
+ wxRichTextLineList::compatibility_iterator node = m_cachedLines.GetLast();
+ wxRichTextLine* line = node->GetData();
+ m_cachedLines.Erase(node);
+ delete line;
+ }
+ }
+ return true;
+}
+
/*!
* wxRichTextLine
wxRichTextLine::wxRichTextLine(wxRichTextParagraph* parent)
{
- Init();
-
- m_parent = parent;
+ Init(parent);
}
/// Initialisation
-void wxRichTextLine::Init()
+void wxRichTextLine::Init(wxRichTextParagraph* parent)
{
- m_parent = NULL;
+ m_parent = parent;
+ m_range.SetRange(-1, -1);
+ m_pos = wxPoint(0, 0);
+ m_size = wxSize(0, 0);
m_descent = 0;
}
return m_parent->GetPosition() + m_pos;
}
+/// Get the absolute range
+wxRichTextRange wxRichTextLine::GetAbsoluteRange() const
+{
+ wxRichTextRange range(m_range.GetStart() + m_parent->GetRange().GetStart(), 0);
+ range.SetEnd(range.GetStart() + m_range.GetLength()-1);
+ return range;
+}
+
/*!
* wxRichTextPlainText
* This object represents a single piece of text.
// Let's draw unselected chunk, selected chunk, then unselected chunk.
dc.SetBackgroundMode(wxTRANSPARENT);
-
+
// 1. Initial unselected chunk, if any, up until start of selection.
if (selectionRange.GetStart() > range.GetStart() && selectionRange.GetStart() <= range.GetEnd())
{
dc.SetTextForeground(GetAttributes().GetTextColour());
dc.DrawText(stringFragment, x, y);
- }
+ }
}
return true;
bool wxRichTextPlainText::CanMerge(wxRichTextObject* object) const
{
return object->GetClassInfo() == CLASSINFO(wxRichTextPlainText) &&
- (m_text.IsEmpty() || wxTextAttrEq(GetAttributes(), object->GetAttributes()));
+ (m_text.empty() || wxTextAttrEq(GetAttributes(), object->GetAttributes()));
}
/// Returns true if this object merged itself with the given one.
DeleteChildren();
GetCommandProcessor()->ClearCommands();
Modify(false);
+ Invalidate(wxRICHTEXT_ALL);
}
void wxRichTextBuffer::Reset()
{
DeleteChildren();
- AddParagraph(wxT(""));
+ AddParagraph(wxEmptyString);
GetCommandProcessor()->ClearCommands();
Modify(false);
+ Invalidate(wxRICHTEXT_ALL);
}
/// Submit command to insert the given text
// Set the range we'll need to delete in Undo
action->SetRange(wxRichTextRange(pos, pos + text.Length() - 1));
-
+
SubmitAction(action);
-
+
return true;
}
wxTextAttrEx attr(GetBasicStyle());
wxRichTextApplyStyle(attr, GetDefaultStyle());
-
- wxRichTextParagraph* newPara = new wxRichTextParagraph(wxT(""), this, & attr);
+
+ wxRichTextParagraph* newPara = new wxRichTextParagraph(wxEmptyString, this, & attr);
action->GetNewParagraphs().AppendChild(newPara);
action->GetNewParagraphs().UpdateRanges();
action->GetNewParagraphs().SetPartialParagraph(false);
// Set the range we'll need to delete in Undo
action->SetRange(wxRichTextRange(pos, pos));
-
+
SubmitAction(action);
-
+
return true;
}
wxTextAttrEx attr(GetBasicStyle());
wxRichTextApplyStyle(attr, GetDefaultStyle());
-
+
wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr);
wxRichTextImage* imageObject = new wxRichTextImage(imageBlock, newPara);
newPara->AppendChild(imageObject);
// Set the range we'll need to delete in Undo
action->SetRange(wxRichTextRange(pos, pos));
-
+
SubmitAction(action);
-
+
return true;
}
bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange& range, long initialCaretPosition, long WXUNUSED(newCaretPositon), wxRichTextCtrl* ctrl)
{
wxRichTextAction* action = new wxRichTextAction(NULL, _("Delete"), wxRICHTEXT_DELETE, this, ctrl);
-
+
action->SetPosition(initialCaretPosition);
// Set the range to delete
action->SetRange(range);
-
+
// Copy the fragment that we'll need to restore in Undo
CopyFragment(range, action->GetOldParagraphs());
}
SubmitAction(action);
-
+
return true;
}
m_batchedCommand = new wxRichTextCommand(cmdName);
}
- m_batchedCommandDepth ++;
+ m_batchedCommandDepth ++;
return true;
}
/// Begin suppressing undo/redo commands.
bool wxRichTextBuffer::BeginSuppressUndo()
{
- m_suppressUndo ++;
+ m_suppressUndo ++;
return true;
}
/// End suppressing undo/redo commands.
bool wxRichTextBuffer::EndSuppressUndo()
{
- m_suppressUndo --;
+ m_suppressUndo --;
return true;
}
return false;
}
- wxNode* node = m_attributeStack.GetLast();
+ wxList::compatibility_iterator node = m_attributeStack.GetLast();
wxTextAttrEx* attr = (wxTextAttrEx*)node->GetData();
- delete node;
+ m_attributeStack.Erase(node);
SetDefaultStyle(*attr);
/// Clear the style stack
void wxRichTextBuffer::ClearStyleStack()
{
- for (wxNode* node = m_attributeStack.GetFirst(); node; node = node->GetNext())
+ for (wxList::compatibility_iterator node = m_attributeStack.GetFirst(); node; node = node->GetNext())
delete (wxTextAttrEx*) node->GetData();
m_attributeStack.Clear();
}
wxTextAttrEx attr;
attr.SetFont(font,wxTEXT_ATTR_FONT_WEIGHT);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFont(font, wxTEXT_ATTR_FONT_ITALIC);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFont(font, wxTEXT_ATTR_FONT_UNDERLINE);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFont(font, wxTEXT_ATTR_FONT_SIZE);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_FONT);
attr.SetFont(font);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_TEXT_COLOUR);
attr.SetTextColour(colour);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_ALIGNMENT);
attr.SetAlignment(alignment);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT);
attr.SetLeftIndent(leftIndent, leftSubIndent);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_RIGHT_INDENT);
attr.SetRightIndent(rightIndent);
-
+
return BeginStyle(attr);
}
attr.SetFlags(flags);
attr.SetParagraphSpacingBefore(before);
attr.SetParagraphSpacingAfter(after);
-
+
return BeginStyle(attr);
}
wxTextAttrEx attr;
attr.SetFlags(wxTEXT_ATTR_LINE_SPACING);
attr.SetLineSpacing(lineSpacing);
-
+
return BeginStyle(attr);
}
attr.SetBulletStyle(bulletStyle);
attr.SetBulletNumber(bulletNumber);
attr.SetLeftIndent(leftIndent, leftSubIndent);
-
+
return BeginStyle(attr);
}
attr.SetBulletStyle(bulletStyle);
attr.SetLeftIndent(leftIndent, leftSubIndent);
attr.SetBulletSymbol(symbol);
-
+
return BeginStyle(attr);
}
sm_handlers.Clear();
}
-wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save)
+wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save, wxArrayInt* types)
{
+ if (types)
+ types->Clear();
+
wxString wildcard;
wxList::compatibility_iterator node = GetHandlers().GetFirst();
wildcard += handler->GetExtension();
wildcard += wxT(")|*.");
wildcard += handler->GetExtension();
+ if (types)
+ types->Add(handler->GetType());
}
count ++;
}
{
wxRichTextFileHandler* handler = FindHandlerFilenameOrType(filename, type);
if (handler)
- return handler->LoadFile(this, filename);
+ {
+ SetDefaultStyle(wxTextAttrEx());
+
+ bool success = handler->LoadFile(this, filename);
+ Invalidate(wxRICHTEXT_ALL);
+ return success;
+ }
else
return false;
}
{
wxRichTextFileHandler* handler = FindHandler(type);
if (handler)
- return handler->LoadFile(this, stream);
+ {
+ SetDefaultStyle(wxTextAttrEx());
+ bool success = handler->LoadFile(this, stream);
+ Invalidate(wxRICHTEXT_ALL);
+ return success;
+ }
else
return false;
}
bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range)
{
bool success = false;
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
wxString text = GetTextForRange(range);
- if (wxTheClipboard->Open())
- {
+ if (!wxTheClipboard->IsOpened() && wxTheClipboard->Open())
+ {
success = wxTheClipboard->SetData(new wxTextDataObject(text));
wxTheClipboard->Close();
}
+#else
+ wxUnusedVar(range);
+#endif
return success;
}
bool wxRichTextBuffer::PasteFromClipboard(long position)
{
bool success = false;
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
if (CanPasteFromClipboard())
{
if (wxTheClipboard->Open())
wxString text(data.GetText());
InsertTextWithUndo(position+1, text, GetRichTextCtrl());
-
+
success = true;
}
else if (wxTheClipboard->IsSupported(wxDF_BITMAP))
wxImage image(bitmap.ConvertToImage());
wxRichTextAction* action = new wxRichTextAction(NULL, _("Insert Image"), wxRICHTEXT_INSERT, this, GetRichTextCtrl(), false);
-
+
action->GetNewParagraphs().AddImage(image);
if (action->GetNewParagraphs().GetChildCount() == 1)
action->GetNewParagraphs().SetPartialParagraph(true);
-
+
action->SetPosition(position);
-
+
// Set the range we'll need to delete in Undo
action->SetRange(wxRichTextRange(position, position));
-
+
SubmitAction(action);
success = true;
wxTheClipboard->Close();
}
}
+#else
+ wxUnusedVar(position);
+#endif
return success;
}
/// Can we paste from the clipboard?
bool wxRichTextBuffer::CanPasteFromClipboard() const
{
- bool canPaste = FALSE;
- if (wxTheClipboard->Open())
+ bool canPaste = false;
+#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ
+ if (!wxTheClipboard->IsOpened() && wxTheClipboard->Open())
{
if (wxTheClipboard->IsSupported(wxDF_TEXT) || wxTheClipboard->IsSupported(wxDF_BITMAP))
{
- canPaste = TRUE;
+ canPaste = true;
}
wxTheClipboard->Close();
}
+#endif
return canPaste;
}
*/
wxRichTextCommand::wxRichTextCommand(const wxString& name, wxRichTextCommandId id, wxRichTextBuffer* buffer,
- wxRichTextCtrl* ctrl, bool ignoreFirstTime): wxCommand(TRUE, name)
+ wxRichTextCtrl* ctrl, bool ignoreFirstTime): wxCommand(true, name)
{
/* wxRichTextAction* action = */ new wxRichTextAction(this, name, id, buffer, ctrl, ignoreFirstTime);
}
-wxRichTextCommand::wxRichTextCommand(const wxString& name): wxCommand(TRUE, name)
+wxRichTextCommand::wxRichTextCommand(const wxString& name): wxCommand(true, name)
{
}
bool wxRichTextCommand::Do()
{
- for (wxNode* node = m_actions.GetFirst(); node; node = node->GetNext())
+ for (wxList::compatibility_iterator node = m_actions.GetFirst(); node; node = node->GetNext())
{
wxRichTextAction* action = (wxRichTextAction*) node->GetData();
action->Do();
bool wxRichTextCommand::Undo()
{
- for (wxNode* node = m_actions.GetLast(); node; node = node->GetPrevious())
+ for (wxList::compatibility_iterator node = m_actions.GetLast(); node; node = node->GetPrevious())
{
wxRichTextAction* action = (wxRichTextAction*) node->GetData();
action->Undo();
{
m_buffer->InsertFragment(GetPosition(), m_newParagraphs);
m_buffer->UpdateRanges();
+ m_buffer->Invalidate(GetRange());
long newCaretPosition = GetPosition() + m_newParagraphs.GetRange().GetLength() - 1;
if (m_newParagraphs.GetPartialParagraph())
{
m_buffer->DeleteRange(GetRange());
m_buffer->UpdateRanges();
+ m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
UpdateAppearance(GetRange().GetStart()-1, true /* send update event */);
case wxRICHTEXT_CHANGE_STYLE:
{
ApplyParagraphs(GetNewParagraphs());
+ m_buffer->Invalidate(GetRange());
UpdateAppearance(GetPosition());
{
m_buffer->DeleteRange(GetRange());
m_buffer->UpdateRanges();
+ m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart()));
long newCaretPosition = GetPosition() - 1;
// if (m_newParagraphs.GetPartialParagraph())
{
m_buffer->InsertFragment(GetRange().GetStart(), m_oldParagraphs);
m_buffer->UpdateRanges();
+ m_buffer->Invalidate(GetRange());
UpdateAppearance(GetPosition(), true /* send update event */);
case wxRICHTEXT_CHANGE_STYLE:
{
ApplyParagraphs(GetOldParagraphs());
+ m_buffer->Invalidate(GetRange());
UpdateAppearance(GetPosition());
m_ctrl->SetCaretPosition(caretPosition);
if (!m_ctrl->IsFrozen())
{
- m_ctrl->Layout();
+ m_ctrl->LayoutContent();
m_ctrl->PositionCaret();
- m_ctrl->Refresh();
+ m_ctrl->Refresh(false);
if (sendUpdateEvent)
m_ctrl->SendUpdateEvent();
}
- }
+ }
}
/// Replace the buffer paragraphs with the new ones.
(attr1.GetRightIndent() != attr2.GetRightIndent()))
return false;
- if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) &&
+ if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
(attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
return false;
- if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
+ if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
(attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
return false;
- if ((flags && wxTEXT_ATTR_LINE_SPACING) &&
+ if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
(attr1.GetLineSpacing() != attr2.GetLineSpacing()))
return false;
- if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
+ if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
(attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
return false;
- if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
+ if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
(attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
return false;
(attr1.GetRightIndent() != attr2.GetRightIndent()))
return false;
- if ((flags && wxTEXT_ATTR_PARA_SPACING_AFTER) &&
+ if ((flags & wxTEXT_ATTR_PARA_SPACING_AFTER) &&
(attr1.GetParagraphSpacingAfter() != attr2.GetParagraphSpacingAfter()))
return false;
- if ((flags && wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
+ if ((flags & wxTEXT_ATTR_PARA_SPACING_BEFORE) &&
(attr1.GetParagraphSpacingBefore() != attr2.GetParagraphSpacingBefore()))
return false;
- if ((flags && wxTEXT_ATTR_LINE_SPACING) &&
+ if ((flags & wxTEXT_ATTR_LINE_SPACING) &&
(attr1.GetLineSpacing() != attr2.GetLineSpacing()))
return false;
- if ((flags && wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
+ if ((flags & wxTEXT_ATTR_CHARACTER_STYLE_NAME) &&
(attr1.GetCharacterStyleName() != attr2.GetCharacterStyleName()))
return false;
- if ((flags && wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
+ if ((flags & wxTEXT_ATTR_PARAGRAPH_STYLE_NAME) &&
(attr1.GetParagraphStyleName() != attr2.GetParagraphStyleName()))
return false;
bool wxRichTextApplyStyle(wxTextAttrEx& destStyle, const wxRichTextAttr& style)
{
-
+
// Whole font. Avoiding setting individual attributes if possible, since
// it recreates the font each time.
if ((style.GetFlags() & (wxTEXT_ATTR_FONT)) == (wxTEXT_ATTR_FONT))
if (style.GetFlags() & wxTEXT_ATTR_FONT_FACE)
font.SetFaceName(style.GetFontFaceName());
-
+
if (style.GetFlags() & wxTEXT_ATTR_FONT_SIZE)
font.SetPointSize(style.GetFontSize());
-
+
if (style.GetFlags() & wxTEXT_ATTR_FONT_ITALIC)
font.SetStyle(style.GetFontStyle());
-
+
if (style.GetFlags() & wxTEXT_ATTR_FONT_WEIGHT)
font.SetWeight(style.GetFontWeight());
-
+
if (style.GetFlags() & wxTEXT_ATTR_FONT_UNDERLINE)
font.SetUnderlined(style.GetFontUnderlined());
wxFont wxRichTextAttr::CreateFont() const
{
wxFont font(m_fontSize, wxDEFAULT, m_fontStyle, m_fontWeight, m_fontUnderlined, m_fontFaceName);
+#ifdef __WXMAC__
+ font.SetNoAntiAliasing(true);
+#endif
return font;
}
IMPLEMENT_CLASS(wxRichTextFileHandler, wxObject)
+#if wxUSE_STREAMS
bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer *buffer, const wxString& filename)
{
wxFFileInputStream stream(filename);
else
return false;
}
+#endif // wxUSE_STREAMS
/// Can we handle this filename (if using files)? By default, checks the extension.
bool wxRichTextFileHandler::CanHandle(const wxString& filename) const
IMPLEMENT_CLASS(wxRichTextPlainTextHandler, wxRichTextFileHandler)
#if wxUSE_STREAMS
-bool wxRichTextPlainTextHandler::LoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
+bool wxRichTextPlainTextHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStream& stream)
{
if (!stream.IsOk())
return false;
wxString str;
- int ch = 0;
+ int lastCh = 0;
while (!stream.Eof())
{
- ch = stream.GetC();
+ int ch = stream.GetC();
+
+ if (!stream.Eof())
+ {
+ if (ch == 10 && lastCh != 13)
+ str += wxT('\n');
- if (ch > 0)
- str += ch;
+ if (ch > 0 && ch != 10)
+ str += wxChar(ch);
+
+ lastCh = ch;
+ }
}
buffer->Clear();
}
-bool wxRichTextPlainTextHandler::SaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
+bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream)
{
if (!stream.IsOk())
return false;
stream.Write((const char*) buf, text.Length());
return true;
}
-
-#endif
+#endif // wxUSE_STREAMS
/*
* Stores information about an image, in binary in-memory form
void wxRichTextImageBlock::Clear()
{
- if (m_data)
- delete m_data;
+ delete[] m_data;
m_data = NULL;
m_dataSize = 0;
m_imageType = -1;
m_imageType = imageType;
wxString filenameToRead(filename);
- bool removeFile = FALSE;
+ bool removeFile = false;
if (imageType == -1)
- return FALSE; // Could not determine image type
+ return false; // Could not determine image type
if ((imageType != wxBITMAP_TYPE_JPEG) && convertToJPEG)
{
image.SaveFile(tempFile, wxBITMAP_TYPE_JPEG);
filenameToRead = tempFile;
- removeFile = TRUE;
+ removeFile = true;
m_imageType = wxBITMAP_TYPE_JPEG;
}
wxFile file;
if (!file.Open(filenameToRead))
- return FALSE;
+ return false;
m_dataSize = (size_t) file.Length();
file.Close();
image.SetOption(wxT("quality"), quality);
if (imageType == -1)
- return FALSE; // Could not determine image type
+ return false; // Could not determine image type
wxString tempFile;
bool success = wxGetTempFileName(_("image"), tempFile) ;
-
+
wxASSERT(success);
wxUnusedVar(success);
-
+
if (!image.SaveFile(tempFile, m_imageType))
{
if (wxFileExists(tempFile))
wxRemoveFile(tempFile);
- return FALSE;
+ return false;
}
wxFile file;
if (!file.Open(tempFile))
- return FALSE;
+ return false;
m_dataSize = (size_t) file.Length();
file.Close();
bool wxRichTextImageBlock::Load(wxImage& image)
{
if (!m_data)
- return FALSE;
+ return false;
// Read in the image.
#if 1
if (!WriteBlock(tempFile, m_data, m_dataSize))
{
- return FALSE;
+ return false;
}
success = image.LoadFile(tempFile, GetImageType());
wxRemoveFile(tempFile);
{
hex = wxDecToHex(m_data[i]);
wxCharBuffer buf = hex.ToAscii();
-
+
stream.Write((const char*) buf, hex.Length());
}
str[0] = stream.GetC();
str[1] = stream.GetC();
- m_data[i] = wxHexToDec(str);
+ m_data[i] = (unsigned char)wxHexToDec(str);
}
m_dataSize = dataSize;
{
wxFileOutputStream outStream(filename);
if (!outStream.Ok())
- return FALSE;
+ return false;
return WriteBlock(outStream, block, size);
}
#endif
// wxUSE_RICHTEXT
-