X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/011b3dcbef1f34e476a7a8be04d9525ec47b8062..a4f4d548ce0d3533fe9e84d812643cc7c21dd580:/src/richtext/richtextbuffer.cpp?ds=sidebyside diff --git a/src/richtext/richtextbuffer.cpp b/src/richtext/richtextbuffer.cpp index ab68f2f393..82ae7f3c0d 100644 --- a/src/richtext/richtextbuffer.cpp +++ b/src/richtext/richtextbuffer.cpp @@ -1,10 +1,10 @@ ///////////////////////////////////////////////////////////////////////////// -// 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 ///////////////////////////////////////////////////////////////////////////// @@ -26,6 +26,7 @@ #include "wx/filename.h" #include "wx/clipbrd.h" +#include "wx/dataobj.h" #include "wx/wfstream.h" #include "wx/module.h" #include "wx/mstream.h" @@ -174,9 +175,10 @@ bool wxRichTextCompositeObject::RemoveChild(wxRichTextObject* child, bool delete 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; } @@ -195,7 +197,7 @@ bool wxRichTextCompositeObject::DeleteChildren() child->Dereference(); // Only delete if reference count is zero node = node->GetNext(); - delete oldNode; + m_children.Erase(oldNode); } return true; @@ -293,12 +295,12 @@ void wxRichTextCompositeObject::CalculateRange(long start, long& end) 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 @@ -307,7 +309,7 @@ bool wxRichTextCompositeObject::DeleteRange(const wxRichTextRange& range) // 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); @@ -318,13 +320,13 @@ bool wxRichTextCompositeObject::DeleteRange(const wxRichTextRange& 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; } @@ -340,9 +342,9 @@ wxString wxRichTextCompositeObject::GetTextForRange(const wxRichTextRange& range if (!child->GetRange().IsOutside(range)) { childRange.LimitTo(child->GetRange()); - + wxString childText = child->GetTextForRange(childRange); - + text += childText; } node = node->GetNext(); @@ -359,7 +361,7 @@ bool wxRichTextCompositeObject::Defragment() { wxRichTextObject* child = node->GetData(); wxRichTextCompositeObject* composite = wxDynamicCast(child, wxRichTextCompositeObject); - if (composite) + if (composite) composite->Defragment(); if (node->GetNext()) @@ -368,7 +370,7 @@ bool wxRichTextCompositeObject::Defragment() 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. @@ -480,6 +482,7 @@ void wxRichTextParagraphLayoutBox::Init() // 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; @@ -494,11 +497,11 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range, { wxRichTextParagraph* child = wxDynamicCast(node->GetData(), wxRichTextParagraph); wxASSERT (child != NULL); - + if (child && !child->GetRange().IsOutside(range)) { wxRect childRect(child->GetPosition(), child->GetCachedSize()); - + if (childRect.GetTop() > rect.GetBottom() || childRect.GetBottom() < rect.GetTop()) { // Skip @@ -515,7 +518,31 @@ bool wxRichTextParagraphLayoutBox::Draw(wxDC& dc, const wxRichTextRange& range, /// 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); @@ -523,6 +550,41 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl 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 @@ -530,11 +592,48 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl 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(); } @@ -542,6 +641,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl SetCachedSize(wxSize(maxWidth, availableSpace.y)); m_dirty = false; + m_invalidRange = wxRICHTEXT_NONE; return true; } @@ -557,8 +657,8 @@ bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wx { 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(); @@ -670,15 +770,17 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineAtPosition(long pos, bool c { 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(); } @@ -710,7 +812,7 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineAtYPosition(int y) const return line; node2 = node2->GetNext(); - } + } node = node->GetNext(); } @@ -744,7 +846,7 @@ int wxRichTextParagraphLayoutBox::GetLineCount() const /// 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 @@ -820,7 +922,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text i ++; } - if (!line.IsEmpty()) + if (!line.empty()) { lastPara = new wxRichTextParagraph(line, this, & style); //wxLogDebug("Para Face = %s", lastPara->GetAttributes().GetFont().GetFaceName()); @@ -902,7 +1004,7 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm while (objectNode) { wxRichTextObject* newObj = objectNode->GetData()->Clone(); - + if (!nextObject) { // Append @@ -913,7 +1015,7 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm // Insert before nextObject para->InsertChild(newObj, nextObject); } - + objectNode = objectNode->GetNext(); } @@ -949,10 +1051,10 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm while (objectNode) { wxRichTextObject* newObj = objectNode->GetData()->Clone(); - + // Append para->AppendChild(newObj); - + objectNode = objectNode->GetNext(); } @@ -978,7 +1080,7 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm if (nextParagraph) InsertChild(finalPara, nextParagraph); else - AppendChild(finalPara); + AppendChild(finalPara); } else while (i) { @@ -991,7 +1093,7 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm InsertChild(finalPara, nextParagraph); else AppendChild(finalPara); - + i = i->GetNext(); } @@ -1003,7 +1105,7 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm // 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); @@ -1021,9 +1123,9 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm { wxRichTextParagraph* para = wxDynamicCast(i->GetData(), wxRichTextParagraph); wxASSERT( para != NULL ); - + AppendChild(para->Clone()); - + i = i->GetNext(); } @@ -1046,7 +1148,7 @@ bool wxRichTextParagraphLayoutBox::CopyFragment(const wxRichTextRange& range, wx if (!para->GetRange().IsOutside(range)) { fragment.AppendChild(para->Clone()); - } + } i = i->GetNext(); } @@ -1123,20 +1225,21 @@ long wxRichTextParagraphLayoutBox::GetVisibleLineNumber(long pos, bool caretPosi 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 @@ -1170,14 +1273,14 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineForVisibleLineNumber(long l while (node2) { wxRichTextLine* line = node2->GetData(); - + if (lineCount == lineNumber) return line; lineCount ++; - + node2 = node2->GetNext(); - } + } } else lineCount += child->GetLines().GetCount(); @@ -1193,14 +1296,14 @@ wxRichTextLine* wxRichTextParagraphLayoutBox::GetLineForVisibleLineNumber(long l 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)) @@ -1249,7 +1352,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range) } wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext(); - delete node1; + nextParagraph->GetChildren().Erase(node1); node1 = next1; } @@ -1258,14 +1361,14 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range) RemoveChild(nextParagraph, true); } - } + } } } - + node = next; } - + return true; } @@ -1284,9 +1387,9 @@ wxString wxRichTextParagraphLayoutBox::GetTextForRange(const wxRichTextRange& ra text += wxT("\n"); wxRichTextRange childRange = range; childRange.LimitTo(child->GetRange()); - + wxString childText = child->GetTextForRange(childRange); - + text += childText; lineCount ++; @@ -1378,13 +1481,13 @@ wxRichTextObject* wxRichTextParagraphLayoutBox::GetLeafObjectAtPosition(long pos 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) @@ -1410,7 +1513,7 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const bool haveControl = (GetRichTextCtrl() != NULL); wxRichTextAction* action = NULL; - + if (haveControl && withUndo) { action = new wxRichTextAction(NULL, _("Change Style"), wxRICHTEXT_CHANGE_STYLE, & GetRichTextCtrl()->GetBuffer(), GetRichTextCtrl()); @@ -1434,8 +1537,8 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const { // 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); @@ -1454,24 +1557,24 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const { 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(); @@ -1479,29 +1582,29 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const // 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(); } } @@ -1528,11 +1631,13 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const /// 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(); @@ -1545,11 +1650,13 @@ bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxTextAttrEx& style) /// 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(); @@ -1668,7 +1775,48 @@ void wxRichTextParagraphLayoutBox::Reset() { 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; } /*! @@ -1746,21 +1894,21 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(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; @@ -1772,24 +1920,25 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), 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(); @@ -1803,11 +1952,11 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), 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; @@ -1819,7 +1968,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), 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; @@ -1827,7 +1976,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), } node = node->GetNext(); - } + } return true; } @@ -1835,7 +1984,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), /// 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()); @@ -1943,7 +2092,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) 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); @@ -1951,28 +2100,28 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) 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; @@ -2005,9 +2154,13 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) { 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) @@ -2027,10 +2180,11 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) 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); @@ -2075,7 +2229,7 @@ void wxRichTextParagraph::ApplyParagraphStyle(const wxRect& 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) @@ -2116,7 +2270,7 @@ bool wxRichTextParagraph::InsertText(long pos, const wxString& text) wxRichTextObject* child = node->GetData(); child->SetRange(wxRichTextRange(textObject->GetRange().GetStart() + textLength, textObject->GetRange().GetEnd() + textLength)); - + node = node->GetNext(); } @@ -2173,11 +2327,11 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz 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); @@ -2206,20 +2360,21 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz 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)) @@ -2229,7 +2384,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz } descent = wxMax(descent, childDescent); } - + node2 = node2->GetNext(); } @@ -2296,12 +2451,13 @@ bool wxRichTextParagraph::FindPosition(wxDC& dc, long index, wxPoint& pt, int* h 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()) { @@ -2314,7 +2470,7 @@ bool wxRichTextParagraph::FindPosition(wxDC& dc, long index, wxPoint& pt, int* h pt.y = line->GetPosition().y + GetPosition().y; - wxRichTextRange r(line->GetRange().GetStart(), index); + wxRichTextRange r(lineRange.GetStart(), index); wxSize rangeSize; int descent = 0; @@ -2350,30 +2506,31 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition 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; @@ -2399,7 +2556,7 @@ int wxRichTextParagraph::HitTest(wxDC& dc, const wxPoint& pt, long& textPosition } } } - + node = node->GetNext(); } @@ -2418,7 +2575,12 @@ wxRichTextObject* wxRichTextParagraph::SplitAt(long pos, wxRichTextObject** prev if (pos == child->GetRange().GetStart()) { if (previousObject) - *previousObject = child; + { + if (node->GetPrevious()) + *previousObject = node->GetPrevious()->GetData(); + else + *previousObject = NULL; + } return child; } @@ -2478,7 +2640,7 @@ void wxRichTextParagraph::MoveToList(wxRichTextObject* obj, wxList& list) /// 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()); } @@ -2504,7 +2666,7 @@ wxRichTextObject* wxRichTextParagraph::FindObjectAtPosition(long position) wxRichTextObject* obj = node->GetData(); if (obj->GetRange().Contains(position)) return obj; - + node = node->GetNext(); } return NULL; @@ -2667,6 +2829,40 @@ wxString wxRichTextParagraph::GetBulletText() 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 @@ -2677,15 +2873,16 @@ wxString wxRichTextParagraph::GetBulletText() 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; } @@ -2701,6 +2898,14 @@ wxPoint wxRichTextLine::GetAbsolutePosition() const 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. @@ -2766,7 +2971,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR // 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()) { @@ -2822,7 +3027,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR dc.SetTextForeground(GetAttributes().GetTextColour()); dc.DrawText(stringFragment, x, y); - } + } } return true; @@ -2939,7 +3144,7 @@ wxString wxRichTextPlainText::GetTextForRange(const wxRichTextRange& range) cons 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. @@ -2999,14 +3204,16 @@ void wxRichTextBuffer::Clear() 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 @@ -3022,9 +3229,9 @@ bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRich // Set the range we'll need to delete in Undo action->SetRange(wxRichTextRange(pos, pos + text.Length() - 1)); - + SubmitAction(action); - + return true; } @@ -3035,8 +3242,8 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl) 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); @@ -3044,9 +3251,9 @@ bool wxRichTextBuffer::InsertNewlineWithUndo(long pos, wxRichTextCtrl* ctrl) // Set the range we'll need to delete in Undo action->SetRange(wxRichTextRange(pos, pos)); - + SubmitAction(action); - + return true; } @@ -3057,7 +3264,7 @@ bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock& wxTextAttrEx attr(GetBasicStyle()); wxRichTextApplyStyle(attr, GetDefaultStyle()); - + wxRichTextParagraph* newPara = new wxRichTextParagraph(this, & attr); wxRichTextImage* imageObject = new wxRichTextImage(imageBlock, newPara); newPara->AppendChild(imageObject); @@ -3070,9 +3277,9 @@ bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock& // Set the range we'll need to delete in Undo action->SetRange(wxRichTextRange(pos, pos)); - + SubmitAction(action); - + return true; } @@ -3080,12 +3287,12 @@ bool wxRichTextBuffer::InsertImageWithUndo(long pos, const wxRichTextImageBlock& 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()); @@ -3110,7 +3317,7 @@ bool wxRichTextBuffer::DeleteRangeWithUndo(const wxRichTextRange& range, long in } SubmitAction(action); - + return true; } @@ -3127,7 +3334,7 @@ bool wxRichTextBuffer::BeginBatchUndo(const wxString& cmdName) m_batchedCommand = new wxRichTextCommand(cmdName); } - m_batchedCommandDepth ++; + m_batchedCommandDepth ++; return true; } @@ -3169,7 +3376,7 @@ bool wxRichTextBuffer::SubmitAction(wxRichTextAction* action) /// Begin suppressing undo/redo commands. bool wxRichTextBuffer::BeginSuppressUndo() { - m_suppressUndo ++; + m_suppressUndo ++; return true; } @@ -3177,7 +3384,7 @@ bool wxRichTextBuffer::BeginSuppressUndo() /// End suppressing undo/redo commands. bool wxRichTextBuffer::EndSuppressUndo() { - m_suppressUndo --; + m_suppressUndo --; return true; } @@ -3209,9 +3416,9 @@ bool wxRichTextBuffer::EndStyle() 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); @@ -3230,7 +3437,7 @@ bool wxRichTextBuffer::EndAllStyles() /// 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(); } @@ -3243,7 +3450,7 @@ bool wxRichTextBuffer::BeginBold() wxTextAttrEx attr; attr.SetFont(font,wxTEXT_ATTR_FONT_WEIGHT); - + return BeginStyle(attr); } @@ -3255,7 +3462,7 @@ bool wxRichTextBuffer::BeginItalic() wxTextAttrEx attr; attr.SetFont(font, wxTEXT_ATTR_FONT_ITALIC); - + return BeginStyle(attr); } @@ -3267,7 +3474,7 @@ bool wxRichTextBuffer::BeginUnderline() wxTextAttrEx attr; attr.SetFont(font, wxTEXT_ATTR_FONT_UNDERLINE); - + return BeginStyle(attr); } @@ -3279,7 +3486,7 @@ bool wxRichTextBuffer::BeginFontSize(int pointSize) wxTextAttrEx attr; attr.SetFont(font, wxTEXT_ATTR_FONT_SIZE); - + return BeginStyle(attr); } @@ -3289,7 +3496,7 @@ bool wxRichTextBuffer::BeginFont(const wxFont& font) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_FONT); attr.SetFont(font); - + return BeginStyle(attr); } @@ -3299,7 +3506,7 @@ bool wxRichTextBuffer::BeginTextColour(const wxColour& colour) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_TEXT_COLOUR); attr.SetTextColour(colour); - + return BeginStyle(attr); } @@ -3309,7 +3516,7 @@ bool wxRichTextBuffer::BeginAlignment(wxTextAttrAlignment alignment) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_ALIGNMENT); attr.SetAlignment(alignment); - + return BeginStyle(attr); } @@ -3319,7 +3526,7 @@ bool wxRichTextBuffer::BeginLeftIndent(int leftIndent, int leftSubIndent) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_LEFT_INDENT); attr.SetLeftIndent(leftIndent, leftSubIndent); - + return BeginStyle(attr); } @@ -3329,7 +3536,7 @@ bool wxRichTextBuffer::BeginRightIndent(int rightIndent) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_RIGHT_INDENT); attr.SetRightIndent(rightIndent); - + return BeginStyle(attr); } @@ -3346,7 +3553,7 @@ bool wxRichTextBuffer::BeginParagraphSpacing(int before, int after) attr.SetFlags(flags); attr.SetParagraphSpacingBefore(before); attr.SetParagraphSpacingAfter(after); - + return BeginStyle(attr); } @@ -3356,7 +3563,7 @@ bool wxRichTextBuffer::BeginLineSpacing(int lineSpacing) wxTextAttrEx attr; attr.SetFlags(wxTEXT_ATTR_LINE_SPACING); attr.SetLineSpacing(lineSpacing); - + return BeginStyle(attr); } @@ -3368,7 +3575,7 @@ bool wxRichTextBuffer::BeginNumberedBullet(int bulletNumber, int leftIndent, int attr.SetBulletStyle(bulletStyle); attr.SetBulletNumber(bulletNumber); attr.SetLeftIndent(leftIndent, leftSubIndent); - + return BeginStyle(attr); } @@ -3380,7 +3587,7 @@ bool wxRichTextBuffer::BeginSymbolBullet(wxChar symbol, int leftIndent, int left attr.SetBulletStyle(bulletStyle); attr.SetLeftIndent(leftIndent, leftSubIndent); attr.SetBulletSymbol(symbol); - + return BeginStyle(attr); } @@ -3518,8 +3725,11 @@ void wxRichTextBuffer::CleanUpHandlers() 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(); @@ -3546,6 +3756,8 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save) wildcard += handler->GetExtension(); wildcard += wxT(")|*."); wildcard += handler->GetExtension(); + if (types) + types->Add(handler->GetType()); } count ++; } @@ -3563,7 +3775,13 @@ bool wxRichTextBuffer::LoadFile(const wxString& filename, int type) { 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; } @@ -3583,7 +3801,12 @@ bool wxRichTextBuffer::LoadFile(wxInputStream& stream, int type) { 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; } @@ -3602,12 +3825,16 @@ bool wxRichTextBuffer::SaveFile(wxOutputStream& stream, int type) 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; } @@ -3615,6 +3842,7 @@ bool wxRichTextBuffer::CopyToClipboard(const wxRichTextRange& range) bool wxRichTextBuffer::PasteFromClipboard(long position) { bool success = false; +#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ if (CanPasteFromClipboard()) { if (wxTheClipboard->Open()) @@ -3626,7 +3854,7 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) wxString text(data.GetText()); InsertTextWithUndo(position+1, text, GetRichTextCtrl()); - + success = true; } else if (wxTheClipboard->IsSupported(wxDF_BITMAP)) @@ -3637,17 +3865,17 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) 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; @@ -3655,21 +3883,26 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) 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; } @@ -3709,12 +3942,12 @@ IMPLEMENT_DYNAMIC_CLASS(wxRichTextModule, wxModule) */ 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) { } @@ -3731,7 +3964,7 @@ void wxRichTextCommand::AddAction(wxRichTextAction* action) 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(); @@ -3742,7 +3975,7 @@ bool wxRichTextCommand::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(); @@ -3790,6 +4023,7 @@ bool wxRichTextAction::Do() { 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()) @@ -3803,6 +4037,7 @@ bool wxRichTextAction::Do() { m_buffer->DeleteRange(GetRange()); m_buffer->UpdateRanges(); + m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); UpdateAppearance(GetRange().GetStart()-1, true /* send update event */); @@ -3811,6 +4046,7 @@ bool wxRichTextAction::Do() case wxRICHTEXT_CHANGE_STYLE: { ApplyParagraphs(GetNewParagraphs()); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition()); @@ -3833,6 +4069,7 @@ bool wxRichTextAction::Undo() { m_buffer->DeleteRange(GetRange()); m_buffer->UpdateRanges(); + m_buffer->Invalidate(wxRichTextRange(GetRange().GetStart(), GetRange().GetStart())); long newCaretPosition = GetPosition() - 1; // if (m_newParagraphs.GetPartialParagraph()) @@ -3846,6 +4083,7 @@ bool wxRichTextAction::Undo() { m_buffer->InsertFragment(GetRange().GetStart(), m_oldParagraphs); m_buffer->UpdateRanges(); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition(), true /* send update event */); @@ -3854,6 +4092,7 @@ bool wxRichTextAction::Undo() case wxRICHTEXT_CHANGE_STYLE: { ApplyParagraphs(GetOldParagraphs()); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition()); @@ -3881,7 +4120,7 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent if (sendUpdateEvent) m_ctrl->SendUpdateEvent(); } - } + } } /// Replace the buffer paragraphs with the new ones. @@ -4132,23 +4371,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxTextAttrEx& attr2, i (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; @@ -4214,23 +4453,23 @@ bool wxTextAttrEqPartial(const wxTextAttrEx& attr1, const wxRichTextAttr& attr2, (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; @@ -4340,7 +4579,7 @@ bool wxRichTextApplyStyle(wxRichTextAttr& destStyle, const wxTextAttrEx& style) 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)) @@ -4354,16 +4593,16 @@ bool wxRichTextApplyStyle(wxTextAttrEx& destStyle, const wxRichTextAttr& style) 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()); @@ -4549,6 +4788,9 @@ void wxRichTextAttr::CopyTo(wxTextAttrEx& attr) const 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; } @@ -4623,6 +4865,7 @@ void wxTextAttrEx::operator= (const wxTextAttr& attr) IMPLEMENT_CLASS(wxRichTextFileHandler, wxObject) +#if wxUSE_STREAMS bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer *buffer, const wxString& filename) { wxFFileInputStream stream(filename); @@ -4640,6 +4883,7 @@ bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& f 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 @@ -4658,20 +4902,28 @@ 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 && ch != 10) + str += wxChar(ch); - if (ch > 0) - str += ch; + lastCh = ch; + } } buffer->Clear(); @@ -4682,7 +4934,7 @@ bool wxRichTextPlainTextHandler::LoadFile(wxRichTextBuffer *buffer, wxInputStrea } -bool wxRichTextPlainTextHandler::SaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream) +bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputStream& stream) { if (!stream.IsOk()) return false; @@ -4693,8 +4945,7 @@ bool wxRichTextPlainTextHandler::SaveFile(wxRichTextBuffer *buffer, wxOutputStre stream.Write((const char*) buf, text.Length()); return true; } - -#endif +#endif // wxUSE_STREAMS /* * Stores information about an image, in binary in-memory form @@ -4748,10 +4999,10 @@ bool wxRichTextImageBlock::MakeImageBlock(const wxString& filename, int imageTyp 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) { @@ -4764,13 +5015,13 @@ bool wxRichTextImageBlock::MakeImageBlock(const wxString& filename, int imageTyp 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(); @@ -4793,24 +5044,24 @@ bool wxRichTextImageBlock::MakeImageBlock(wxImage& image, int imageType, int qua 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(); @@ -4859,7 +5110,7 @@ void wxRichTextImageBlock::operator=(const wxRichTextImageBlock& block) bool wxRichTextImageBlock::Load(wxImage& image) { if (!m_data) - return FALSE; + return false; // Read in the image. #if 1 @@ -4872,7 +5123,7 @@ bool wxRichTextImageBlock::Load(wxImage& image) if (!WriteBlock(tempFile, m_data, m_dataSize)) { - return FALSE; + return false; } success = image.LoadFile(tempFile, GetImageType()); wxRemoveFile(tempFile); @@ -4890,7 +5141,7 @@ bool wxRichTextImageBlock::WriteHex(wxOutputStream& stream) { hex = wxDecToHex(m_data[i]); wxCharBuffer buf = hex.ToAscii(); - + stream.Write((const char*) buf, hex.Length()); } @@ -4913,7 +5164,7 @@ bool wxRichTextImageBlock::ReadHex(wxInputStream& stream, int length, int imageT str[0] = stream.GetC(); str[1] = stream.GetC(); - m_data[i] = wxHexToDec(str); + m_data[i] = (unsigned char)wxHexToDec(str); } m_dataSize = dataSize; @@ -4957,11 +5208,10 @@ bool wxRichTextImageBlock::WriteBlock(const wxString& filename, unsigned char* b { wxFileOutputStream outStream(filename); if (!outStream.Ok()) - return FALSE; + return false; return WriteBlock(outStream, block, size); } #endif // wxUSE_RICHTEXT -