xref: /haiku/src/apps/mail/KUndoBuffer.cpp (revision 16d5c24e533eb14b7b8a99ee9f3ec9ba66335b1e)
1 #include <stdlib.h>
2 #include <stdio.h>
3 #include <memory.h>
4 #include "KUndoBuffer.h"
5 
6 
7 /*
8  KUndoItem
9 KUndoBuffer に格納される Undo/Redo 情報を記憶するクラス
10 (The class which remembers the Undo/Redo information which is housed in the KUndoBuffer)
11 */
12 KUndoItem::KUndoItem(const char *redo_text,
13 					int32 length,
14 					int32 offset,
15 					undo_type history,
16 					int32 cursor_pos)
17 {
18 	Offset = offset;
19 	Length = length;
20 	History = history;
21 	CursorPos = cursor_pos;
22 
23 	if (redo_text!=NULL) {
24 		RedoText = (char *)malloc(length);
25 		memcpy(RedoText, redo_text, length);
26 		if (RedoText!=NULL) {
27 			Status = B_OK;
28 		} else {
29 			Status = B_ERROR;
30 		}
31 	}
32 }
33 
34 KUndoItem::~KUndoItem()
35 {
36 	free(RedoText);
37 }
38 
39 status_t
40 KUndoItem::InitCheck()
41 {
42 	return Status;
43 }
44 
45 void
46 KUndoItem::Merge(const char *text, int32 length)
47 {
48 	RedoText = (char *)realloc(RedoText, Length + length);
49 	memcpy(&RedoText[Length], text, length);
50 	Length += length;
51 }
52 
53 
54 /*
55  KUndoBuffer
56 Undo/Redo情報リストを管理するクラス。
57 (The class which manages the Undo/Redo information list.)
58 このクラス自体は、BTextViewに影響を及ぼすものではない。
59 (This class itself is not something which exerts influence on the BTextView.)
60 あくまで、アプリケーションがUndo/Redoを実装するための補助にすぎない。
61 (To the last, it is no more than an assistance because application mounts the Undo/Redo.)
62 */
63 KUndoBuffer::KUndoBuffer():BList(1024)
64 {
65 	FIndex = 0;
66 	Off();
67 	FNewItem = true;
68 }
69 
70 KUndoBuffer::~KUndoBuffer()
71 {
72 	MakeEmpty();
73 }
74 
75 /*
76 Undo情報を追加する。
77 (Undo information is added.)
78 リスト途中に追加したら、以降はRedoの必要がなくなるため、
79 追加位置以降のUndo情報があれば削除する。
80 (When it adds on the list middle, if later because necessity of the Redo is
81 gone, there is Undo information after the additional position, it deletes.)
82 */
83 bool
84 KUndoBuffer::AddItem(KUndoItem *item, int32 index)
85 {
86 	for (int32 i=CountItems()-1; i>=index; i--) {
87 		RemoveItem(i);
88 	}
89 	return AddItem(item);
90 }
91 
92 bool
93 KUndoBuffer::AddItem(KUndoItem *item)
94 {
95 	return BList::AddItem(item);
96 }
97 
98 void
99 KUndoBuffer::MakeEmpty(void)
100 {
101 	for(int32 i=CountItems()-1; i>=0;i--) {
102 		RemoveItem(i);
103 	}
104 }
105 
106 KUndoItem *
107 KUndoBuffer::RemoveItem(int32 index)
108 {
109 	if (FIndex>=CountItems()) FIndex--;
110 	delete this->ItemAt(index);
111 	return (KUndoItem *)BList::RemoveItem(index);
112 }
113 
114 KUndoItem *
115 KUndoBuffer::ItemAt(int32 index) const
116 {
117 	return (KUndoItem *)BList::ItemAt(index);
118 }
119 
120 /*
121  Off() 呼び出し後は、On()を実行しないとUndo情報追加を行わない。
122  (Unless OFF () it calls after, ON () executes, Undo information addition is not done.)
123 */
124 void
125 KUndoBuffer::On()
126 {
127 	FNoTouch = false;
128 }
129 
130 void
131 KUndoBuffer::Off()
132 {
133 	FNoTouch = true;
134 }
135 
136 status_t
137 KUndoBuffer::NewUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos)
138 {
139 	KUndoItem *NewUndoItem = new KUndoItem(text, length, offset, history, cursor_pos);
140 	status_t status = NewUndoItem->InitCheck();
141 	if ( status != B_OK) {
142 		delete NewUndoItem;
143 		return status;
144 	}
145 	AddItem(NewUndoItem, FIndex);
146 	FIndex++;
147 	return status;
148 }
149 
150 /*
151 Undo情報をリストに追加する。
152 (Undo information is added to the list.)
153 */
154 status_t
155 KUndoBuffer::AddUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos)
156 {
157 	if (FNoTouch) return B_OK;
158 
159 	status_t status;
160 
161 	// 新たな追加予約がある(FNewItem)か、現在位置(FIndex)が最後尾でないか、Undoリストが空であれば
162 	// 新たにUndo情報を追加する。
163 	// (There is new additional reservation, if (the FNewItem), 現在位置 (the
164 	// FIndex) is not the last tail or and the Undo list is the sky, Undo
165 	// information is added anew.)
166 	// さもなくば、最後尾Undo情報に結合すべきなら結合し、そうでなければ
167 	// やはり新たにUndo情報を追加する。
168 	// (Without, if it should connect to last tail Undo information, if it
169 	// connects and so is not Undo information is added after all anew.)
170 	if (FNewItem || (FIndex < CountItems()) || (CountItems()==0)) {
171 		status = NewUndo(text, length, offset, history, cursor_pos);
172 		FNewItem = false;
173 	} else {
174 		KUndoItem *CurrentUndoItem;
175 		CurrentUndoItem = ItemAt(FIndex-1);
176 		if (CurrentUndoItem!=NULL) {
177 			int32 c_length = CurrentUndoItem->Length;
178 			int32 c_offset = CurrentUndoItem->Offset;
179 			undo_type c_history = CurrentUndoItem->History;
180 			if (c_history == history) {
181 				switch(c_history) {
182 					case K_INSERTED:
183 					case K_REPLACED:
184 						if ((c_offset + c_length) == offset) {
185 							CurrentUndoItem->Merge(text, length);
186 						} else {
187 							status = NewUndo(text, length, offset, history, cursor_pos);
188 						}
189 						break;
190 					case K_DELETED:
191 						status = NewUndo(text, length, offset, history, cursor_pos);
192 						break;
193 				}
194 			} else {
195 				status = NewUndo(text, length, offset, history, cursor_pos);
196 			}
197 		}
198 	}
199 
200 	return B_OK;
201 }
202 
203 // Enterを押した、矢印キーを押した等、Undoを一区切り起きたい場合に
204 // MakeNewUndoItem()を呼び出す。
205 // (The Enter was pushed, one you divide the Undo and the MakeNewUndoItem ()
206 // you call when we would like to occur e.g., the arrow key was pushed.)
207 status_t
208 KUndoBuffer::MakeNewUndoItem()
209 {
210 	if (FIndex >= CountItems()) {
211 		FNewItem = true;
212 		return B_OK;
213 	}
214 	return B_ERROR;
215 }
216 
217 // Undo() Redo() は、FIndexをいったりきたりしながら
218 // 挿入位置、文字長、復元テキスト等の情報を返す。
219 // (The Undo () the Redo (), the FIndex, while going back and forth, it
220 // returns the information of insertion position, letter length and the
221 // restoration text et cetera.)
222 status_t
223 KUndoBuffer::Undo(char **text,
224 				int32 *length,
225 				int32 *offset,
226 				undo_type *history,
227 				int32 *cursor_pos)
228 {
229 	KUndoItem *undoItem;
230 	status_t status;
231 
232 	if (FIndex>0) {
233 		undoItem = ItemAt(FIndex-1);
234 		if (undoItem!=NULL) {
235 			*text = undoItem->RedoText;
236 			*length = undoItem->Length;
237 			*offset = undoItem->Offset;
238 			*history = undoItem->History;
239 			*cursor_pos = undoItem->CursorPos + undoItem->Length;
240 			status = B_OK;
241 		} else {
242 			status = B_ERROR;
243 		}
244 		FIndex--;
245 	} else {
246 		status = B_ERROR;
247 	}
248 	return status;
249 }
250 
251 status_t
252 KUndoBuffer::Redo(char **text,
253 				int32 *length,
254 				int32 *offset,
255 				undo_type *history,
256 				int32 *cursor_pos,
257 				bool *replaced)
258 {
259 	KUndoItem *undoItem;
260 	status_t status;
261 
262 	if (FIndex < CountItems()) {
263 		undoItem = ItemAt(FIndex);
264 		if (undoItem!=NULL) {
265 			*text = undoItem->RedoText;
266 			*length = undoItem->Length;
267 			*offset = undoItem->Offset;
268 			*history = undoItem->History;
269 			*cursor_pos = undoItem->CursorPos;
270 			if ((FIndex+1) < CountItems()) {
271 				*replaced = ItemAt(FIndex+1)->History==K_REPLACED;
272 			} else {
273 				*replaced = false;
274 			}
275 			status = B_OK;
276 		} else {
277 			status = B_ERROR;
278 		}
279 		FIndex++;
280 	} else {
281 		status = B_ERROR;
282 	}
283 	return status;
284 }
285 
286 // Undo/Redo 情報を標準出力に書きだす。
287 // (It starts writing Undo/Redo information on standard output.)
288 // デバッグ時のみ。
289 // (Only when debugging.)
290 void
291 KUndoBuffer::PrintToStream()
292 {
293 	for(int32 i=0; i<CountItems(); i++) {
294 		KUndoItem *item = ItemAt(i);
295 		printf("%3.3d   ", (int)i);
296 		switch(item->History) {
297 			case K_INSERTED:
298 				printf("INSERTED  ");
299 				break;
300 			case K_DELETED:
301 				printf("DELETED   ");
302 				break;
303 			case K_REPLACED:
304 				printf("REPLACED  ");
305 				break;
306 		}
307 		printf("Offset = %d  ", (int)item->Offset);
308 		printf("Length = %d  ", (int)item->Length);
309 		printf("CursorPos = %d  ", (int)item->CursorPos);
310 		printf("RedoText = '");
311 		for(int32 j=0;j<item->Length;j++) {
312 			uchar c = (uchar)item->RedoText[j];
313 			if (c >= 0x20) {
314 				printf("%c", c);
315 			} else {
316 				printf("?");
317 			}
318 		}
319 		printf("'\n");
320 	}
321 }
322