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, 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 27 KUndoItem::~KUndoItem() 28 { 29 free(RedoText); 30 } 31 32 33 status_t 34 KUndoItem::InitCheck() 35 { 36 return fStatus; 37 } 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 57 KUndoBuffer::~KUndoBuffer() 58 { 59 MakeEmpty(); 60 } 61 62 63 bool 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 74 KUndoBuffer::AddItem(KUndoItem* item) 75 { 76 return BList::AddItem(item); 77 } 78 79 80 void 81 KUndoBuffer::MakeEmpty(void) 82 { 83 for (int32 i = CountItems() - 1; i >= 0; i--) 84 RemoveItem(i); 85 } 86 87 88 KUndoItem* 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* 99 KUndoBuffer::ItemAt(int32 index) const 100 { 101 return (KUndoItem*)BList::ItemAt(index); 102 } 103 104 105 void 106 KUndoBuffer::On() 107 { 108 fNoTouch = false; 109 } 110 111 112 void 113 KUndoBuffer::Off() 114 { 115 fNoTouch = true; 116 } 117 118 119 status_t 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 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 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 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 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 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