From 300c690eb6647ffcd727a0bbbe2256e7c0e6476e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stephan=20A=C3=9Fmus?= Date: Sun, 19 Jan 2014 23:04:50 +0100 Subject: [PATCH] Text stuff: Fixed various issues with editing. * Insert/Remove now works for simple typing. * Inserting multiple paragaphs not yet tested. * Renamed TextSpan::CharCount() to CountChars() for consistency. --- src/apps/haiku-depot/textview/Paragraph.cpp | 24 ++-- .../haiku-depot/textview/ParagraphLayout.cpp | 6 +- .../haiku-depot/textview/TextDocument.cpp | 116 +++++++++++++++--- src/apps/haiku-depot/textview/TextDocument.h | 16 +-- src/apps/haiku-depot/textview/TextEditor.cpp | 6 + src/apps/haiku-depot/textview/TextSpan.h | 2 +- 6 files changed, 127 insertions(+), 43 deletions(-) diff --git a/src/apps/haiku-depot/textview/Paragraph.cpp b/src/apps/haiku-depot/textview/Paragraph.cpp index 768d20864b..3543b80170 100644 --- a/src/apps/haiku-depot/textview/Paragraph.cpp +++ b/src/apps/haiku-depot/textview/Paragraph.cpp @@ -105,9 +105,9 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan) int32 index = 0; while (index < fTextSpans.CountItems()) { const TextSpan& span = fTextSpans.ItemAtFast(index); - if (offset - span.CharCount() < 0) + if (offset - span.CountChars() < 0) break; - offset -= span.CharCount(); + offset -= span.CountChars(); index++; } @@ -126,7 +126,7 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan) // Try to merge with TextSpan before if offset == 0 && index > 0 TextSpan span = fTextSpans.ItemAtFast(index - 1); if (span.Style() == newSpan.Style()) { - span.Insert(span.CharCount(), newSpan.Text()); + span.Insert(span.CountChars(), newSpan.Text()); return fTextSpans.Replace(index - 1, span); } } @@ -136,7 +136,7 @@ Paragraph::Insert(int32 offset, const TextSpan& newSpan) // Split the span, TextSpan spanBefore = span.SubSpan(0, offset); - TextSpan spanAfter = span.SubSpan(offset, span.CharCount() - offset); + TextSpan spanAfter = span.SubSpan(offset, span.CountChars() - offset); return fTextSpans.Replace(index, spanBefore) && fTextSpans.Add(newSpan, index + 1) @@ -153,9 +153,9 @@ Paragraph::Remove(int32 offset, int32 length) int32 index = 0; while (index < fTextSpans.CountItems()) { const TextSpan& span = fTextSpans.ItemAtFast(index); - if (offset - span.CharCount() < 0) + if (offset - span.CountChars() < 0) break; - offset -= span.CharCount(); + offset -= span.CountChars(); index++; } @@ -163,7 +163,7 @@ Paragraph::Remove(int32 offset, int32 length) return false; TextSpan span(fTextSpans.ItemAtFast(index)); - int32 removeLength = std::min(span.CharCount() - offset, length); + int32 removeLength = std::min(span.CountChars() - offset, length); span.Remove(offset, removeLength); fTextSpans.Replace(index, span); length -= removeLength; @@ -171,7 +171,7 @@ Paragraph::Remove(int32 offset, int32 length) // Remove more spans if necessary while (length > 0 && index < fTextSpans.CountItems()) { - int32 spanLength = fTextSpans.ItemAtFast(index).CharCount(); + int32 spanLength = fTextSpans.ItemAtFast(index).CountChars(); if (spanLength <= length) { fTextSpans.Remove(index); length -= spanLength; @@ -182,7 +182,7 @@ Paragraph::Remove(int32 offset, int32 length) removeLength, spanLength - removeLength); // Try to merge with first span, otherwise replace span at index if (lastSpan.Style() == span.Style()) { - span.Insert(span.CharCount(), lastSpan.Text()); + span.Insert(span.CountChars(), lastSpan.Text()); fTextSpans.Replace(index - 1, span); } else { fTextSpans.Replace(index, lastSpan); @@ -193,7 +193,7 @@ Paragraph::Remove(int32 offset, int32 length) } // See if anything from the TextSpan at offset remained - if (span.CharCount() == 0) + if (span.CountChars() == 0) fTextSpans.Remove(index - 1); return true; @@ -213,7 +213,7 @@ Paragraph::Length() const int32 length = 0; for (int32 i = fTextSpans.CountItems() - 1; i >= 0; i--) { const TextSpan& span = fTextSpans.ItemAtFast(i); - length += span.CharCount(); + length += span.CountChars(); } return length; } @@ -237,7 +237,7 @@ Paragraph::GetText(int32 start, int32 length) const int32 count = fTextSpans.CountItems(); for (int32 i = 0; i < count; i++) { const TextSpan& span = fTextSpans.ItemAtFast(i); - int32 spanLength = span.CharCount(); + int32 spanLength = span.CountChars(); if (spanLength == 0) continue; if (start > spanLength) { diff --git a/src/apps/haiku-depot/textview/ParagraphLayout.cpp b/src/apps/haiku-depot/textview/ParagraphLayout.cpp index fe9ccc68b2..fc926c8d16 100644 --- a/src/apps/haiku-depot/textview/ParagraphLayout.cpp +++ b/src/apps/haiku-depot/textview/ParagraphLayout.cpp @@ -792,7 +792,7 @@ ParagraphLayout::_ApplyAlignment() bool ParagraphLayout::_AppendGlyphInfos(const TextSpan& span) { - int charCount = span.CharCount(); + int charCount = span.CountChars(); if (charCount == 0) return true; @@ -861,7 +861,7 @@ ParagraphLayout::_FinalizeLine(int lineStart, int lineEnd, int lineIndex, spanIndex++; const TextSpan& span = fTextSpans.ItemAt(spanIndex); spanStart = spanEnd; - spanEnd += span.CharCount(); + spanEnd += span.CountChars(); addSpan = true; } @@ -910,7 +910,7 @@ ParagraphLayout::_DrawLine(BView* view, const BPoint& offset, for (int i = 0; i < spanCount; i++) { const TextSpan& span = line.layoutedSpans.ItemAtFast(i); _DrawSpan(view, offset, span, textOffset); - textOffset += span.CharCount(); + textOffset += span.CountChars(); } } diff --git a/src/apps/haiku-depot/textview/TextDocument.cpp b/src/apps/haiku-depot/textview/TextDocument.cpp index 02043814f6..26f5daaa96 100644 --- a/src/apps/haiku-depot/textview/TextDocument.cpp +++ b/src/apps/haiku-depot/textview/TextDocument.cpp @@ -70,24 +70,102 @@ TextDocument::operator!=(const TextDocument& other) const status_t -TextDocument::Insert(int32 offset, const BString& text) +TextDocument::Insert(int32 textOffset, const BString& text) { - return Insert(offset, text, CharacterStyleAt(offset)); + return Insert(textOffset, text, CharacterStyleAt(textOffset)); } status_t -TextDocument::Insert(int32 offset, const BString& text, const CharacterStyle& style) +TextDocument::Insert(int32 textOffset, const BString& text, + const CharacterStyle& style) { - return Insert(offset, text, style, ParagraphStyleAt(offset)); + return Insert(textOffset, text, style, ParagraphStyleAt(textOffset)); } status_t -TextDocument::Insert(int32 offset, const BString& text, - const CharacterStyle& CharacterStyle, const ParagraphStyle& paragraphStyle) +TextDocument::Insert(int32 textOffset, const BString& text, + const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle) { - return Replace(offset, 0, text, CharacterStyle, paragraphStyle); + int32 paragraphOffset; + int32 index = ParagraphIndexFor(textOffset, paragraphOffset); + if (index < 0) + return B_BAD_VALUE; + + textOffset -= paragraphOffset; + + bool hasLineBreaks = text.FindFirst('\n', 0) >= 0; + + 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); + } + } + + 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) { + if (!paragraph1.Append(span)) + return B_NO_MEMORY; + if (paragraph1.Length() > 0) { + if (!fParagraphs.Add(paragraph1, index)) + return B_NO_MEMORY; + index++; + } + paragraph1 = Paragraph(paragraphStyle); + } else { + if (!paragraph2.Prepend(span)) + return B_NO_MEMORY; + if (paragraph2.Length() > 0) { + if (!fParagraphs.Add(paragraph2, index)) + return B_NO_MEMORY; + index++; + } + } + + chunkStart = chunkEnd + 1; + } + } else { + Paragraph paragraph(ParagraphAt(index)); + paragraph.Insert(textOffset, TextSpan(text, characterStyle)); + if (!fParagraphs.Replace(index, paragraph)) + return B_NO_MEMORY; + } + + return B_OK; } @@ -165,31 +243,30 @@ TextDocument::Remove(int32 textOffset, int32 length) status_t -TextDocument::Replace(int32 offset, int32 length, const BString& text) +TextDocument::Replace(int32 textOffset, int32 length, const BString& text) { - return Replace(offset, length, text, CharacterStyleAt(offset)); + return Replace(textOffset, length, text, CharacterStyleAt(textOffset)); } status_t -TextDocument::Replace(int32 offset, int32 length, const BString& text, +TextDocument::Replace(int32 textOffset, int32 length, const BString& text, const CharacterStyle& style) { - return Replace(offset, length, text, style, ParagraphStyleAt(offset)); + return Replace(textOffset, length, text, style, + ParagraphStyleAt(textOffset)); } status_t -TextDocument::Replace(int32 offset, int32 length, const BString& text, - const CharacterStyle& CharacterStyle, const ParagraphStyle& paragraphStyle) +TextDocument::Replace(int32 textOffset, int32 length, const BString& text, + const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle) { - status_t ret = Remove(offset, length); + status_t ret = Remove(textOffset, length); if (ret != B_OK) return ret; - // TODO: ... - - return B_ERROR; + return Insert(textOffset, text, characterStyle, paragraphStyle); } @@ -208,9 +285,10 @@ TextDocument::CharacterStyleAt(int32 textOffset) const int32 index = 0; while (index < spans.CountItems()) { const TextSpan& span = spans.ItemAtFast(index); - if (textOffset - span.CharCount() < 0) + if (textOffset - span.CountChars() < 0) return span.Style(); - textOffset -= span.CharCount(); + textOffset -= span.CountChars(); + index++; } return fDefaultCharacterStyle; diff --git a/src/apps/haiku-depot/textview/TextDocument.h b/src/apps/haiku-depot/textview/TextDocument.h index 16154f1335..d48d8bfec8 100644 --- a/src/apps/haiku-depot/textview/TextDocument.h +++ b/src/apps/haiku-depot/textview/TextDocument.h @@ -28,21 +28,21 @@ public: bool operator!=(const TextDocument& other) const; // Text insertion and removing - status_t Insert(int32 offset, const BString& text); - status_t Insert(int32 offset, const BString& text, + status_t Insert(int32 textOffset, const BString& text); + status_t Insert(int32 textOffset, const BString& text, const CharacterStyle& style); - status_t Insert(int32 offset, const BString& text, + status_t Insert(int32 textOffset, const BString& text, const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle); - status_t Remove(int32 offset, int32 length); + status_t Remove(int32 textOffset, int32 length); - status_t Replace(int32 offset, int32 length, + status_t Replace(int32 textOffset, int32 length, const BString& text); - status_t Replace(int32 offset, int32 length, + status_t Replace(int32 textOffset, int32 length, const BString& text, const CharacterStyle& style); - status_t Replace(int32 offset, int32 length, + status_t Replace(int32 textOffset, int32 length, const BString& text, const CharacterStyle& characterStyle, const ParagraphStyle& paragraphStyle); @@ -68,7 +68,7 @@ public: // Query information int32 Length() const; - BString GetText(int32 start, int32 length) const; + BString GetText(int32 textOffset, int32 length) const; private: ParagraphList fParagraphs; diff --git a/src/apps/haiku-depot/textview/TextEditor.cpp b/src/apps/haiku-depot/textview/TextEditor.cpp index 62b46ea80c..9d9f4cd952 100644 --- a/src/apps/haiku-depot/textview/TextEditor.cpp +++ b/src/apps/haiku-depot/textview/TextEditor.cpp @@ -6,6 +6,7 @@ #include "TextEditor.h" #include +#include TextEditor::TextEditor() @@ -230,6 +231,11 @@ TextEditor::KeyDown(KeyEvent event) if (event.bytes != NULL && event.length > 0) { // Handle null-termintating the string BString text(event.bytes, event.length); + + // Remove selection, if any + if (HasSelection()) + Remove(SelectionStart(), SelectionLength()); + Insert(fSelection.Caret(), text); } break; diff --git a/src/apps/haiku-depot/textview/TextSpan.h b/src/apps/haiku-depot/textview/TextSpan.h index b6625256d5..6387b3c933 100644 --- a/src/apps/haiku-depot/textview/TextSpan.h +++ b/src/apps/haiku-depot/textview/TextSpan.h @@ -30,7 +30,7 @@ public: inline const CharacterStyle& Style() const { return fStyle; } - inline int32 CharCount() const + inline int32 CountChars() const { return fCharCount; } bool Insert(int32 offset, const BString& text);