11539Srgrimes#include <stdlib.h>
21539Srgrimes#include <stdio.h>
31539Srgrimes#include <memory.h>
41539Srgrimes#include "KUndoBuffer.h"
51539Srgrimes
61539Srgrimes
71539SrgrimesKUndoItem::KUndoItem(const char* redo_text, int32 length, int32 offset,
81539Srgrimes	undo_type history, int32 cursor_pos)
91539Srgrimes{
101539Srgrimes	Offset = offset;
111539Srgrimes	Length = length;
121539Srgrimes	History = history;
131539Srgrimes	CursorPos = cursor_pos;
141539Srgrimes
151539Srgrimes	if (redo_text != NULL) {
161539Srgrimes		RedoText = (char*)malloc(length);
171539Srgrimes
181539Srgrimes		if (RedoText != NULL) {
191539Srgrimes			memcpy(RedoText, redo_text, length);
201539Srgrimes			fStatus = B_OK;
211539Srgrimes		} else
221539Srgrimes			fStatus = B_ERROR;
231539Srgrimes	}
241539Srgrimes}
251539Srgrimes
261539Srgrimes
271539SrgrimesKUndoItem::~KUndoItem()
281539Srgrimes{
291539Srgrimes	free(RedoText);
301539Srgrimes}
311539Srgrimes
321539Srgrimes
331539Srgrimesstatus_t
341539SrgrimesKUndoItem::InitCheck()
351539Srgrimes{
361539Srgrimes	return fStatus;
371539Srgrimes}
381539Srgrimes
391539Srgrimes
401539Srgrimesvoid
411539SrgrimesKUndoItem::Merge(const char* text, int32 length)
421539Srgrimes{
431539Srgrimes	RedoText = (char*)realloc(RedoText, Length + length);
441539Srgrimes	memcpy(&RedoText[Length], text, length);
451539Srgrimes	Length += length;
461539Srgrimes}
471539Srgrimes
481539Srgrimes
491539SrgrimesKUndoBuffer::KUndoBuffer():BList(1024)
501539Srgrimes{
511539Srgrimes	fIndex = 0;
521539Srgrimes	Off();
531539Srgrimes	fNewItem = true;
541539Srgrimes}
551539Srgrimes
561539Srgrimes
571539SrgrimesKUndoBuffer::~KUndoBuffer()
581539Srgrimes{
591539Srgrimes	MakeEmpty();
601539Srgrimes}
611539Srgrimes
621539Srgrimes
631539Srgrimesbool
641539SrgrimesKUndoBuffer::AddItem(KUndoItem* item, int32 index)
651539Srgrimes{
661539Srgrimes	for (int32 i = CountItems() - 1; i >= index; i--)
67		RemoveItem(i);
68
69	return AddItem(item);
70}
71
72
73bool
74KUndoBuffer::AddItem(KUndoItem* item)
75{
76	return BList::AddItem(item);
77}
78
79
80void
81KUndoBuffer::MakeEmpty(void)
82{
83	for (int32 i = CountItems() - 1; i >= 0; i--)
84		RemoveItem(i);
85}
86
87
88KUndoItem*
89KUndoBuffer::RemoveItem(int32 index)
90{
91	if (fIndex >= CountItems())
92		fIndex--;
93	delete this->ItemAt(index);
94	return (KUndoItem*)BList::RemoveItem(index);
95}
96
97
98KUndoItem*
99KUndoBuffer::ItemAt(int32 index) const
100{
101	return (KUndoItem*)BList::ItemAt(index);
102}
103
104
105void
106KUndoBuffer::On()
107{
108	fNoTouch = false;
109}
110
111
112void
113KUndoBuffer::Off()
114{
115	fNoTouch = true;
116}
117
118
119status_t
120KUndoBuffer::NewUndo(const char* text, int32 length, int32 offset,
121	undo_type history, int32 cursor_pos)
122{
123	KUndoItem* NewUndoItem = new KUndoItem(text, length, offset, history,
124		cursor_pos);
125
126	status_t status = NewUndoItem->InitCheck();
127	if (status != B_OK) {
128		delete NewUndoItem;
129		return status;
130	}
131	AddItem(NewUndoItem, fIndex);
132	fIndex++;
133	return status;
134}
135
136
137status_t
138KUndoBuffer::AddUndo(const char* text, int32 length, int32 offset,
139	undo_type history, int32 cursor_pos)
140{
141	if (fNoTouch)
142		return B_OK;
143
144	status_t status = B_OK;
145
146	if (fNewItem || fIndex < CountItems() || CountItems() == 0) {
147		status = NewUndo(text, length, offset, history, cursor_pos);
148		fNewItem = false;
149	} else {
150		KUndoItem* CurrentUndoItem;
151		CurrentUndoItem = ItemAt(fIndex - 1);
152		if (CurrentUndoItem != NULL) {
153			int32 c_length = CurrentUndoItem->Length;
154			int32 c_offset = CurrentUndoItem->Offset;
155			undo_type c_history = CurrentUndoItem->History;
156			if (c_history == history) {
157				switch (c_history) {
158					case K_INSERTED:
159					case K_REPLACED:
160						if ((c_offset + c_length) == offset)
161							CurrentUndoItem->Merge(text, length);
162						else {
163							status = NewUndo(text, length, offset, history,
164								cursor_pos);
165						}
166						break;
167					case K_DELETED:
168						status = NewUndo(text, length, offset, history,
169							cursor_pos);
170						break;
171				}
172			} else
173				status = NewUndo(text, length, offset, history, cursor_pos);
174		}
175	}
176
177	return status;
178}
179
180
181status_t
182KUndoBuffer::MakeNewUndoItem()
183{
184	if (fIndex >= CountItems()) {
185		fNewItem = true;
186		return B_OK;
187	}
188	return B_ERROR;
189}
190
191
192status_t
193KUndoBuffer::Undo(char** text, int32* length, int32* offset,
194	undo_type* history, int32* cursor_pos)
195{
196	KUndoItem* undoItem;
197	status_t status = B_ERROR;
198
199	if (fIndex > 0) {
200		undoItem = ItemAt(fIndex - 1);
201		if (undoItem != NULL) {
202			*text = undoItem->RedoText;
203			*length = undoItem->Length;
204			*offset = undoItem->Offset;
205			*history = undoItem->History;
206			*cursor_pos = undoItem->CursorPos + undoItem->Length;
207			status = B_OK;
208		}
209		fIndex--;
210	}
211	return status;
212}
213
214
215status_t
216KUndoBuffer::Redo(char** text, int32* length, int32* offset,
217	undo_type* history, int32* cursor_pos, bool* replaced)
218{
219	KUndoItem* undoItem;
220	status_t status = B_ERROR;
221
222	if (fIndex < CountItems()) {
223		undoItem = ItemAt(fIndex);
224		if (undoItem != NULL) {
225			*text = undoItem->RedoText;
226			*length = undoItem->Length;
227			*offset = undoItem->Offset;
228			*history = undoItem->History;
229			*cursor_pos = undoItem->CursorPos;
230			if (fIndex + 1 < CountItems())
231				*replaced = ItemAt(fIndex + 1)->History == K_REPLACED;
232			else
233				*replaced = false;
234			status = B_OK;
235		}
236		fIndex++;
237	}
238	return status;
239}
240
241
242void
243KUndoBuffer::PrintToStream()
244{
245	for (int32 i = 0; i < CountItems(); i++) {
246		KUndoItem* item = ItemAt(i);
247		printf("%3.3d   ", (int)i);
248		switch (item->History) {
249			case K_INSERTED:
250				printf("INSERTED  ");
251				break;
252			case K_DELETED:
253				printf("DELETED   ");
254				break;
255			case K_REPLACED:
256				printf("REPLACED  ");
257				break;
258		}
259		printf("Offset = %d  ", (int)item->Offset);
260		printf("Length = %d  ", (int)item->Length);
261		printf("CursorPos = %d  ", (int)item->CursorPos);
262		printf("RedoText = '");
263		for (int32 j = 0; j < item->Length; j++) {
264			uchar c = (uchar)item->RedoText[j];
265			if (c >= 0x20)
266				printf("%c", c);
267			else
268				printf("?");
269		}
270		printf("'\n");
271	}
272}
273
274