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