274 lines
4.8 KiB
C++
274 lines
4.8 KiB
C++
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include "KUndoBuffer.h"
|
|
|
|
|
|
KUndoItem::KUndoItem(const char* redo_text, int32 length, int32 offset,
|
|
undo_type history, int32 cursor_pos)
|
|
{
|
|
Offset = offset;
|
|
Length = length;
|
|
History = history;
|
|
CursorPos = cursor_pos;
|
|
|
|
if (redo_text != NULL) {
|
|
RedoText = (char*)malloc(length);
|
|
|
|
if (RedoText != NULL) {
|
|
memcpy(RedoText, redo_text, length);
|
|
fStatus = B_OK;
|
|
} else
|
|
fStatus = B_ERROR;
|
|
}
|
|
}
|
|
|
|
|
|
KUndoItem::~KUndoItem()
|
|
{
|
|
free(RedoText);
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoItem::InitCheck()
|
|
{
|
|
return fStatus;
|
|
}
|
|
|
|
|
|
void
|
|
KUndoItem::Merge(const char* text, int32 length)
|
|
{
|
|
RedoText = (char*)realloc(RedoText, Length + length);
|
|
memcpy(&RedoText[Length], text, length);
|
|
Length += length;
|
|
}
|
|
|
|
|
|
KUndoBuffer::KUndoBuffer():BList(1024)
|
|
{
|
|
fIndex = 0;
|
|
Off();
|
|
fNewItem = true;
|
|
}
|
|
|
|
|
|
KUndoBuffer::~KUndoBuffer()
|
|
{
|
|
MakeEmpty();
|
|
}
|
|
|
|
|
|
bool
|
|
KUndoBuffer::AddItem(KUndoItem* item, int32 index)
|
|
{
|
|
for (int32 i = CountItems() - 1; i >= index; i--)
|
|
RemoveItem(i);
|
|
|
|
return AddItem(item);
|
|
}
|
|
|
|
|
|
bool
|
|
KUndoBuffer::AddItem(KUndoItem* item)
|
|
{
|
|
return BList::AddItem(item);
|
|
}
|
|
|
|
|
|
void
|
|
KUndoBuffer::MakeEmpty(void)
|
|
{
|
|
for (int32 i = CountItems() - 1; i >= 0; i--)
|
|
RemoveItem(i);
|
|
}
|
|
|
|
|
|
KUndoItem*
|
|
KUndoBuffer::RemoveItem(int32 index)
|
|
{
|
|
if (fIndex >= CountItems())
|
|
fIndex--;
|
|
delete this->ItemAt(index);
|
|
return (KUndoItem*)BList::RemoveItem(index);
|
|
}
|
|
|
|
|
|
KUndoItem*
|
|
KUndoBuffer::ItemAt(int32 index) const
|
|
{
|
|
return (KUndoItem*)BList::ItemAt(index);
|
|
}
|
|
|
|
|
|
void
|
|
KUndoBuffer::On()
|
|
{
|
|
fNoTouch = false;
|
|
}
|
|
|
|
|
|
void
|
|
KUndoBuffer::Off()
|
|
{
|
|
fNoTouch = true;
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoBuffer::NewUndo(const char* text, int32 length, int32 offset,
|
|
undo_type history, int32 cursor_pos)
|
|
{
|
|
KUndoItem* NewUndoItem = new KUndoItem(text, length, offset, history,
|
|
cursor_pos);
|
|
|
|
status_t status = NewUndoItem->InitCheck();
|
|
if (status != B_OK) {
|
|
delete NewUndoItem;
|
|
return status;
|
|
}
|
|
AddItem(NewUndoItem, fIndex);
|
|
fIndex++;
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoBuffer::AddUndo(const char* text, int32 length, int32 offset,
|
|
undo_type history, int32 cursor_pos)
|
|
{
|
|
if (fNoTouch)
|
|
return B_OK;
|
|
|
|
status_t status = B_OK;
|
|
|
|
if (fNewItem || fIndex < CountItems() || CountItems() == 0) {
|
|
status = NewUndo(text, length, offset, history, cursor_pos);
|
|
fNewItem = false;
|
|
} else {
|
|
KUndoItem* CurrentUndoItem;
|
|
CurrentUndoItem = ItemAt(fIndex - 1);
|
|
if (CurrentUndoItem != NULL) {
|
|
int32 c_length = CurrentUndoItem->Length;
|
|
int32 c_offset = CurrentUndoItem->Offset;
|
|
undo_type c_history = CurrentUndoItem->History;
|
|
if (c_history == history) {
|
|
switch (c_history) {
|
|
case K_INSERTED:
|
|
case K_REPLACED:
|
|
if ((c_offset + c_length) == offset)
|
|
CurrentUndoItem->Merge(text, length);
|
|
else {
|
|
status = NewUndo(text, length, offset, history,
|
|
cursor_pos);
|
|
}
|
|
break;
|
|
case K_DELETED:
|
|
status = NewUndo(text, length, offset, history,
|
|
cursor_pos);
|
|
break;
|
|
}
|
|
} else
|
|
status = NewUndo(text, length, offset, history, cursor_pos);
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoBuffer::MakeNewUndoItem()
|
|
{
|
|
if (fIndex >= CountItems()) {
|
|
fNewItem = true;
|
|
return B_OK;
|
|
}
|
|
return B_ERROR;
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoBuffer::Undo(char** text, int32* length, int32* offset,
|
|
undo_type* history, int32* cursor_pos)
|
|
{
|
|
KUndoItem* undoItem;
|
|
status_t status = B_ERROR;
|
|
|
|
if (fIndex > 0) {
|
|
undoItem = ItemAt(fIndex - 1);
|
|
if (undoItem != NULL) {
|
|
*text = undoItem->RedoText;
|
|
*length = undoItem->Length;
|
|
*offset = undoItem->Offset;
|
|
*history = undoItem->History;
|
|
*cursor_pos = undoItem->CursorPos + undoItem->Length;
|
|
status = B_OK;
|
|
}
|
|
fIndex--;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
status_t
|
|
KUndoBuffer::Redo(char** text, int32* length, int32* offset,
|
|
undo_type* history, int32* cursor_pos, bool* replaced)
|
|
{
|
|
KUndoItem* undoItem;
|
|
status_t status = B_ERROR;
|
|
|
|
if (fIndex < CountItems()) {
|
|
undoItem = ItemAt(fIndex);
|
|
if (undoItem != NULL) {
|
|
*text = undoItem->RedoText;
|
|
*length = undoItem->Length;
|
|
*offset = undoItem->Offset;
|
|
*history = undoItem->History;
|
|
*cursor_pos = undoItem->CursorPos;
|
|
if (fIndex + 1 < CountItems())
|
|
*replaced = ItemAt(fIndex + 1)->History == K_REPLACED;
|
|
else
|
|
*replaced = false;
|
|
status = B_OK;
|
|
}
|
|
fIndex++;
|
|
}
|
|
return status;
|
|
}
|
|
|
|
|
|
void
|
|
KUndoBuffer::PrintToStream()
|
|
{
|
|
for (int32 i = 0; i < CountItems(); i++) {
|
|
KUndoItem* item = ItemAt(i);
|
|
printf("%3.3d ", (int)i);
|
|
switch (item->History) {
|
|
case K_INSERTED:
|
|
printf("INSERTED ");
|
|
break;
|
|
case K_DELETED:
|
|
printf("DELETED ");
|
|
break;
|
|
case K_REPLACED:
|
|
printf("REPLACED ");
|
|
break;
|
|
}
|
|
printf("Offset = %d ", (int)item->Offset);
|
|
printf("Length = %d ", (int)item->Length);
|
|
printf("CursorPos = %d ", (int)item->CursorPos);
|
|
printf("RedoText = '");
|
|
for (int32 j = 0; j < item->Length; j++) {
|
|
uchar c = (uchar)item->RedoText[j];
|
|
if (c >= 0x20)
|
|
printf("%c", c);
|
|
else
|
|
printf("?");
|
|
}
|
|
printf("'\n");
|
|
}
|
|
}
|
|
|