Text stuff: Support extracting sub-paragraphs and documents
* Also some WIP towards integrating TextListener. * Everything untested. * Fixed a bug where copying to the clipboard had an extra line-break after each paragraph since the recent changes that made sure each paragraph ends in a line-break.
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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("</document>\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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,9 +10,14 @@
|
||||
#include "CharacterStyle.h"
|
||||
#include "List.h"
|
||||
#include "Paragraph.h"
|
||||
#include "TextListener.h"
|
||||
|
||||
|
||||
typedef List<Paragraph, false> ParagraphList;
|
||||
typedef List<Paragraph, false> ParagraphList;
|
||||
typedef List<TextListenerRef, false> TextListenerList;
|
||||
|
||||
class TextDocument;
|
||||
typedef BReference<TextDocument> 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<TextDocument> TextDocumentRef;
|
||||
|
||||
|
||||
#endif // TEXT_DOCUMENT_H
|
||||
|
||||
@@ -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());
|
||||
|
||||
|
||||
Reference in New Issue
Block a user