[haiku-commits] haiku: hrev49658 - src/apps/haikudepot/textview

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 20 Sep 2015 22:19:24 +0200 (CEST)

hrev49658 adds 5 changesets to branch 'master'
old head: 287dab9d8e79fca7e2efb349ceb26078ac797093
new head: 5f80d48a76353e7bf18a7ad69462974e0db1d455
overview:
http://cgit.haiku-os.org/haiku/log/?qt=range&q=5f80d48a7635+%5E287dab9d8e79

----------------------------------------------------------------------------

1fa37d5af891: HaikuDepot: Text: Fix regression for B_SELECT_ALL

An Invalidate() was removed, since I originally planned to remove the need
to invalidate on selection changes, but then saved it for later.

9a8dd79cc2fa: TextDocumentLayout: Use Invalidate() instead of
InvalidateParagraphs()

Added TODO about which data the TextChangedEvent should have in order to
know how to respond in the TextDocumentLayout. For now, update all paragraphs
in the layout, add new ones as necessary, and remove the ones we have in
excess by using Invalidate().

2e2ff27a922c: Paragraph: Added EndsWith(BString)

f890fab65b63: TextDocument: Change _Insert() to use TextDocument

In preparation for implementing Undo/Redo support, we need _Insert() to
take a TextDocument instead of a BString, CharacterStyle and ParagraphStyle.
When a chunk of the TextDocument has been removed, we need to be able to
Insert() that as part of the Undo operation. Not well tested, but typing
still works.

5f80d48a7635: TextDocument: Extended comment in _Insert().

[ Stephan Aßmus <superstippi@xxxxxx> ]

----------------------------------------------------------------------------

6 files changed, 207 insertions(+), 79 deletions(-)
src/apps/haikudepot/textview/Paragraph.cpp | 11 +
src/apps/haikudepot/textview/Paragraph.h | 1 +
src/apps/haikudepot/textview/TextDocument.cpp | 223 +++++++++++++------
src/apps/haikudepot/textview/TextDocument.h | 38 ++--
.../haikudepot/textview/TextDocumentLayout.cpp | 12 +-
.../haikudepot/textview/TextDocumentView.cpp | 1 +

############################################################################

Commit: 1fa37d5af89141df852e589279511e395194efe6
URL: http://cgit.haiku-os.org/haiku/commit/?id=1fa37d5af891
Author: Stephan Aßmus <superstippi@xxxxxx>
Date: Sun Sep 13 19:16:23 2015 UTC

HaikuDepot: Text: Fix regression for B_SELECT_ALL

An Invalidate() was removed, since I originally planned to remove the need
to invalidate on selection changes, but then saved it for later.

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/textview/TextDocumentView.cpp
b/src/apps/haikudepot/textview/TextDocumentView.cpp
index 9d09a7a..1584d24 100644
--- a/src/apps/haikudepot/textview/TextDocumentView.cpp
+++ b/src/apps/haikudepot/textview/TextDocumentView.cpp
@@ -369,6 +369,7 @@ TextDocumentView::SelectAll()

fTextEditor->SelectAll();
_ShowCaret(false);
+ Invalidate();
}



############################################################################

Commit: 9a8dd79cc2fabb946e4f61fdd0a70780184a1a8b
URL: http://cgit.haiku-os.org/haiku/commit/?id=9a8dd79cc2fa
Author: Stephan Aßmus <superstippi@xxxxxx>
Date: Sun Sep 20 20:09:52 2015 UTC

TextDocumentLayout: Use Invalidate() instead of InvalidateParagraphs()

