* Copyright 2003-2008, Haiku, Inc. All Rights Reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
* Stefano Ceccherini (burton666@libero.it)
*/
#include "UndoBuffer.h"
#include "utf8_functions.h"
#include <Clipboard.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
BTextView::UndoBuffer::UndoBuffer(BTextView* textView, undo_state state)
:
fTextView(textView),
fTextData(NULL),
fRunArray(NULL),
fRunArrayLength(0),
fRedo(false),
fState(state)
{
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);
}
BTextView::UndoBuffer::~UndoBuffer()
{
free(fTextData);
BTextView::FreeRunArray(fRunArray);
}
void
BTextView::UndoBuffer::Undo(BClipboard* clipboard)
{
fRedo ? RedoSelf(clipboard) : UndoSelf(clipboard);
fRedo = !fRedo;
}
undo_state
BTextView::UndoBuffer::State(bool* _isRedo) const
{
*_isRedo = fRedo;
return fState;
}
void
BTextView::UndoBuffer::UndoSelf(BClipboard* clipboard)
{
fTextView->Select(fStart, fStart);
fTextView->Insert(fTextData, fTextLength, fRunArray);
fTextView->Select(fStart, fStart);
}
void
BTextView::UndoBuffer::RedoSelf(BClipboard* clipboard)
{
}
BTextView::CutUndoBuffer::CutUndoBuffer(BTextView* textView)
: BTextView::UndoBuffer(textView, B_UNDO_CUT)
{
}
BTextView::CutUndoBuffer::~CutUndoBuffer()
{
}
void
BTextView::CutUndoBuffer::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();
}
}
BTextView::PasteUndoBuffer::PasteUndoBuffer(BTextView* textView,
const char* text, int32 textLen, text_run_array* runArray,
int32 runArrayLen)
: BTextView::UndoBuffer(textView, B_UNDO_PASTE),
fPasteText(NULL),
fPasteTextLength(textLen),
fPasteRunArray(NULL)
{
fPasteText = (char*)malloc(fPasteTextLength);
memcpy(fPasteText, text, fPasteTextLength);
if (runArray)
fPasteRunArray = BTextView::CopyRunArray(runArray);
}
BTextView::PasteUndoBuffer::~PasteUndoBuffer()
{
free(fPasteText);
BTextView::FreeRunArray(fPasteRunArray);
}
void
BTextView::PasteUndoBuffer::UndoSelf(BClipboard* clipboard)
{
fTextView->Select(fStart, fStart);
fTextView->Delete(fStart, fStart + fPasteTextLength);
fTextView->Insert(fTextData, fTextLength, fRunArray);
fTextView->Select(fStart, fEnd);
}
void
BTextView::PasteUndoBuffer::RedoSelf(BClipboard* clipboard)
{
fTextView->Select(fStart, fStart);
fTextView->Delete(fStart, fEnd);
fTextView->Insert(fPasteText, fPasteTextLength, fPasteRunArray);
fTextView->Select(fStart + fPasteTextLength, fStart + fPasteTextLength);
}
BTextView::ClearUndoBuffer::ClearUndoBuffer(BTextView* textView)
: BTextView::UndoBuffer(textView, B_UNDO_CLEAR)
{
}
BTextView::ClearUndoBuffer::~ClearUndoBuffer()
{
}
void
BTextView::ClearUndoBuffer::RedoSelf(BClipboard* clipboard)
{
fTextView->Select(fStart, fStart);
fTextView->Delete(fStart, fEnd);
}
BTextView::DropUndoBuffer::DropUndoBuffer(BTextView* textView,
char const* text, int32 textLen, text_run_array* runArray,
int32 runArrayLen, int32 location, bool internalDrop)
: BTextView::UndoBuffer(textView, B_UNDO_DROP),
fDropText(NULL),
fDropTextLength(textLen),
fDropRunArray(NULL)
{
fInternalDrop = internalDrop;
fDropLocation = location;
fDropText = (char*)malloc(fDropTextLength);
memcpy(fDropText, text, fDropTextLength);
if (runArray)
fDropRunArray = BTextView::CopyRunArray(runArray);
if (fInternalDrop && fDropLocation >= fEnd)
fDropLocation -= fDropTextLength;
}
BTextView::DropUndoBuffer::~DropUndoBuffer()
{
free(fDropText);
BTextView::FreeRunArray(fDropRunArray);
}
void
BTextView::DropUndoBuffer::UndoSelf(BClipboard* )
{
fTextView->Select(fDropLocation, fDropLocation);
fTextView->Delete(fDropLocation, fDropLocation + fDropTextLength);
if (fInternalDrop) {
fTextView->Select(fStart, fStart);
fTextView->Insert(fTextData, fTextLength, fRunArray);
}
fTextView->Select(fStart, fEnd);
}
void
BTextView::DropUndoBuffer::RedoSelf(BClipboard* )
{
if (fInternalDrop) {
fTextView->Select(fStart, fStart);
fTextView->Delete(fStart, fEnd);
}
fTextView->Select(fDropLocation, fDropLocation);
fTextView->Insert(fDropText, fDropTextLength, fDropRunArray);
fTextView->Select(fDropLocation, fDropLocation + fDropTextLength);
}
BTextView::TypingUndoBuffer::TypingUndoBuffer(BTextView* textView)
: BTextView::UndoBuffer(textView, B_UNDO_TYPING),
fTypedText(NULL),
fTypedStart(fStart),
fTypedEnd(fEnd),
fUndone(0)
{
}
BTextView::TypingUndoBuffer::~TypingUndoBuffer()
{
free(fTypedText);
}
void
BTextView::TypingUndoBuffer::UndoSelf(BClipboard* clipboard)
{
int32 len = fTypedEnd - fTypedStart;
free(fTypedText);
fTypedText = (char*)malloc(len);
memcpy(fTypedText, fTextView->Text() + fTypedStart, len);
fTextView->Select(fTypedStart, fTypedStart);
fTextView->Delete(fTypedStart, fTypedEnd);
fTextView->Insert(fTextData, fTextLength);
fTextView->Select(fStart, fEnd);
fUndone++;
}
void
BTextView::TypingUndoBuffer::RedoSelf(BClipboard* clipboard)
{
fTextView->Select(fTypedStart, fTypedStart);
fTextView->Delete(fTypedStart, fTypedStart + fTextLength);
fTextView->Insert(fTypedText, fTypedEnd - fTypedStart);
fUndone--;
}
void
BTextView::TypingUndoBuffer::InputCharacter(int32 len)
{
int32 start, end;
fTextView->GetSelection(&start, &end);
if (start != fTypedEnd || end != fTypedEnd)
_Reset();
fTypedEnd += len;
}
void
BTextView::TypingUndoBuffer::_Reset()
{
free(fTextData);
fTextView->GetSelection(&fStart, &fEnd);
fTextLength = fEnd - fStart;
fTypedStart = fStart;
fTypedEnd = fStart;
fTextData = (char*)malloc(fTextLength);
memcpy(fTextData, fTextView->Text() + fStart, fTextLength);
free(fTypedText);
fTypedText = NULL;
fRedo = false;
fUndone = 0;
}
void
BTextView::TypingUndoBuffer::BackwardErase()
{
int32 start, end;
fTextView->GetSelection(&start, &end);
const char* text = fTextView->Text();
int32 charLen = UTF8PreviousCharLen(text + start, text);
if (start != fTypedEnd || end != fTypedEnd) {
_Reset();
if (start != end)
return;
}
char* buffer = (char*)malloc(fTextLength + charLen);
memcpy(buffer + charLen, fTextData, fTextLength);
fTypedStart = start - charLen;
start = fTypedStart;
for (int32 x = 0; x < charLen; x++)
buffer[x] = fTextView->ByteAt(start + x);
free(fTextData);
fTextData = buffer;
fTextLength += charLen;
fTypedEnd -= charLen;
}
void
BTextView::TypingUndoBuffer::ForwardErase()
{
int32 start, end;
fTextView->GetSelection(&start, &end);
int32 charLen = UTF8NextCharLen(fTextView->Text() + start);
if (start != fTypedEnd || end != fTypedEnd || fUndone > 0) {
_Reset();
if (fStart == fEnd) {
free(fTextData);
fTextLength = charLen;
fTextData = (char*)malloc(fTextLength);
for (int32 x = 0; x < charLen; x++)
fTextData[x] = fTextView->ByteAt(start + x);
}
} else {
int32 newLength = fTextLength + charLen;
char* buffer = (char*)malloc(newLength);
memcpy(buffer, fTextData, fTextLength);
if (fTextLength < newLength) {
for (int32 x = 0; x < charLen; x++)
buffer[fTextLength + x] = fTextView->ByteAt(start + x);
}
fTextLength = newLength;
free(fTextData);
fTextData = buffer;
}
}