xref: /haiku/src/apps/mail/KUndoBuffer.cpp (revision 93e30a47bed879ad448b3e2d9e10333d3f2e60ae)
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)
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 
175 status_t
176 KUndoBuffer::MakeNewUndoItem()
177 {
178 	if (fIndex >= CountItems()) {
179 		fNewItem = true;
180 		return B_OK;
181 	}
182 	return B_ERROR;
183 }
184 
185 
186 status_t
187 KUndoBuffer::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 
215 status_t
216 KUndoBuffer::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 
251 void
252 KUndoBuffer::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