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