KUndoBuffer.cpp revision 5c6b9eb0
1#include <stdlib.h>
2#include <stdio.h>
3#include <memory.h>
4#include "KUndoBuffer.h"
5
6
7KUndoItem::KUndoItem(const char* redo_text,
8					int32 length,
9					int32 offset,
10					undo_type history,
11					int32 cursor_pos)
12{
13	Offset = offset;
14	Length = length;
15	History = history;
16	CursorPos = cursor_pos;
17
18	if (redo_text!=NULL) {
19		RedoText = (char*)malloc(length);
20		memcpy(RedoText, redo_text, length);
21		if (RedoText!=NULL) {
22			fStatus = B_OK;
23		} else {
24			fStatus = B_ERROR;
25		}
26	}
27}
28
29KUndoItem::~KUndoItem()
30{
31	free(RedoText);
32}
33
34status_t
35KUndoItem::InitCheck()
36{
37	return fStatus;
38}
39
40void
41KUndoItem::Merge(const char* text, int32 length)
42{
43	RedoText = (char*)realloc(RedoText, Length + length);
44	memcpy(&RedoText[Length], text, length);
45	Length += length;
46}
47
48
49KUndoBuffer::KUndoBuffer():BList(1024)
50{
51	fIndex = 0;
52	Off();
53	fNewItem = true;
54}
55
56KUndoBuffer::~KUndoBuffer()
57{
58	MakeEmpty();
59}
60
61
62bool
63KUndoBuffer::AddItem(KUndoItem* item, int32 index)
64{
65	for (int32 i=CountItems()-1; i>=index; i--) {
66		RemoveItem(i);
67	}
68	return AddItem(item);
69}
70
71bool
72KUndoBuffer::AddItem(KUndoItem* item)
73{
74	return BList::AddItem(item);
75}
76
77void
78KUndoBuffer::MakeEmpty(void)
79{
80	for(int32 i=CountItems()-1; i>=0;i--) {
81		RemoveItem(i);
82	}
83}
84
85KUndoItem*
86KUndoBuffer::RemoveItem(int32 index)
87{
88	if (fIndex>=CountItems()) fIndex--;
89	delete this->ItemAt(index);
90	return (KUndoItem*)BList::RemoveItem(index);
91}
92
93KUndoItem*
94KUndoBuffer::ItemAt(int32 index) const
95{
96	return (KUndoItem*)BList::ItemAt(index);
97}
98
99
100void
101KUndoBuffer::On()
102{
103	fNoTouch = false;
104}
105
106void
107KUndoBuffer::Off()
108{
109	fNoTouch = true;
110}
111
112status_t
113KUndoBuffer::NewUndo(const char* text, int32 length, int32 offset,
114	undo_type history, int32 cursor_pos)
115{
116	KUndoItem* NewUndoItem = new KUndoItem(text, length, offset, history,
117		cursor_pos);
118
119	status_t status = NewUndoItem->InitCheck();
120	if ( status != B_OK) {
121		delete NewUndoItem;
122		return status;
123	}
124	AddItem(NewUndoItem, fIndex);
125	fIndex++;
126	return status;
127}
128
129
130status_t
131KUndoBuffer::AddUndo(const char* text, int32 length, int32 offset,
132	undo_type history, int32 cursor_pos)
133{
134	if (fNoTouch)
135		return B_OK;
136
137	status_t status = B_OK;
138
139	if (fNewItem || (fIndex < CountItems()) || (CountItems()==0)) {
140		status = NewUndo(text, length, offset, history, cursor_pos);
141		fNewItem = false;
142	} else {
143		KUndoItem* CurrentUndoItem;
144		CurrentUndoItem = ItemAt(fIndex-1);
145		if (CurrentUndoItem!=NULL) {
146			int32 c_length = CurrentUndoItem->Length;
147			int32 c_offset = CurrentUndoItem->Offset;
148			undo_type c_history = CurrentUndoItem->History;
149			if (c_history == history) {
150				switch(c_history) {
151					case K_INSERTED:
152					case K_REPLACED:
153						if ((c_offset + c_length) == offset) {
154							CurrentUndoItem->Merge(text, length);
155						} else {
156							status = NewUndo(text, length, offset, history,
157								cursor_pos);
158						}
159						break;
160					case K_DELETED:
161						status = NewUndo(text, length, offset, history,
162							cursor_pos);
163						break;
164				}
165			} else {
166				status = NewUndo(text, length, offset, history, cursor_pos);
167			}
168		}
169	}
170
171	return status;
172}
173
174
175status_t
176KUndoBuffer::MakeNewUndoItem()
177{
178	if (fIndex >= CountItems()) {
179		fNewItem = true;
180		return B_OK;
181	}
182	return B_ERROR;
183}
184
185
186status_t
187KUndoBuffer::Undo(char** text,
188				int32* length,
189				int32* offset,
190				undo_type* history,
191				int32* cursor_pos)
192{
193	KUndoItem* undoItem;
194	status_t status;
195
196	if (fIndex>0) {
197		undoItem = ItemAt(fIndex-1);
198		if (undoItem!=NULL) {
199			*text = undoItem->RedoText;
200			*length = undoItem->Length;
201			*offset = undoItem->Offset;
202			*history = undoItem->History;
203			*cursor_pos = undoItem->CursorPos + undoItem->Length;
204			status = B_OK;
205		} else {
206			status = B_ERROR;
207		}
208		fIndex--;
209	} else {
210		status = B_ERROR;
211	}
212	return status;
213}
214
215status_t
216KUndoBuffer::Redo(char** text,
217				int32* length,
218				int32* offset,
219				undo_type* history,
220				int32* cursor_pos,
221				bool* replaced)
222{
223	KUndoItem* undoItem;
224	status_t status;
225
226	if (fIndex < CountItems()) {
227		undoItem = ItemAt(fIndex);
228		if (undoItem!=NULL) {
229			*text = undoItem->RedoText;
230			*length = undoItem->Length;
231			*offset = undoItem->Offset;
232			*history = undoItem->History;
233			*cursor_pos = undoItem->CursorPos;
234			if ((fIndex+1) < CountItems()) {
235				*replaced = ItemAt(fIndex+1)->History==K_REPLACED;
236			} else {
237				*replaced = false;
238			}
239			status = B_OK;
240		} else {
241			status = B_ERROR;
242		}
243		fIndex++;
244	} else {
245		status = B_ERROR;
246	}
247	return status;
248}
249
250
251void
252KUndoBuffer::PrintToStream()
253{
254	for(int32 i=0; i<CountItems(); i++) {
255		KUndoItem* item = ItemAt(i);
256		printf("%3.3d   ", (int)i);
257		switch(item->History) {
258			case K_INSERTED:
259				printf("INSERTED  ");
260				break;
261			case K_DELETED:
262				printf("DELETED   ");
263				break;
264			case K_REPLACED:
265				printf("REPLACED  ");
266				break;
267		}
268		printf("Offset = %d  ", (int)item->Offset);
269		printf("Length = %d  ", (int)item->Length);
270		printf("CursorPos = %d  ", (int)item->CursorPos);
271		printf("RedoText = '");
272		for(int32 j=0;j<item->Length;j++) {
273			uchar c = (uchar)item->RedoText[j];
274			if (c >= 0x20) {
275				printf("%c", c);
276			} else {
277				printf("?");
278			}
279		}
280		printf("'\n");
281	}
282}
283
284