diff --git a/src/kits/interface/BTextView/TextView.cpp b/src/kits/interface/BTextView/TextView.cpp index 8a831adbe2..a41aa29241 100644 --- a/src/kits/interface/BTextView/TextView.cpp +++ b/src/kits/interface/BTextView/TextView.cpp @@ -26,7 +26,6 @@ // Standard Includes ----------------------------------------------------------- - // System Includes ------------------------------------------------------------- #include #include @@ -42,6 +41,7 @@ #include "TextGapBuffer.h" #include "LineBuffer.h" #include "StyleBuffer.h" +#include "UndoBuffer.h" //#include @@ -142,8 +142,8 @@ prop_list[] = { 0 } }; -sem_id BTextView::sWidthSem; -int32 BTextView::sWidthAtom; +sem_id BTextView::sWidthSem = B_BAD_SEM_ID; // Created/deleted by init/fini_interface_kit +int32 BTextView::sWidthAtom = 0; //------------------------------------------------------------------------------ BTextView::BTextView(BRect frame, const char *name, BRect textRect, @@ -285,6 +285,7 @@ BTextView::~BTextView() delete fLines; delete fStyles; delete fDisallowedChars; + delete fUndo; } //------------------------------------------------------------------------------ BArchivable * @@ -668,7 +669,11 @@ BTextView::MessageReceived(BMessage *message) case B_PASTE: Paste(be_clipboard); break; - + + case B_UNDO: + Undo(be_clipboard); + break; + case B_SET_PROPERTY: case B_GET_PROPERTY: case B_COUNT_PROPERTIES: @@ -975,8 +980,7 @@ BTextView::Delete(int32 startOffset, int32 endOffset) Refresh(startOffset, endOffset, true, true); // draw the caret - if (fActive) - { + if (fActive) { if (!fCaretVisible) InvertCaret(); } @@ -1039,8 +1043,12 @@ BTextView::GoToLine(int32 index) void BTextView::Cut(BClipboard *clipboard) { + delete fUndo; + fUndo = new _BCutUndoBuffer_(this); Copy(clipboard); DeleteText(fSelStart, fSelEnd); + + Refresh(0, LONG_MAX, true, false); } //------------------------------------------------------------------------------ void @@ -1068,18 +1076,27 @@ BTextView::Paste(BClipboard *clipboard) if (clipboard->Lock()) { if ((clip = clipboard->Data()) != NULL) { - const char *text; - ssize_t len; - + const char *text = NULL; + text_run_array * runArray = NULL; + ssize_t len = 0; + ssize_t runLen = 0; + + clip->FindData("application/x-vnd.Be-text_run_array", B_MIME_TYPE, + (const void **)&runArray, &runLen); if (clip->FindData("text/plain", B_MIME_TYPE, (const void **)&text, &len) == B_OK) { DeleteText(fSelStart, fSelEnd); - InsertText(text, len, fSelStart, NULL); - } + InsertText(text, len, fSelStart, runArray); + + delete fUndo; + fUndo = new _BPasteUndoBuffer_(this, text, len, runArray, runLen); + } } clipboard->Unlock(); } + + Refresh(0, LONG_MAX, true, false); } //------------------------------------------------------------------------------ void @@ -1104,7 +1121,7 @@ BTextView::AcceptsPaste(BClipboard *clipboard) be_clipboard->Unlock(); - return (result); + return result; } //------------------------------------------------------------------------------ bool @@ -1941,13 +1958,18 @@ BTextView::IsResizable () const void BTextView::SetDoesUndo(bool undo) { - + if (undo && fUndo == NULL) + fUndo = new _BUndoBuffer_(this, B_UNDO_UNAVAILABLE); + else if (!undo && fUndo != NULL) { + delete fUndo; + fUndo = NULL; + } } //------------------------------------------------------------------------------ bool BTextView::DoesUndo() const { - return false; + return fUndo != NULL; } //------------------------------------------------------------------------------ void @@ -2128,12 +2150,14 @@ BTextView::DeleteText(int32 fromOffset, int32 toOffset) void BTextView::Undo(BClipboard *clipboard) { + if (fUndo) + fUndo->Undo(clipboard); } //------------------------------------------------------------------------------ undo_state BTextView::UndoState(bool *isRedo) const { - return B_UNDO_UNAVAILABLE; + return fUndo == NULL ? B_UNDO_UNAVAILABLE : fUndo->State(isRedo); } //------------------------------------------------------------------------------ void @@ -3133,8 +3157,7 @@ BTextView::PreviousInitialByte(int32 offset) const const char *text = Text(); int count = 6; - for (--offset; (text + offset) > text && count; --offset, --count) - { + for (--offset; (text + offset) > text && count; --offset, --count) { if ((*(text + offset) & 0xc0 ) != 0x80) break; } @@ -3146,16 +3169,13 @@ bool BTextView::GetProperty(BMessage *specifier, int32 form, const char *property, BMessage *reply) { - if (strcmp(property, "Selection") == 0) - { + if (strcmp(property, "Selection") == 0) { reply->what = B_REPLY; reply->AddInt32("result", fSelStart); reply->AddInt32("result", fSelEnd); reply->AddInt32("error", B_OK); return true; - } - else if (strcmp(property, "Text") == 0) - { + } else if (strcmp(property, "Text") == 0) { int32 index, range; char *buffer; @@ -3170,11 +3190,8 @@ BTextView::GetProperty(BMessage *specifier, int32 form, delete buffer; reply->AddInt32("error", B_OK); return true; - } - else if (strcmp(property, "text_run_array") == 0) - { + } else if (strcmp(property, "text_run_array") == 0) return false; - } else return false; } @@ -3183,8 +3200,7 @@ bool BTextView::SetProperty(BMessage *specifier, int32 form, const char *property, BMessage *reply) { - if (strcmp(property, "Selection") == 0) - { + if (strcmp(property, "Selection") == 0) { int32 index, range; specifier->FindInt32("index", &index); @@ -3197,8 +3213,7 @@ BTextView::SetProperty(BMessage *specifier, int32 form, return true; } - else if (strcmp(property, "Text") == 0) - { + else if (strcmp(property, "Text") == 0) { int32 index, range; const char *buffer; @@ -3216,9 +3231,8 @@ BTextView::SetProperty(BMessage *specifier, int32 form, return true; } else if (strcmp(property, "text_run_array") == 0) - { return false; - } + else return false; } @@ -3227,8 +3241,7 @@ bool BTextView::CountProperties(BMessage *specifier, int32 form, const char *property, BMessage *reply) { - if (strcmp(property, "Text") == 0) - { + if (strcmp(property, "Text") == 0) { reply->what = B_REPLY; reply->AddInt32("result", TextLength()); reply->AddInt32("error", B_OK); @@ -3257,14 +3270,14 @@ BTextView::CancelInputMethod() void BTextView::LockWidthBuffer() { - if (atomic_add(&sWidthAtom, -1) <= 0) + if (atomic_add(&sWidthAtom, 1) > 0) acquire_sem(sWidthSem); } //------------------------------------------------------------------------------ void BTextView::UnlockWidthBuffer() { - if (atomic_add(&sWidthAtom, 1) < 0) + if (atomic_add(&sWidthAtom, -1) > 1) release_sem(sWidthSem); } //------------------------------------------------------------------------------ diff --git a/src/kits/interface/BTextView/UndoBuffer.cpp b/src/kits/interface/BTextView/UndoBuffer.cpp new file mode 100644 index 0000000000..dfadaa113b --- /dev/null +++ b/src/kits/interface/BTextView/UndoBuffer.cpp @@ -0,0 +1,168 @@ +#include "UndoBuffer.h" + +#include +#include +#include + +#include + +// ******** _BUndoBuffer_ ******* + +_BUndoBuffer_::_BUndoBuffer_(BTextView *textView, undo_state state) + : + fTextView(textView), + fState(state), + fRedo(false), + fRunArray(NULL), + fRunArrayLength(0) + +{ + fTextView->GetSelection(&fStart, &fEnd); + fTextLength = fEnd - fStart; + + fTextData = (char*)malloc(fTextLength); + memcpy(fTextData, fTextView->Text() + fStart, fTextLength); + + if (fTextView->IsStylable()) + fRunArray = fTextView->RunArray(fStart, fEnd, &fRunArrayLength); +} + + +_BUndoBuffer_::~_BUndoBuffer_() +{ + free(fTextData); + free(fRunArray); +} + + +void +_BUndoBuffer_::Undo(BClipboard *clipboard) +{ + fRedo ? RedoSelf(clipboard) : UndoSelf(clipboard); + + fRedo = !fRedo; +} + + +undo_state +_BUndoBuffer_::State(bool *redo) +{ + *redo = fRedo; + + return fState; +} + + +void +_BUndoBuffer_::UndoSelf(BClipboard *clipboard) +{ + fTextView->Select(fStart, fStart); + fTextView->Insert(fTextData, fTextLength, fRunArray); + fTextView->Select(fStart, fStart); +} + + +void +_BUndoBuffer_::RedoSelf(BClipboard *clipboard) +{ +} + + +// ******** _BCutUndoBuffer_ ******* +_BCutUndoBuffer_::_BCutUndoBuffer_(BTextView *textView) + :_BUndoBuffer_(textView, B_UNDO_CUT) +{ +} + + +_BCutUndoBuffer_::~_BCutUndoBuffer_() +{ +} + + +void +_BCutUndoBuffer_::RedoSelf(BClipboard *clipboard) +{ + BMessage *clip = NULL; + + fTextView->Select(fStart, fStart); + fTextView->Delete(fStart, fEnd); + if (clipboard->Lock()) { + clipboard->Clear(); + if ((clip = clipboard->Data())) { + clip->AddData("text/plain", B_MIME_TYPE, fTextData, fTextLength); + if (fRunArray) + clip->AddData("application/x-vnd.Be-text_run_array", B_MIME_TYPE, + fRunArray, fRunArrayLength); + clipboard->Commit(); + } + clipboard->Unlock(); + } +} + + +// ******** _BPasteUndoBuffer_ ******* +_BPasteUndoBuffer_::_BPasteUndoBuffer_(BTextView *textView, const char *text, + int32 textLen, text_run_array *runArray, int32 runArrayLen) + :_BUndoBuffer_(textView, B_UNDO_PASTE), + fPasteText(NULL), + fPasteTextLength(textLen), + fPasteRunArray(NULL) +{ + fPasteText = (char *)malloc(fPasteTextLength); + memcpy(fPasteText, text, fPasteTextLength); + + if (runArray) { + fPasteRunArray = (text_run_array *)malloc(runArrayLen); + fPasteRunArrayLength = runArrayLen; + memcpy(fPasteRunArray, runArray, runArrayLen); + } +} + + +_BPasteUndoBuffer_::~_BPasteUndoBuffer_() +{ + free(fPasteText); + free(fPasteRunArray); +} + + +void +_BPasteUndoBuffer_::UndoSelf(BClipboard *clipboard) +{ + fTextView->Select(fStart, fStart); + fTextView->Delete(fStart, fStart + fPasteTextLength); + fTextView->Insert(fTextData, fTextLength, fRunArray); + fTextView->Select(fStart, fEnd); +} + + +void +_BPasteUndoBuffer_::RedoSelf(BClipboard *clipboard) +{ + fTextView->Select(fStart, fStart); + fTextView->Delete(fStart, fEnd); + fTextView->Insert(fPasteText, fPasteTextLength, fPasteRunArray); + fTextView->Select(fStart + fPasteTextLength, fStart + fPasteTextLength); +} + + +// ******** _BClearUndoBuffer_ ******* +_BClearUndoBuffer_::_BClearUndoBuffer_(BTextView *textView) + : + _BUndoBuffer_(textView, B_UNDO_CLEAR) +{ +} + + +_BClearUndoBuffer_::~_BClearUndoBuffer_() +{ +} + + +void +_BClearUndoBuffer_::RedoSelf(BClipboard *clipboard) +{ + fTextView->Select(fStart, fStart); + fTextView->Delete(fStart, fEnd); +} diff --git a/src/kits/interface/BTextView/UndoBuffer.h b/src/kits/interface/BTextView/UndoBuffer.h new file mode 100644 index 0000000000..a9938b2b5f --- /dev/null +++ b/src/kits/interface/BTextView/UndoBuffer.h @@ -0,0 +1,74 @@ +#ifndef __UNDOBUFFER_H +#define __UNDOBUFFER_H + +#include + +class BClipboard; +class _BUndoBuffer_ +{ +public: + _BUndoBuffer_(BTextView *, undo_state); + virtual ~_BUndoBuffer_(); + + void Undo(BClipboard *); + undo_state State(bool *); + +protected: + virtual void UndoSelf(BClipboard *); + virtual void RedoSelf(BClipboard *); + + BTextView *fTextView; + int32 fStart; + int32 fEnd; + + char *fTextData; + int32 fTextLength; + text_run_array *fRunArray; + int32 fRunArrayLength; + +private: + undo_state fState; + bool fRedo; +}; + + +// ******** _BCutUndoBuffer_ ******* +class _BCutUndoBuffer_ : public _BUndoBuffer_ +{ +public: + _BCutUndoBuffer_(BTextView *textView); + ~_BCutUndoBuffer_(); +protected: + virtual void RedoSelf(BClipboard *); +}; + + +// ******** _BPasteUndoBuffer_ ******* +class _BPasteUndoBuffer_ : public _BUndoBuffer_ +{ +public: + _BPasteUndoBuffer_(BTextView *, const char *, int32, text_run_array *, int32); + ~_BPasteUndoBuffer_(); +protected: + virtual void UndoSelf(BClipboard *); + virtual void RedoSelf(BClipboard *); +private: + char *fPasteText; + int32 fPasteTextLength; + text_run_array *fPasteRunArray; + int32 fPasteRunArrayLength; +}; + + +// ******** _BClearUndoBuffer_ ******* +class _BClearUndoBuffer_ : public _BUndoBuffer_ +{ +public: + _BClearUndoBuffer_(BTextView *textView); + ~_BClearUndoBuffer_(); +protected: + virtual void RedoSelf(BClipboard *); +}; + + +#endif //__UNDOBUFFER_H