diff --git a/src/apps/haiku-depot/textview/Paragraph.cpp b/src/apps/haiku-depot/textview/Paragraph.cpp index db6ea8a388..4bbfb8d130 100644 --- a/src/apps/haiku-depot/textview/Paragraph.cpp +++ b/src/apps/haiku-depot/textview/Paragraph.cpp @@ -261,12 +261,36 @@ Paragraph::IsEmpty() const BString -Paragraph::GetText(int32 start, int32 length) const +Paragraph::Text() const +{ + BString result; + + int32 count = fTextSpans.CountItems(); + for (int32 i = 0; i < count; i++) + result << fTextSpans.ItemAtFast(i).Text(); + + return result; +} + + +BString +Paragraph::Text(int32 start, int32 length) const +{ + Paragraph subParagraph = SubParagraph(start, length); + return subParagraph.Text(); +} + + +Paragraph +Paragraph::SubParagraph(int32 start, int32 length) const { if (start < 0) start = 0; - BString text; + if (start == 0 && length == Length()) + return *this; + + Paragraph result(fStyle); int32 count = fTextSpans.CountItems(); for (int32 i = 0; i < count; i++) { @@ -284,13 +308,10 @@ Paragraph::GetText(int32 start, int32 length) const spanLength -= start; int32 copyLength = std::min(spanLength, length); - if (start == 0 && length == spanLength) { - text << span.Text(); - } else { - BString subString; - span.Text().CopyCharsInto(subString, start, copyLength); - text << subString; - } + if (start == 0 && length == spanLength) + result.Append(span); + else + result.Append(span.SubSpan(start, copyLength)); length -= copyLength; if (length == 0) @@ -300,7 +321,7 @@ Paragraph::GetText(int32 start, int32 length) const start = 0; } - return text; + return result; } diff --git a/src/apps/haiku-depot/textview/Paragraph.h b/src/apps/haiku-depot/textview/Paragraph.h index a6ad090d09..a500c95614 100644 --- a/src/apps/haiku-depot/textview/Paragraph.h +++ b/src/apps/haiku-depot/textview/Paragraph.h @@ -39,7 +39,9 @@ public: int32 Length() const; bool IsEmpty() const; - BString GetText(int32 start, int32 length) const; + BString Text() const; + BString Text(int32 start, int32 length) const; + Paragraph SubParagraph(int32 start, int32 length) const; void PrintToStream() const; diff --git a/src/apps/haiku-depot/textview/TextDocument.cpp b/src/apps/haiku-depot/textview/TextDocument.cpp index d1fb07558a..42e113a284 100644 --- a/src/apps/haiku-depot/textview/TextDocument.cpp +++ b/src/apps/haiku-depot/textview/TextDocument.cpp @@ -394,7 +394,14 @@ TextDocument::Length() const BString -TextDocument::GetText(int32 start, int32 length) const +TextDocument::Text() const +{ + return Text(0, Length()); +} + + +BString +TextDocument::Text(int32 start, int32 length) const { if (start < 0) start = 0; @@ -417,13 +424,11 @@ TextDocument::GetText(int32 start, int32 length) const paragraphLength -= start; int32 copyLength = std::min(paragraphLength, length); - text << paragraph.GetText(start, copyLength); + text << paragraph.Text(start, copyLength); length -= copyLength; if (length == 0) break; - else if (i < count - 1) - text << '\n'; // Next paragraph is copied from its beginning start = 0; @@ -433,6 +438,48 @@ TextDocument::GetText(int32 start, int32 length) const } +TextDocumentRef +TextDocument::SubDocument(int32 start, int32 length) const +{ + TextDocumentRef result(new(std::nothrow) TextDocument( + fDefaultCharacterStyle, fEmptyLastParagraph.Style()), true); + + if (result.Get() == NULL) + return result; + + if (start < 0) + start = 0; + + int32 count = fParagraphs.CountItems(); + for (int32 i = 0; i < count; i++) { + const Paragraph& paragraph = fParagraphs.ItemAtFast(i); + int32 paragraphLength = paragraph.Length(); + if (paragraphLength == 0) + continue; + if (start > paragraphLength) { + // Skip paragraph if its before start + start -= paragraphLength; + continue; + } + + // Remaining paragraph length after start + paragraphLength -= start; + int32 copyLength = std::min(paragraphLength, length); + + result->Append(paragraph.SubParagraph(start, copyLength)); + + length -= copyLength; + if (length == 0) + break; + + // Next paragraph is copied from its beginning + start = 0; + } + + return result; +} + + // #pragma mark - @@ -450,3 +497,55 @@ TextDocument::PrintToStream() const } printf("\n"); } + + +// #pragma mark - + + +bool +TextDocument::AddListener(const TextListenerRef& listener) +{ + return fTextListeners.Add(listener); +} + + +bool +TextDocument::RemoveListener(const TextListenerRef& listener) +{ + return fTextListeners.Remove(listener); +} + + +void +TextDocument::_NotifyTextChanging(TextChangingEvent& event) const +{ + // Copy listener list to have a stable list in case listeners + // are added/removed from within the notification hook. + TextListenerList listeners(fTextListeners); + int32 count = listeners.CountItems(); + for (int32 i = 0; i < count; i++) { + const TextListenerRef& listener = listeners.ItemAtFast(i); + if (listener.Get() == NULL) + continue; + listener->TextChanging(event); + if (event.IsCanceled()) + break; + } +} + + +void +TextDocument::_NotifyTextChanged(const TextChangedEvent& event) const +{ + // Copy listener list to have a stable list in case listeners + // are added/removed from within the notification hook. + TextListenerList listeners(fTextListeners); + int32 count = listeners.CountItems(); + for (int32 i = 0; i < count; i++) { + const TextListenerRef& listener = listeners.ItemAtFast(i); + if (listener.Get() == NULL) + continue; + listener->TextChanged(event); + } +} + diff --git a/src/apps/haiku-depot/textview/TextDocument.h b/src/apps/haiku-depot/textview/TextDocument.h index 4aa28c3bd0..d2a4d55a72 100644 --- a/src/apps/haiku-depot/textview/TextDocument.h +++ b/src/apps/haiku-depot/textview/TextDocument.h @@ -10,9 +10,14 @@ #include "CharacterStyle.h" #include "List.h" #include "Paragraph.h" +#include "TextListener.h" -typedef List ParagraphList; +typedef List ParagraphList; +typedef List TextListenerList; + +class TextDocument; +typedef BReference TextDocumentRef; class TextDocument : public BReferenceable { @@ -68,18 +73,30 @@ public: // Query information int32 Length() const; - BString GetText(int32 textOffset, int32 length) const; + BString Text() const; + BString Text(int32 textOffset, int32 length) const; + TextDocumentRef SubDocument(int32 textOffset, + int32 length) const; void PrintToStream() const; + // Listener support + bool AddListener(const TextListenerRef& listener); + bool RemoveListener(const TextListenerRef& listener); + +private: + void _NotifyTextChanging( + TextChangingEvent& event) const; + void _NotifyTextChanged( + const TextChangedEvent& event) const; + private: ParagraphList fParagraphs; Paragraph fEmptyLastParagraph; CharacterStyle fDefaultCharacterStyle; + + TextListenerList fTextListeners; }; -typedef BReference TextDocumentRef; - - #endif // TEXT_DOCUMENT_H diff --git a/src/apps/haiku-depot/textview/TextDocumentView.cpp b/src/apps/haiku-depot/textview/TextDocumentView.cpp index edee42dc48..d4005e808c 100644 --- a/src/apps/haiku-depot/textview/TextDocumentView.cpp +++ b/src/apps/haiku-depot/textview/TextDocumentView.cpp @@ -370,7 +370,7 @@ TextDocumentView::Copy(BClipboard* clipboard) int32 end; GetSelection(start, end); - BString text = fTextDocument->GetText(start, end - start); + BString text = fTextDocument->Text(start, end - start); clip->AddData("text/plain", B_MIME_TYPE, text.String(), text.Length());