Added TODO about which data the TextChangedEvent should have in order to
know how to respond in the TextDocumentLayout. For now, update all paragraphs
in the layout, add new ones as necessary, and remove the ones we have in
excess by using Invalidate().

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/textview/TextDocumentLayout.cpp
b/src/apps/haikudepot/textview/TextDocumentLayout.cpp
index f998e36..8afa114 100644
--- a/src/apps/haikudepot/textview/TextDocumentLayout.cpp
+++ b/src/apps/haikudepot/textview/TextDocumentLayout.cpp
@@ -28,8 +28,16 @@ public:
printf("TextChanged(%" B_PRIi32 ", %" B_PRIi32 ")\n",
event.FirstChangedParagraph(),
event.ChangedParagraphCount());
- fLayout->InvalidateParagraphs(event.FirstChangedParagraph(),
- event.ChangedParagraphCount());
+ // TODO: The event does not contain useful data. Make the event
+ // system work so only the affected paragraphs are updated.
+ // I think we need "first affected", "last affected" (both
relative
+ // to the original paragraph count), and than how many new
paragraphs
+ // are between these. From the difference in old number of
paragraphs
+ // inbetween and the new count, we know how many new paragraphs
are
+ // missing, and the rest in the range needs to be updated.
+// fLayout->InvalidateParagraphs(event.FirstChangedParagraph(),
+// event.ChangedParagraphCount());
+ fLayout->Invalidate();
}

private:

############################################################################

Commit: 2e2ff27a922c071c15aa4193d8f8a8cd6e4de89d
URL: http://cgit.haiku-os.org/haiku/commit/?id=2e2ff27a922c
Author: Stephan Aßmus <superstippi@xxxxxx>
Date: Sun Sep 20 20:13:01 2015 UTC

Paragraph: Added EndsWith(BString)

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/textview/Paragraph.cpp
b/src/apps/haikudepot/textview/Paragraph.cpp
index 907394d..d1d9649 100644
--- a/src/apps/haikudepot/textview/Paragraph.cpp
+++ b/src/apps/haikudepot/textview/Paragraph.cpp
@@ -260,6 +260,17 @@ Paragraph::IsEmpty() const
}


+bool
+Paragraph::EndsWith(BString string) const
+{
+ int length = Length();
+ int endLength = string.CountChars();
+ int start = length - endLength;
+ BString end = Text(start, endLength);
+ return end == string;
+}
+
+
BString
Paragraph::Text() const
{
diff --git a/src/apps/haikudepot/textview/Paragraph.h
b/src/apps/haikudepot/textview/Paragraph.h
index a500c95..f6d953c 100644
--- a/src/apps/haikudepot/textview/Paragraph.h
+++ b/src/apps/haikudepot/textview/Paragraph.h
@@ -38,6 +38,7 @@ public:

int32 Length() const;
bool IsEmpty() const;
+ bool EndsWith(BString
string) const;

BString Text() const;
BString Text(int32 start, int32
length) const;

############################################################################

Commit: f890fab65b6370c2fa9cf5b840b1b01161dee7c0
URL: http://cgit.haiku-os.org/haiku/commit/?id=f890fab65b63
Author: Stephan Aßmus <superstippi@xxxxxx>
Date: Sun Sep 20 20:14:01 2015 UTC

TextDocument: Change _Insert() to use TextDocument

In preparation for implementing Undo/Redo support, we need _Insert() to
take a TextDocument instead of a BString, CharacterStyle and ParagraphStyle.
When a chunk of the TextDocument has been removed, we need to be able to
Insert() that as part of the Undo operation. Not well tested, but typing
still works.

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/textview/TextDocument.cpp
b/src/apps/haikudepot/textview/TextDocument.cpp
index ae15111..3ead9bc 100644
--- a/src/apps/haikudepot/textview/TextDocument.cpp
+++ b/src/apps/haikudepot/textview/TextDocument.cpp
@@ -18,8 +18,8 @@ TextDocument::TextDocument()
}


-TextDocument::TextDocument(const CharacterStyle& characterStyle,
- const ParagraphStyle& paragraphStyle)
+TextDocument::TextDocument(CharacterStyle characterStyle,
+ ParagraphStyle paragraphStyle)
:
fParagraphs(),
fEmptyLastParagraph(paragraphStyle),
@@ -79,7 +79,7 @@ TextDocument::Insert(int32 textOffset, const BString& text)

