X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/38113684016c5ecbc65985bee3c6c7b318c012cf..cdbce971ecd2a3f39ddcc56c0ef7769663fbdf23:/src/richtext/richtextbuffer.cpp diff --git a/src/richtext/richtextbuffer.cpp b/src/richtext/richtextbuffer.cpp index aa12d8a7b4..ee680385d7 100644 --- a/src/richtext/richtextbuffer.cpp +++ b/src/richtext/richtextbuffer.cpp @@ -1,5 +1,5 @@ ///////////////////////////////////////////////////////////////////////////// -// Name: richtext/richtextbuffer.cpp +// Name: src/richtext/richtextbuffer.cpp // Purpose: Buffer for wxRichTextCtrl // Author: Julian Smart // Modified by: @@ -13,16 +13,19 @@ #include "wx/wxprec.h" #ifdef __BORLANDC__ - #pragma hdrstop + #pragma hdrstop #endif -#ifndef WX_PRECOMP - #include "wx/wx.h" -#endif +#if wxUSE_RICHTEXT -#include "wx/image.h" +#include "wx/richtext/richtextbuffer.h" -#if wxUSE_RICHTEXT +#ifndef WX_PRECOMP + #include "wx/dc.h" + #include "wx/intl.h" + #include "wx/log.h" + #include "wx/dataobj.h" +#endif #include "wx/filename.h" #include "wx/clipbrd.h" @@ -31,14 +34,13 @@ #include "wx/mstream.h" #include "wx/sstream.h" -#include "wx/richtext/richtextbuffer.h" #include "wx/richtext/richtextctrl.h" #include "wx/richtext/richtextstyles.h" #include "wx/listimpl.cpp" -WX_DEFINE_LIST(wxRichTextObjectList); -WX_DEFINE_LIST(wxRichTextLineList); +WX_DEFINE_LIST(wxRichTextObjectList) +WX_DEFINE_LIST(wxRichTextLineList) /*! * wxRichTextObject @@ -174,9 +176,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 +198,7 @@ bool wxRichTextCompositeObject::DeleteChildren() child->Dereference(); // Only delete if reference count is zero node = node->GetNext(); - delete oldNode; + m_children.Erase(oldNode); } return true; @@ -368,7 +371,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. @@ -440,13 +443,13 @@ bool wxRichTextBox::Layout(wxDC& dc, const wxRect& rect, int style) } /// Get/set the size for the given range. Assume only has one child. -bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const +bool wxRichTextBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const { wxRichTextObjectList::compatibility_iterator node = m_children.GetFirst(); if (node) { wxRichTextObject* child = node->GetData(); - return child->GetRangeSize(range, size, descent, dc, flags); + return child->GetRangeSize(range, size, descent, dc, flags, position); } else return false; @@ -516,7 +519,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); @@ -524,14 +551,17 @@ 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 == wxRichTextRange(-1, -1)) - layoutAll = 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()) { @@ -539,7 +569,9 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl if (firstParagraph) { wxRichTextObjectList::compatibility_iterator firstNode = m_children.Find(firstParagraph); - wxRichTextObjectList::compatibility_iterator previousNode = firstNode ? node->GetPrevious() : (wxRichTextObjectList::compatibility_iterator) NULL; + wxRichTextObjectList::compatibility_iterator previousNode; + if ( firstNode ) + previousNode = firstNode->GetPrevious(); if (firstNode && previousNode) { wxRichTextParagraph* previousParagraph = wxDynamicCast(previousNode->GetData(), wxRichTextParagraph); @@ -547,24 +579,39 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl // 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); + wxCHECK_MSG( child, false, _T("Unknown object in layout") ); - if (child && (layoutAll || !child->GetRange().IsOutside(invalidRange))) + // TODO: what if the child hasn't been laid out (e.g. involved in Undo) but still has 'old' lines + if ( !forceQuickLayout && + (layoutAll || + child->GetLines().IsEmpty() || + !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 { @@ -600,7 +647,7 @@ bool wxRichTextParagraphLayoutBox::Layout(wxDC& dc, const wxRect& rect, int styl SetCachedSize(wxSize(maxWidth, availableSpace.y)); m_dirty = false; - m_invalidRange = wxRichTextRange(-1, -1); + m_invalidRange = wxRICHTEXT_NONE; return true; } @@ -612,12 +659,12 @@ void wxRichTextParagraphLayoutBox::Copy(const wxRichTextParagraphLayoutBox& obj) } /// Get/set the size for the given range. -bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const +bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const { 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(); @@ -668,7 +715,7 @@ bool wxRichTextParagraphLayoutBox::GetRangeSize(const wxRichTextRange& range, wx wxSize childSize; int childDescent = 0; - child->GetRangeSize(rangeToFind, childSize, childDescent, dc, flags); + child->GetRangeSize(rangeToFind, childSize, childDescent, dc, flags, position); descent = wxMax(childDescent, descent); @@ -729,11 +776,13 @@ 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(); @@ -803,7 +852,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 @@ -859,7 +908,7 @@ wxRichTextRange wxRichTextParagraphLayoutBox::AddParagraphs(const wxString& text wxRichTextRange range(-1, -1); size_t i = 0; - size_t len = text.Length(); + size_t len = text.length(); wxString line; while (i < len) { @@ -1088,8 +1137,6 @@ bool wxRichTextParagraphLayoutBox::InsertFragment(long position, wxRichTextFragm return true; } - - return false; } /// Make a copy of the fragment corresponding to the given range, putting it in 'fragment'. @@ -1182,13 +1229,14 @@ long wxRichTextParagraphLayoutBox::GetVisibleLineNumber(long pos, bool caretPosi while (node2) { wxRichTextLine* line = node2->GetData(); + wxRichTextRange lineRange = line->GetAbsoluteRange(); - if (line->GetRange().Contains(pos)) + 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; @@ -1308,7 +1356,7 @@ bool wxRichTextParagraphLayoutBox::DeleteRange(const wxRichTextRange& range) } wxRichTextObjectList::compatibility_iterator next1 = node1->GetNext(); - delete node1; + nextParagraph->GetChildren().Erase(node1); node1 = next1; } @@ -1365,7 +1413,7 @@ wxString wxRichTextParagraphLayoutBox::GetText() const /// Get the paragraph by number wxRichTextParagraph* wxRichTextParagraphLayoutBox::GetParagraphAtLine(long paragraphNumber) const { - if ((size_t) paragraphNumber <= GetChildCount()) + if ((size_t) paragraphNumber >= GetChildCount()) return NULL; return (wxRichTextParagraph*) GetChild((size_t) paragraphNumber); @@ -1493,7 +1541,7 @@ 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) { @@ -1518,8 +1566,8 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const // 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(); @@ -1548,8 +1596,8 @@ bool wxRichTextParagraphLayoutBox::SetStyle(const wxRichTextRange& range, const wxRichTextObjectList::compatibility_iterator firstNode = newPara->GetChildren().Find(firstObject); wxRichTextObjectList::compatibility_iterator lastNode = newPara->GetChildren().Find(lastObject); - wxASSERT(firstNode != NULL); - wxASSERT(lastNode != NULL); + wxASSERT(firstNode); + wxASSERT(lastNode); wxRichTextObjectList::compatibility_iterator node2 = firstNode; @@ -1587,11 +1635,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(); @@ -1604,11 +1654,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(); @@ -1621,7 +1673,13 @@ bool wxRichTextParagraphLayoutBox::GetStyle(long position, wxRichTextAttr& style /// Set default style bool wxRichTextParagraphLayoutBox::SetDefaultStyle(const wxTextAttrEx& style) { - m_defaultAttributes = style; + // keep the old attributes if the new style doesn't specify them unless the + // new style is empty - then reset m_defaultStyle (as there is no other way + // to do it) + if ( style.IsDefault() ) + m_defaultAttributes = style; + else + m_defaultAttributes = wxTextAttrEx::CombineEx(style, m_defaultAttributes, NULL); return true; } @@ -1734,14 +1792,18 @@ void wxRichTextParagraphLayoutBox::Reset() void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange& invalidRange) { SetDirty(true); - - if (invalidRange == wxRichTextRange(-1, -1)) + + if (invalidRange == wxRICHTEXT_ALL) { - m_invalidRange = invalidRange; + m_invalidRange = wxRICHTEXT_ALL; return; } - - if (invalidRange.GetStart() < m_invalidRange.GetStart()) + + // 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()); @@ -1750,11 +1812,11 @@ void wxRichTextParagraphLayoutBox::Invalidate(const wxRichTextRange& invalidRang /// Get invalid range, rounding to entire paragraphs if argument is true. wxRichTextRange wxRichTextParagraphLayoutBox::GetInvalidRange(bool wholeParagraphs) const { - if (m_invalidRange == wxRichTextRange(-1, -1)) + if (m_invalidRange == wxRICHTEXT_ALL || m_invalidRange == wxRICHTEXT_NONE) return m_invalidRange; - + wxRichTextRange range = m_invalidRange; - + if (wholeParagraphs) { wxRichTextParagraph* para1 = GetParagraphAtPosition(range.GetStart()); @@ -1856,7 +1918,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), 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; @@ -1886,6 +1948,7 @@ bool wxRichTextParagraph::Draw(wxDC& dc, const wxRichTextRange& WXUNUSED(range), while (node) { wxRichTextLine* line = node->GetData(); + wxRichTextRange lineRange = line->GetAbsoluteRange(); int maxDescent = line->GetDescent(); @@ -1899,15 +1962,15 @@ 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; - child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED); + child->GetRangeSize(objectRange, objectSize, descent, dc, wxRICHTEXT_UNFORMATTED, objectPosition); // Use the child object's width, but the whole line's height wxRect childRect(objectPosition, wxSize(objectSize.x, line->GetSize().y)); @@ -1915,7 +1978,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; @@ -1931,7 +1994,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()); @@ -2020,7 +2083,7 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) childDescent = child->GetDescent(); } else - GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED); + GetRangeSize(wxRichTextRange(lastEndPos+1, child->GetRange().GetEnd()), childSize, childDescent, dc, wxRICHTEXT_UNFORMATTED,rect.GetPosition()); if (childSize.x + currentWidth > availableSpaceForText) { @@ -2049,14 +2112,14 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) 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; @@ -2101,9 +2164,13 @@ bool wxRichTextParagraph::Layout(wxDC& dc, const wxRect& rect, int style) { currentPosition.x = (lineCount == 0 ? startPositionFirstLine : startPositionSubsequentLines); - wxRichTextLine* line = new wxRichTextLine(this); + 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->SetRange(lastCompletedEndPos+1, GetRange().GetEnd()-1); line->SetPosition(currentPosition); if (lineHeight == 0) @@ -2123,10 +2190,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); @@ -2171,7 +2239,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) @@ -2198,7 +2266,7 @@ bool wxRichTextParagraph::InsertText(long pos, const wxString& text) text + textObject->GetText().Mid(posInString); textObject->SetText(newText); - int textLength = text.Length(); + int textLength = text.length(); textObject->SetRange(wxRichTextRange(textObject->GetRange().GetStart(), textObject->GetRange().GetEnd() + textLength)); @@ -2250,7 +2318,7 @@ void wxRichTextParagraph::ClearLines() /// Get/set the object size for the given range. Returns false if the range /// is invalid for this object. -bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags) const +bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int flags, wxPoint position) const { if (!range.IsWithin(GetRange())) return false; @@ -2274,7 +2342,7 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz rangeToUse.LimitTo(child->GetRange()); int childDescent = 0; - if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags)) + if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, position)) { sz.y = wxMax(sz.y, childSize.y); sz.x += childSize.x; @@ -2302,7 +2370,8 @@ 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; @@ -2311,14 +2380,14 @@ bool wxRichTextParagraph::GetRangeSize(const wxRichTextRange& range, wxSize& siz { 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)) + if (child->GetRangeSize(rangeToUse, childSize, childDescent, dc, flags, position)) { lineSize.y = wxMax(lineSize.y, childSize.y); lineSize.x += childSize.x; @@ -2392,12 +2461,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()) { @@ -2410,7 +2480,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; @@ -2418,7 +2488,7 @@ bool wxRichTextParagraph::FindPosition(wxDC& dc, long index, wxPoint& pt, int* h // then we can add this size to the line start position and // paragraph start position to find the actual position. - if (GetRangeSize(r, rangeSize, descent, dc, wxRICHTEXT_UNFORMATTED)) + if (GetRangeSize(r, rangeSize, descent, dc, wxRICHTEXT_UNFORMATTED, line->GetPosition()+ GetPosition())) { pt.x = line->GetPosition().x + GetPosition().x + rangeSize.x; *height = line->GetSize().y; @@ -2446,31 +2516,32 @@ 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); + GetRangeSize(rangeToUse, childSize, descent, dc, wxRICHTEXT_UNFORMATTED, linePos); int nextX = childSize.x + linePos.x; @@ -2514,7 +2585,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; } @@ -2574,7 +2650,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()); } @@ -2684,7 +2760,7 @@ bool wxRichTextParagraph::FindWrapPosition(const wxRichTextRange& range, wxDC& d int spacePos = plainText.Find(wxT(' '), true); if (spacePos != wxNOT_FOUND) { - int positionsFromEndOfString = plainText.Length() - spacePos - 1; + int positionsFromEndOfString = plainText.length() - spacePos - 1; breakPosition = breakPosition - positionsFromEndOfString; } } @@ -2763,6 +2839,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 @@ -2773,15 +2883,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; } @@ -2797,6 +2908,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. @@ -2836,7 +2955,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR // (a) All selected. if (selectionRange.GetStart() <= range.GetStart() && selectionRange.GetEnd() >= range.GetEnd()) - { + {/* // Draw all selected dc.SetBrush(*wxBLACK_BRUSH); dc.SetPen(*wxBLACK_PEN); @@ -2846,15 +2965,18 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR dc.DrawRectangle(selRect); dc.SetTextForeground(*wxWHITE); dc.SetBackgroundMode(wxTRANSPARENT); - dc.DrawText(stringChunk, x, y); + dc.DrawText(stringChunk, x, y);*/ + DrawTabbedString(dc, rect,stringChunk, x, y, true); } // (b) None selected. else if (selectionRange.GetEnd() < range.GetStart() || selectionRange.GetStart() > range.GetEnd()) { // Draw all unselected + /* dc.SetTextForeground(GetAttributes().GetTextColour()); dc.SetBackgroundMode(wxTRANSPARENT); - dc.DrawText(stringChunk, x, y); + dc.DrawText(stringChunk, x, y);*/ + DrawTabbedString(dc, rect,stringChunk, x, y, false); } else { @@ -2872,13 +2994,14 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR if (fragmentLen < 0) wxLogDebug(wxT("Mid(%d, %d"), (int)(r1 - offset), (int)fragmentLen); wxString stringFragment = m_text.Mid(r1 - offset, fragmentLen); - +/* dc.SetTextForeground(GetAttributes().GetTextColour()); dc.DrawText(stringFragment, x, y); wxCoord w, h; dc.GetTextExtent(stringFragment, & w, & h); - x += w; + x += w;*/ + DrawTabbedString(dc, rect,stringFragment, x, y, false); } // 2. Selected chunk, if any. @@ -2891,7 +3014,7 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR if (fragmentLen < 0) wxLogDebug(wxT("Mid(%d, %d"), (int)(s1 - offset), (int)fragmentLen); wxString stringFragment = m_text.Mid(s1 - offset, fragmentLen); - +/* wxCoord w, h; dc.GetTextExtent(stringFragment, & w, & h); wxRect selRect(x, rect.y, w, rect.GetHeight()); @@ -2902,7 +3025,8 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR dc.SetTextForeground(*wxWHITE); dc.DrawText(stringFragment, x, y); - x += w; + x += w;*/ + DrawTabbedString(dc, rect,stringFragment, x, y, true); } // 3. Remaining unselected chunk, if any @@ -2915,15 +3039,76 @@ bool wxRichTextPlainText::Draw(wxDC& dc, const wxRichTextRange& range, const wxR if (fragmentLen < 0) wxLogDebug(wxT("Mid(%d, %d"), (int)(s2 - offset), (int)fragmentLen); wxString stringFragment = m_text.Mid(s2 - offset, fragmentLen); - +/* dc.SetTextForeground(GetAttributes().GetTextColour()); - dc.DrawText(stringFragment, x, y); + dc.DrawText(stringFragment, x, y);*/ + DrawTabbedString(dc, rect,stringFragment, x, y, false); } } return true; } +bool wxRichTextPlainText::DrawTabbedString(wxDC& dc,const wxRect& rect,wxString& str, wxCoord& x, wxCoord& y, bool selected) +{ + wxArrayInt tab_array = GetAttributes().GetTabs(); + if(tab_array.IsEmpty()){// create a default tab list at 10 mm each. + for( int i = 0; i < 20; ++i){ + tab_array.Add(i*100); + } + } + int map_mode = dc.GetMapMode(); + dc.SetMapMode(wxMM_LOMETRIC ); + int num_tabs = tab_array.GetCount(); + for( int i = 0; i < num_tabs; ++i){ + tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]); + } + dc.SetMapMode(map_mode ); + int next_tab_pos = -1; + int tab_pos = -1; + wxCoord w, h; + if(selected){ + dc.SetBrush(*wxBLACK_BRUSH); + dc.SetPen(*wxBLACK_PEN); + dc.SetTextForeground(*wxWHITE); + dc.SetBackgroundMode(wxTRANSPARENT); + } + else{ + dc.SetTextForeground(GetAttributes().GetTextColour()); + dc.SetBackgroundMode(wxTRANSPARENT); + } + while(str.Find(wxT('\t')) >= 0){// the string has a tab + // break up the string at the Tab + wxString stringChunk = str.BeforeFirst(wxT('\t')); + str = str.AfterFirst(wxT('\t')); + dc.GetTextExtent(stringChunk, & w, & h); + tab_pos = x + w; + bool not_found = true; + for( int i = 0; i < num_tabs && not_found; ++i){ + next_tab_pos = tab_array.Item(i); + if( next_tab_pos > tab_pos){ + not_found = false; + if(selected){ + w = next_tab_pos - x; + wxRect selRect(x, rect.y, w, rect.GetHeight()); + dc.DrawRectangle(selRect); + } + dc.DrawText(stringChunk, x, y); + x = next_tab_pos; + } + } + } + + dc.GetTextExtent(str, & w, & h); + if(selected){ + wxRect selRect(x, rect.y, w, rect.GetHeight()); + dc.DrawRectangle(selRect); + } + dc.DrawText(str, x, y); + x += w; + return true; + +} /// Lay the item out bool wxRichTextPlainText::Layout(wxDC& dc, const wxRect& WXUNUSED(rect), int WXUNUSED(style)) { @@ -2947,7 +3132,7 @@ void wxRichTextPlainText::Copy(const wxRichTextPlainText& obj) /// Get/set the object size for the given range. Returns false if the range /// is invalid for this object. -bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags)) const +bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& descent, wxDC& dc, int WXUNUSED(flags), wxPoint position) const { if (!range.IsWithin(GetRange())) return false; @@ -2963,8 +3148,47 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz long len = range.GetLength(); wxString stringChunk = m_text.Mid(startPos, (size_t) len); wxCoord w, h; + int width = 0; + if(stringChunk.Find(wxT('\t')) >= 0){// the string has a tab + wxArrayInt tab_array = GetAttributes().GetTabs(); + if(tab_array.IsEmpty()) + { + // create a default tab list at 10 mm each. + for( int i = 0; i < 20; ++i) + { + tab_array.Add(i*100); + } + } + int map_mode = dc.GetMapMode(); + dc.SetMapMode(wxMM_LOMETRIC ); + int num_tabs = tab_array.GetCount(); + for( int i = 0; i < num_tabs; ++i) + { + tab_array[i] = dc.LogicalToDeviceXRel(tab_array[i]); + } + dc.SetMapMode(map_mode ); + int next_tab_pos = -1; + + while(stringChunk.Find(wxT('\t')) >= 0){// the string has a tab + // break up the string at the Tab + wxString stringFragment = stringChunk.BeforeFirst(wxT('\t')); + stringChunk = stringChunk.AfterFirst(wxT('\t')); + dc.GetTextExtent(stringFragment, & w, & h); + width += w; + int absolute_width = width + position.x; + bool not_found = true; + for( int i = 0; i < num_tabs && not_found; ++i){ + next_tab_pos = tab_array.Item(i); + if( next_tab_pos > absolute_width){ + not_found = false; + width = next_tab_pos - position.x; + } + } + } + } dc.GetTextExtent(stringChunk, & w, & h, & descent); - size = wxSize(w, dc.GetCharHeight()); + width += w; + size = wxSize(width, dc.GetCharHeight()); return true; } @@ -2974,7 +3198,7 @@ bool wxRichTextPlainText::GetRangeSize(const wxRichTextRange& range, wxSize& siz wxRichTextObject* wxRichTextPlainText::DoSplit(long pos) { int index = pos - GetRange().GetStart(); - if (index < 0 || index >= (int) m_text.Length()) + if (index < 0 || index >= (int) m_text.length()) return NULL; wxString firstPart = m_text.Mid(0, index); @@ -2994,7 +3218,7 @@ wxRichTextObject* wxRichTextPlainText::DoSplit(long pos) /// Calculate range void wxRichTextPlainText::CalculateRange(long start, long& end) { - end = start + m_text.Length() - 1; + end = start + m_text.length() - 1; m_range.SetRange(start, end); } @@ -3095,6 +3319,7 @@ void wxRichTextBuffer::Clear() DeleteChildren(); GetCommandProcessor()->ClearCommands(); Modify(false); + Invalidate(wxRICHTEXT_ALL); } void wxRichTextBuffer::Reset() @@ -3103,6 +3328,7 @@ void wxRichTextBuffer::Reset() AddParagraph(wxEmptyString); GetCommandProcessor()->ClearCommands(); Modify(false); + Invalidate(wxRICHTEXT_ALL); } /// Submit command to insert the given text @@ -3117,7 +3343,7 @@ bool wxRichTextBuffer::InsertTextWithUndo(long pos, const wxString& text, wxRich action->SetPosition(pos); // Set the range we'll need to delete in Undo - action->SetRange(wxRichTextRange(pos, pos + text.Length() - 1)); + action->SetRange(wxRichTextRange(pos, pos + text.length() - 1)); SubmitAction(action); @@ -3299,15 +3525,15 @@ bool wxRichTextBuffer::BeginStyle(const wxTextAttrEx& style) /// End the style bool wxRichTextBuffer::EndStyle() { - if (m_attributeStack.GetFirst() == NULL) + if (!m_attributeStack.GetFirst()) { wxLogDebug(_("Too many EndStyle calls!")); 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); @@ -3326,7 +3552,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(); } @@ -3614,8 +3840,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(); @@ -3642,6 +3871,8 @@ wxString wxRichTextBuffer::GetExtWildcard(bool combine, bool save) wildcard += handler->GetExtension(); wildcard += wxT(")|*."); wildcard += handler->GetExtension(); + if (types) + types->Add(handler->GetType()); } count ++; } @@ -3659,7 +3890,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; } @@ -3679,7 +3916,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; } @@ -3698,12 +3940,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; } @@ -3711,6 +3957,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()) @@ -3720,6 +3967,7 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) wxTextDataObject data; wxTheClipboard->GetData(data); wxString text(data.GetText()); + text.Replace(_T("\r\n"), _T("\n")); InsertTextWithUndo(position+1, text, GetRichTextCtrl()); @@ -3751,6 +3999,9 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) wxTheClipboard->Close(); } } +#else + wxUnusedVar(position); +#endif return success; } @@ -3758,7 +4009,8 @@ bool wxRichTextBuffer::PasteFromClipboard(long position) bool wxRichTextBuffer::CanPasteFromClipboard() const { bool canPaste = false; - if (wxTheClipboard->Open()) +#if wxUSE_CLIPBOARD && wxUSE_DATAOBJ + if (!wxTheClipboard->IsOpened() && wxTheClipboard->Open()) { if (wxTheClipboard->IsSupported(wxDF_TEXT) || wxTheClipboard->IsSupported(wxDF_BITMAP)) { @@ -3766,6 +4018,7 @@ bool wxRichTextBuffer::CanPasteFromClipboard() const } wxTheClipboard->Close(); } +#endif return canPaste; } @@ -3827,7 +4080,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(); @@ -3838,7 +4091,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(); @@ -3886,6 +4139,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()) @@ -3899,6 +4153,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 */); @@ -3907,6 +4162,7 @@ bool wxRichTextAction::Do() case wxRICHTEXT_CHANGE_STYLE: { ApplyParagraphs(GetNewParagraphs()); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition()); @@ -3929,6 +4185,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()) @@ -3942,6 +4199,7 @@ bool wxRichTextAction::Undo() { m_buffer->InsertFragment(GetRange().GetStart(), m_oldParagraphs); m_buffer->UpdateRanges(); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition(), true /* send update event */); @@ -3950,6 +4208,7 @@ bool wxRichTextAction::Undo() case wxRICHTEXT_CHANGE_STYLE: { ApplyParagraphs(GetOldParagraphs()); + m_buffer->Invalidate(GetRange()); UpdateAppearance(GetPosition()); @@ -3970,9 +4229,9 @@ void wxRichTextAction::UpdateAppearance(long caretPosition, bool sendUpdateEvent 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(); @@ -4114,7 +4373,7 @@ bool wxRichTextImage::Layout(wxDC& WXUNUSED(dc), const wxRect& rect, int WXUNUSE /// Get/set the object size for the given range. Returns false if the range /// is invalid for this object. -bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags)) const +bool wxRichTextImage::GetRangeSize(const wxRichTextRange& range, wxSize& size, int& WXUNUSED(descent), wxDC& WXUNUSED(dc), int WXUNUSED(flags), wxPoint WXUNUSED(position)) const { if (!range.IsWithin(GetRange())) return false; @@ -4228,23 +4487,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; @@ -4310,23 +4569,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; @@ -4645,6 +4904,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; } @@ -4663,6 +4925,94 @@ bool wxRichTextAttr::GetFontAttributes(const wxFont& font) return true; } +wxRichTextAttr wxRichTextAttr::Combine(const wxRichTextAttr& attr, + const wxRichTextAttr& attrDef, + const wxTextCtrlBase *text) +{ + wxColour colFg = attr.GetTextColour(); + if ( !colFg.Ok() ) + { + colFg = attrDef.GetTextColour(); + + if ( text && !colFg.Ok() ) + colFg = text->GetForegroundColour(); + } + + wxColour colBg = attr.GetBackgroundColour(); + if ( !colBg.Ok() ) + { + colBg = attrDef.GetBackgroundColour(); + + if ( text && !colBg.Ok() ) + colBg = text->GetBackgroundColour(); + } + + wxRichTextAttr newAttr(colFg, colBg); + + if (attr.HasWeight()) + newAttr.SetFontWeight(attr.GetFontWeight()); + + if (attr.HasSize()) + newAttr.SetFontSize(attr.GetFontSize()); + + if (attr.HasItalic()) + newAttr.SetFontStyle(attr.GetFontStyle()); + + if (attr.HasUnderlined()) + newAttr.SetFontUnderlined(attr.GetFontUnderlined()); + + if (attr.HasFaceName()) + newAttr.SetFontFaceName(attr.GetFontFaceName()); + + if (attr.HasAlignment()) + newAttr.SetAlignment(attr.GetAlignment()); + else if (attrDef.HasAlignment()) + newAttr.SetAlignment(attrDef.GetAlignment()); + + if (attr.HasTabs()) + newAttr.SetTabs(attr.GetTabs()); + else if (attrDef.HasTabs()) + newAttr.SetTabs(attrDef.GetTabs()); + + if (attr.HasLeftIndent()) + newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); + else if (attrDef.HasLeftIndent()) + newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); + + if (attr.HasRightIndent()) + newAttr.SetRightIndent(attr.GetRightIndent()); + else if (attrDef.HasRightIndent()) + newAttr.SetRightIndent(attrDef.GetRightIndent()); + + // NEW ATTRIBUTES + + if (attr.HasParagraphSpacingAfter()) + newAttr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter()); + + if (attr.HasParagraphSpacingBefore()) + newAttr.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore()); + + if (attr.HasLineSpacing()) + newAttr.SetLineSpacing(attr.GetLineSpacing()); + + if (attr.HasCharacterStyleName()) + newAttr.SetCharacterStyleName(attr.GetCharacterStyleName()); + + if (attr.HasParagraphStyleName()) + newAttr.SetParagraphStyleName(attr.GetParagraphStyleName()); + + if (attr.HasBulletStyle()) + newAttr.SetBulletStyle(attr.GetBulletStyle()); + + if (attr.HasBulletNumber()) + newAttr.SetBulletNumber(attr.GetBulletNumber()); + + if (attr.HasBulletSymbol()) + newAttr.SetBulletSymbol(attr.GetBulletSymbol()); + + return newAttr; +} + /*! * wxTextAttrEx is an extended version of wxTextAttr with more paragraph attributes. */ @@ -4712,6 +5062,146 @@ void wxTextAttrEx::operator= (const wxTextAttr& attr) wxTextAttr::operator= (attr); } +wxTextAttrEx wxTextAttrEx::CombineEx(const wxTextAttrEx& attr, + const wxTextAttrEx& attrDef, + const wxTextCtrlBase *text) +{ + wxTextAttrEx newAttr; + + // If attr specifies the complete font, just use that font, overriding all + // default font attributes. + if ((attr.GetFlags() & wxTEXT_ATTR_FONT) == wxTEXT_ATTR_FONT) + newAttr.SetFont(attr.GetFont()); + else + { + // First find the basic, default font + long flags = 0; + + wxFont font; + if (attrDef.HasFont()) + { + flags = (attrDef.GetFlags() & wxTEXT_ATTR_FONT); + font = attrDef.GetFont(); + } + else + { + if (text) + font = text->GetFont(); + + // We leave flags at 0 because no font attributes have been specified yet + } + if (!font.Ok()) + font = *wxNORMAL_FONT; + + // Otherwise, if there are font attributes in attr, apply them + if (attr.HasFont()) + { + if (attr.HasSize()) + { + flags |= wxTEXT_ATTR_FONT_SIZE; + font.SetPointSize(attr.GetFont().GetPointSize()); + } + if (attr.HasItalic()) + { + flags |= wxTEXT_ATTR_FONT_ITALIC;; + font.SetStyle(attr.GetFont().GetStyle()); + } + if (attr.HasWeight()) + { + flags |= wxTEXT_ATTR_FONT_WEIGHT; + font.SetWeight(attr.GetFont().GetWeight()); + } + if (attr.HasFaceName()) + { + flags |= wxTEXT_ATTR_FONT_FACE; + font.SetFaceName(attr.GetFont().GetFaceName()); + } + if (attr.HasUnderlined()) + { + flags |= wxTEXT_ATTR_FONT_UNDERLINE; + font.SetUnderlined(attr.GetFont().GetUnderlined()); + } + newAttr.SetFont(font); + newAttr.SetFlags(newAttr.GetFlags()|flags); + } + } + + // TODO: should really check we are specifying these in the flags, + // before setting them, as per above; or we will set them willy-nilly. + // However, we should also check whether this is the intention + // as per wxTextAttr::Combine, i.e. always to have valid colours + // in the style. + wxColour colFg = attr.GetTextColour(); + if ( !colFg.Ok() ) + { + colFg = attrDef.GetTextColour(); + + if ( text && !colFg.Ok() ) + colFg = text->GetForegroundColour(); + } + + wxColour colBg = attr.GetBackgroundColour(); + if ( !colBg.Ok() ) + { + colBg = attrDef.GetBackgroundColour(); + + if ( text && !colBg.Ok() ) + colBg = text->GetBackgroundColour(); + } + + newAttr.SetTextColour(colFg); + newAttr.SetBackgroundColour(colBg); + + if (attr.HasAlignment()) + newAttr.SetAlignment(attr.GetAlignment()); + else if (attrDef.HasAlignment()) + newAttr.SetAlignment(attrDef.GetAlignment()); + + if (attr.HasTabs()) + newAttr.SetTabs(attr.GetTabs()); + else if (attrDef.HasTabs()) + newAttr.SetTabs(attrDef.GetTabs()); + + if (attr.HasLeftIndent()) + newAttr.SetLeftIndent(attr.GetLeftIndent(), attr.GetLeftSubIndent()); + else if (attrDef.HasLeftIndent()) + newAttr.SetLeftIndent(attrDef.GetLeftIndent(), attr.GetLeftSubIndent()); + + if (attr.HasRightIndent()) + newAttr.SetRightIndent(attr.GetRightIndent()); + else if (attrDef.HasRightIndent()) + newAttr.SetRightIndent(attrDef.GetRightIndent()); + + // NEW ATTRIBUTES + + if (attr.HasParagraphSpacingAfter()) + newAttr.SetParagraphSpacingAfter(attr.GetParagraphSpacingAfter()); + + if (attr.HasParagraphSpacingBefore()) + newAttr.SetParagraphSpacingBefore(attr.GetParagraphSpacingBefore()); + + if (attr.HasLineSpacing()) + newAttr.SetLineSpacing(attr.GetLineSpacing()); + + if (attr.HasCharacterStyleName()) + newAttr.SetCharacterStyleName(attr.GetCharacterStyleName()); + + if (attr.HasParagraphStyleName()) + newAttr.SetParagraphStyleName(attr.GetParagraphStyleName()); + + if (attr.HasBulletStyle()) + newAttr.SetBulletStyle(attr.GetBulletStyle()); + + if (attr.HasBulletNumber()) + newAttr.SetBulletNumber(attr.GetBulletNumber()); + + if (attr.HasBulletSymbol()) + newAttr.SetBulletSymbol(attr.GetBulletSymbol()); + + return newAttr; +} + + /*! * wxRichTextFileHandler * Base class for file handlers @@ -4725,8 +5215,8 @@ bool wxRichTextFileHandler::LoadFile(wxRichTextBuffer *buffer, const wxString& f wxFFileInputStream stream(filename); if (stream.Ok()) return LoadFile(buffer, stream); - else - return false; + + return false; } bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& filename) @@ -4734,8 +5224,8 @@ bool wxRichTextFileHandler::SaveFile(wxRichTextBuffer *buffer, const wxString& f wxFFileOutputStream stream(filename); if (stream.Ok()) return SaveFile(buffer, stream); - else - return false; + + return false; } #endif // wxUSE_STREAMS @@ -4762,14 +5252,22 @@ bool wxRichTextPlainTextHandler::DoLoadFile(wxRichTextBuffer *buffer, wxInputStr 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 += wxChar(ch); + lastCh = ch; + } } buffer->Clear(); @@ -4788,7 +5286,7 @@ bool wxRichTextPlainTextHandler::DoSaveFile(wxRichTextBuffer *buffer, wxOutputSt wxString text = buffer->GetText(); wxCharBuffer buf = text.ToAscii(); - stream.Write((const char*) buf, text.Length()); + stream.Write((const char*) buf, text.length()); return true; } #endif // wxUSE_STREAMS @@ -4826,8 +5324,7 @@ void wxRichTextImageBlock::Init() void wxRichTextImageBlock::Clear() { - if (m_data) - delete m_data; + delete[] m_data; m_data = NULL; m_dataSize = 0; m_imageType = -1; @@ -4988,7 +5485,7 @@ bool wxRichTextImageBlock::WriteHex(wxOutputStream& stream) hex = wxDecToHex(m_data[i]); wxCharBuffer buf = hex.ToAscii(); - stream.Write((const char*) buf, hex.Length()); + stream.Write((const char*) buf, hex.length()); } return true; @@ -5061,4 +5558,3 @@ bool wxRichTextImageBlock::WriteBlock(const wxString& filename, unsigned char* b #endif // wxUSE_RICHTEXT -