xref: /haiku/src/apps/mail/KUndoBuffer.cpp (revision f67bf6411c0487eedca478690d89b3a363cf32c3)
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <memory.h>
4 #include "KUndoBuffer.h"
5 
6 
KUndoItem(const char * redo_text,int32 length,int32 offset,undo_type history,int32 cursor_pos)7 KUndoItem::KUndoItem(const char* redo_text, int32 length, int32 offset,
8 	undo_type history, int32 cursor_pos)
9 {
10 	Offset = offset;
11 	Length = length;
12 	History = history;
13 	CursorPos = cursor_pos;
14 
15 	if (redo_text != NULL) {
16 		RedoText = (char*)malloc(length);
17 
18 		if (RedoText != NULL) {
19 			memcpy(RedoText, redo_text, length);
20 			fStatus = B_OK;
21 		} else
22 			fStatus = B_ERROR;
23 	}
24 }
25 
26 
~KUndoItem()27 KUndoItem::~KUndoItem()
28 {
29 	free(RedoText);
30 }
31 
32 
33 status_t
InitCheck()34 KUndoItem::InitCheck()
35 {
36 	return fStatus;
37 }
38 
39 
40 void
Merge(const char * text,int32 length)41 KUndoItem::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 
KUndoBuffer()49 KUndoBuffer::KUndoBuffer():BList(1024)
50 {
51 	fIndex = 0;
52 	Off();
53 	fNewItem = true;
54 }
55 
56 
~KUndoBuffer()57 KUndoBuffer::~KUndoBuffer()
58 {
59 	MakeEmpty();
60 }
61 
62 
63 bool
AddItem(KUndoItem * item,int32 index)64 KUndoBuffer::AddItem(KUndoItem* item, int32 index)
65 {
66 	for (int32 i = CountItems() - 1; i >= index; i--)
67 		RemoveItem(i);
68 
69 	return AddItem(item);
70 }
71 
72 
73 bool
AddItem(KUndoItem * item)74 KUndoBuffer::AddItem(KUndoItem* item)
75 {
76 	return BList::AddItem(item);
77 }
78 
79 
80 void
MakeEmpty(void)81 KUndoBuffer::MakeEmpty(void)
82 {
83 	for (int32 i = CountItems() - 1; i >= 0; i--)
84 		RemoveItem(i);
85 }
86 
87 
88 KUndoItem*
RemoveItem(int32 index)89 KUndoBuffer::RemoveItem(int32 index)
90 {
91 	if (fIndex >= CountItems())
92 		fIndex--;
93 	delete this->ItemAt(index);
94 	return (KUndoItem*)BList::RemoveItem(index);
95 }
96 
97 
98 KUndoItem*
ItemAt(int32 index) const99 KUndoBuffer::ItemAt(int32 index) const
100 {
101 	return (KUndoItem*)BList::ItemAt(index);
102 }
103 
104 
105 void
On()106 KUndoBuffer::On()
107 {
108 	fNoTouch = false;
109 }
110 
111 
112 void
Off()113 KUndoBuffer::Off()
114 {
115 	fNoTouch = true;
116 }
117 
118 
119 status_t
NewUndo(const char * text,int32 length,int32 offset,undo_type history,int32 cursor_pos)120 KUndoBuffer::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 
137 status_t
AddUndo(const char * text,int32 length,int32 offset,undo_type history,int32 cursor_pos)138 KUndoBuffer::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 
181 status_t
MakeNewUndoItem()182 KUndoBuffer::MakeNewUndoItem()
183 {
184 	if (fIndex >= CountItems()) {
185 		fNewItem = true;
186 		return B_OK;
187 	}
188 	return B_ERROR;
189 }
190 
191 
192 status_t
Undo(char ** text,int32 * length,int32 * offset,undo_type * history,int32 * cursor_pos)193 KUndoBuffer::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 
215 status_t
Redo(char ** text,int32 * length,int32 * offset,undo_type * history,int32 * cursor_pos,bool * replaced)216 KUndoBuffer::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 
242 void
PrintToStream()243 KUndoBuffer::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