status_t
TextDocument::Insert(int32 textOffset, const BString& text,
- const CharacterStyle& style)
+ CharacterStyle style)
{
return Replace(textOffset, 0, text, style);
}
@@ -87,7 +87,7 @@ TextDocument::Insert(int32 textOffset, const BString& text,

status_t
TextDocument::Insert(int32 textOffset, const BString& text,
- const CharacterStyle& characterStyle, const ParagraphStyle&
paragraphStyle)
+ CharacterStyle characterStyle, ParagraphStyle paragraphStyle)
{
return Replace(textOffset, 0, text, characterStyle, paragraphStyle);
}
@@ -115,7 +115,7 @@ TextDocument::Replace(int32 textOffset, int32 length, const
BString& text)

status_t
TextDocument::Replace(int32 textOffset, int32 length, const BString& text,
- const CharacterStyle& style)
+ CharacterStyle style)
{
return Replace(textOffset, length, text, style,
ParagraphStyleAt(textOffset));
@@ -124,7 +124,18 @@ TextDocument::Replace(int32 textOffset, int32 length,
const BString& text,

status_t
TextDocument::Replace(int32 textOffset, int32 length, const BString& text,
- const CharacterStyle& characterStyle, const ParagraphStyle&
paragraphStyle)
+ CharacterStyle characterStyle, ParagraphStyle paragraphStyle)
+{
+ TextDocumentRef document = NormalizeText(text, characterStyle,
+ paragraphStyle);
+ if (document.Get() == NULL || document->Length() != text.CountChars())
+ return B_NO_MEMORY;
+ return Replace(textOffset, length, document);
+}
+
+
+status_t
+TextDocument::Replace(int32 textOffset, int32 length, TextDocumentRef document)
{
int32 firstParagraph = 0;
int32 paragraphCount = 0;
@@ -135,8 +146,7 @@ TextDocument::Replace(int32 textOffset, int32 length, const
BString& text,
if (ret != B_OK)
return ret;

- ret = _Insert(textOffset, text, characterStyle, paragraphStyle,
- firstParagraph, paragraphCount);
+ ret = _Insert(textOffset, document, firstParagraph, paragraphCount);

_NotifyTextChanged(TextChangedEvent(firstParagraph, paragraphCount));

@@ -181,6 +191,13 @@ TextDocument::ParagraphStyleAt(int32 textOffset) const


int32
+TextDocument::CountParagraphs() const
+{
+ return fParagraphs.CountItems();
+}
+
+
+int32
TextDocument::ParagraphIndexFor(int32 textOffset, int32& paragraphOffset) const
{
// TODO: Could binary search the Paragraphs if they were wrapped in
classes
@@ -350,32 +367,71 @@ TextDocument::PrintToStream() const
}


+/*static*/ TextDocumentRef
+TextDocument::NormalizeText(const BString& text,
+ CharacterStyle characterStyle, ParagraphStyle paragraphStyle)
+{
+ TextDocumentRef document(new(std::nothrow) TextDocument(characterStyle,
+ paragraphStyle), true);
+ if (document.Get() == NULL)
+ throw B_NO_MEMORY;
+
+ Paragraph paragraph(paragraphStyle);
+
+ // Append TextSpans, splitting 'text' into Paragraphs at line breaks.
+ int32 length = text.CountChars();
+ int32 chunkStart = 0;
+ while (chunkStart < length) {
+ int32 chunkEnd = text.FindFirst('\n', chunkStart);
+ bool foundLineBreak = chunkEnd >= chunkStart;
+ if (foundLineBreak)
+ chunkEnd++;
+ else
+ chunkEnd = length;
+
+ BString chunk;
+ text.CopyCharsInto(chunk, chunkStart, chunkEnd - chunkStart);
+ TextSpan span(chunk, characterStyle);
+
+ if (!paragraph.Append(span))
+ throw B_NO_MEMORY;
+ if (paragraph.Length() > 0 && !document->Append(paragraph))
+ throw B_NO_MEMORY;
+
+ paragraph = Paragraph(paragraphStyle);
+ chunkStart = chunkEnd + 1;
+ }
+
+ return document;
+}
+
+
// #pragma mark -


bool
-TextDocument::AddListener(const TextListenerRef& listener)
+TextDocument::AddListener(TextListenerRef listener)
{
return fTextListeners.Add(listener);
}


bool
-TextDocument::RemoveListener(const TextListenerRef& listener)
+TextDocument::RemoveListener(TextListenerRef listener)
{
return fTextListeners.Remove(listener);
}


bool
-TextDocument::AddUndoListener(const UndoableEditListenerRef& listener)
+TextDocument::AddUndoListener(UndoableEditListenerRef listener)
{
return fUndoListeners.Add(listener);
}


bool
-TextDocument::RemoveUndoListener(const UndoableEditListenerRef& listener)
+TextDocument::RemoveUndoListener(UndoableEditListenerRef listener)
{
return fUndoListeners.Remove(listener);
}
@@ -385,8 +441,7 @@ TextDocument::RemoveUndoListener(const
UndoableEditListenerRef& listener)


status_t
-TextDocument::_Insert(int32 textOffset, const BString& text,
- const CharacterStyle& characterStyle, const ParagraphStyle&
paragraphStyle,
+TextDocument::_Insert(int32 textOffset, TextDocumentRef document,
int32& index, int32& paragraphCount)
{
int32 paragraphOffset;
@@ -394,86 +449,128 @@ TextDocument::_Insert(int32 textOffset, const BString&
text,
if (index < 0)
return B_BAD_VALUE;

- if (text.Length() == 0)
+ if (document->Length() == 0)
return B_OK;

textOffset -= paragraphOffset;

- bool hasLineBreaks = text.FindFirst('\n', 0) >= 0;
+ bool hasLineBreaks;
+ if (document->CountParagraphs() > 1) {
+ hasLineBreaks = true;
+ } else {
+ const Paragraph& paragraph = document->ParagraphAt(0);
+ hasLineBreaks = paragraph.EndsWith("\n");
+ }

if (hasLineBreaks) {
// Split paragraph at textOffset
Paragraph paragraph1(ParagraphAt(index).Style());
- Paragraph paragraph2(paragraphStyle);
- const TextSpanList& textSpans = ParagraphAt(index).TextSpans();
- int32 spanCount = textSpans.CountItems();
- for (int32 i = 0; i < spanCount; i++) {
- const TextSpan& span = textSpans.ItemAtFast(i);
- int32 spanLength = span.CountChars();
- if (textOffset >= spanLength) {
- paragraph1.Append(span);
- textOffset -= spanLength;
- } else if (textOffset > 0) {
- paragraph1.Append(
- span.SubSpan(0, textOffset));
- paragraph2.Append(
- span.SubSpan(textOffset, spanLength -
textOffset));
- textOffset = 0;
- } else {
- paragraph2.Append(span);
+ Paragraph paragraph2(document->ParagraphAt(
+ document->CountParagraphs() - 1).Style());
+ {
+ const TextSpanList& textSpans =
ParagraphAt(index).TextSpans();
+ int32 spanCount = textSpans.CountItems();
+ for (int32 i = 0; i < spanCount; i++) {
+ const TextSpan& span = textSpans.ItemAtFast(i);
+ int32 spanLength = span.CountChars();
+ if (textOffset >= spanLength) {
+ if (!paragraph1.Append(span))
+ return B_NO_MEMORY;
+ textOffset -= spanLength;
+ } else if (textOffset > 0) {
+ if (!paragraph1.Append(
+ span.SubSpan(0,
textOffset))
+ || !paragraph2.Append(
+ span.SubSpan(textOffset,
+ spanLength -
textOffset))) {
+ return B_NO_MEMORY;
+ }
+ textOffset = 0;
+ } else {
+ if (!paragraph2.Append(span))
+ return B_NO_MEMORY;
+ }
}
}

fParagraphs.Remove(index);

- // Insert TextSpans, splitting 'text' into Paragraphs at line
breaks.
- int32 length = text.CountChars();
- int32 chunkStart = 0;
- while (chunkStart < length) {
- int32 chunkEnd = text.FindFirst('\n', chunkStart);
- bool foundLineBreak = chunkEnd >= chunkStart;
- if (foundLineBreak)
- chunkEnd++;
- else
- chunkEnd = length;
-
- BString chunk;
- text.CopyCharsInto(chunk, chunkStart, chunkEnd -
chunkStart);
- TextSpan span(chunk, characterStyle);
-
- if (foundLineBreak) {
+ // Append first paragraph in other document to first part of
+ // paragraph at insert position
+ {
+ const Paragraph& otherParagraph =
document->ParagraphAt(0);
+ const TextSpanList& textSpans =
otherParagraph.TextSpans();
+ int32 spanCount = textSpans.CountItems();
+ for (int32 i = 0; i < spanCount; i++) {
+ const TextSpan& span = textSpans.ItemAtFast(i);
+ // TODO: Import/map CharacterStyles
if (!paragraph1.Append(span))
return B_NO_MEMORY;
- if (paragraph1.Length() > 0) {
- if (!fParagraphs.Add(paragraph1, index))
+ }
+ }
+
+ // Insert the first paragraph-part again to the document

+ if (!fParagraphs.Add(paragraph1, index))
+ return B_NO_MEMORY;
+ paragraphCount++;
+
+ // Insert the other document's paragraph save for the last one
+ for (int32 i = 1; i < document->CountParagraphs() - 1; i++) {
+ const Paragraph& otherParagraph =
document->ParagraphAt(i);
+ // TODO: Import/map CharacterStyles and ParagraphStyle
+ if (!fParagraphs.Add(otherParagraph, ++index))
+ return B_NO_MEMORY;
+ paragraphCount++;
+ }
+
+ int32 lastIndex = document->CountParagraphs() - 1;
+ if (lastIndex > 0) {
+ const Paragraph& otherParagraph =
document->ParagraphAt(lastIndex);
+ if (otherParagraph.EndsWith("\n")) {
+ // TODO: Import/map CharacterStyles and
ParagraphStyle
+ if (!fParagraphs.Add(otherParagraph, ++index))
+ return B_NO_MEMORY;
+ } else {
+ const TextSpanList& textSpans =
otherParagraph.TextSpans();
+ int32 spanCount = textSpans.CountItems();
+ for (int32 i = 0; i < spanCount; i++) {
+ const TextSpan& span =
textSpans.ItemAtFast(i);
+ // TODO: Import/map CharacterStyles
+ if (!paragraph2.Prepend(span))
return B_NO_MEMORY;
- index++;
}
- paragraph1 = Paragraph(paragraphStyle);
- } else {
- if (!paragraph2.Prepend(span))
- return B_NO_MEMORY;
}
-
- chunkStart = chunkEnd + 1;
}

+ // Insert back the second paragraph-part
if (paragraph2.IsEmpty()) {
// Make sure Paragraph has at least one TextSpan, even
// if its empty.
const TextSpanList& spans = paragraph1.TextSpans();
const TextSpan& span = spans.LastItem();
- paragraph2.Append(TextSpan("", span.Style()));
+ if (!paragraph2.Append(TextSpan("", span.Style())))
+ return B_NO_MEMORY;
}

- if (!fParagraphs.Add(paragraph2, index))
+ if (!fParagraphs.Add(paragraph2, ++index))
return B_NO_MEMORY;
+
paragraphCount++;
} else {
Paragraph paragraph(ParagraphAt(index));
- paragraph.Insert(textOffset, TextSpan(text, characterStyle));
+ const Paragraph& otherParagraph = document->ParagraphAt(0);
+
+ const TextSpanList& textSpans = otherParagraph.TextSpans();
+ int32 spanCount = textSpans.CountItems();
+ for (int32 i = 0; i < spanCount; i++) {
+ const TextSpan& span = textSpans.ItemAtFast(i);
+ paragraph.Insert(textOffset, span);
+ textOffset += span.CountChars();
+ }
+
if (!fParagraphs.Replace(index, paragraph))
return B_NO_MEMORY;
+
paragraphCount++;
}

diff --git a/src/apps/haikudepot/textview/TextDocument.h
b/src/apps/haikudepot/textview/TextDocument.h
index 6db9fb9..1029566 100644
--- a/src/apps/haikudepot/textview/TextDocument.h
+++ b/src/apps/haikudepot/textview/TextDocument.h
@@ -26,8 +26,8 @@ class TextDocument : public BReferenceable {
public:
TextDocument();
TextDocument(
- const
CharacterStyle& characterStyle,
- const
ParagraphStyle& paragraphStyle);
+
CharacterStyle characterStyle,
+
ParagraphStyle paragraphStyle);

TextDocument(const TextDocument& other);

TextDocument& operator=(const TextDocument&
other);
@@ -37,10 +37,10 @@ public:
// Text insertion and removing
status_t Insert(int32
textOffset, const BString& text);
status_t Insert(int32
textOffset, const BString& text,
- const
CharacterStyle& style);
+
CharacterStyle style);
status_t Insert(int32
textOffset, const BString& text,
- const
CharacterStyle& characterStyle,
- const
ParagraphStyle& paragraphStyle);
+
CharacterStyle characterStyle,
+
ParagraphStyle paragraphStyle);

status_t Remove(int32
textOffset, int32 length);

@@ -48,11 +48,13 @@ public:
const
BString& text);
status_t Replace(int32
textOffset, int32 length,
const
BString& text,
- const
CharacterStyle& style);
+
CharacterStyle style);
status_t Replace(int32
textOffset, int32 length,
const
BString& text,
- const
CharacterStyle& characterStyle,
- const
ParagraphStyle& paragraphStyle);
+
CharacterStyle characterStyle,
+
ParagraphStyle paragraphStyle);
+ status_t Replace(int32
textOffset, int32 length,
+
TextDocumentRef document);

// Style access
const CharacterStyle& CharacterStyleAt(int32
textOffset) const;
@@ -62,6 +64,8 @@ public:
const ParagraphList& Paragraphs() const
{
return fParagraphs; }

+ int32 CountParagraphs() const;
+
int32 ParagraphIndexFor(int32
textOffset,
int32&
paragraphOffset) const;

@@ -82,18 +86,22 @@ public:

void PrintToStream() const;

+ // Support
+ static TextDocumentRef NormalizeText(const BString& text,
+
CharacterStyle characterStyle,
+
ParagraphStyle paragraphStyle);
+
// Listener support
- bool AddListener(const
TextListenerRef& listener);
- bool RemoveListener(const
TextListenerRef& listener);
+ bool
AddListener(TextListenerRef listener);
+ bool
RemoveListener(TextListenerRef listener);
bool AddUndoListener(
- const
UndoableEditListenerRef& listener);
+
UndoableEditListenerRef listener);
bool RemoveUndoListener(
- const
UndoableEditListenerRef& listener);
+
UndoableEditListenerRef listener);

private:
- status_t _Insert(int32
textOffset, const BString& text,
- const
CharacterStyle& characterStyle,
- const
ParagraphStyle& paragraphStyle,
+ status_t _Insert(int32
textOffset,
+
TextDocumentRef document,
int32&
firstParagraph,
int32&
paragraphCount);
status_t _Remove(int32
textOffset, int32 length,

############################################################################

Revision: hrev49658
Commit: 5f80d48a76353e7bf18a7ad69462974e0db1d455
URL: http://cgit.haiku-os.org/haiku/commit/?id=5f80d48a7635
Author: Stephan Aßmus <superstippi@xxxxxx>
Date: Sun Sep 20 20:18:10 2015 UTC

TextDocument: Extended comment in _Insert().

----------------------------------------------------------------------------

diff --git a/src/apps/haikudepot/textview/TextDocument.cpp
b/src/apps/haikudepot/textview/TextDocument.cpp
index 3ead9bc..0cce1b4 100644
--- a/src/apps/haikudepot/textview/TextDocument.cpp
+++ b/src/apps/haikudepot/textview/TextDocument.cpp
@@ -545,7 +545,9 @@ TextDocument::_Insert(int32 textOffset, TextDocumentRef
document,
// Insert back the second paragraph-part
if (paragraph2.IsEmpty()) {
// Make sure Paragraph has at least one TextSpan, even
- // if its empty.
+ // if its empty. This handles the case of inserting a
+ // line-break at the end of the document. It than needs
to
+ // have a new, empty paragraph at the end.
const TextSpanList& spans = paragraph1.TextSpans();
const TextSpan& span = spans.LastItem();
if (!paragraph2.Append(TextSpan("", span.Style())))


Other related posts:

  • » [haiku-commits] haiku: hrev49658 - src/apps/haikudepot/textview - superstippi