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 memcpy(RedoText, redo_text, length); 18 if (RedoText != NULL) 19 fStatus = B_OK; 20 else 21 fStatus = B_ERROR; 22 } 23 } 24 25 26 KUndoItem::~KUndoItem() 27 { 28 free(RedoText); 29 } 30 31 32 status_t 33 KUndoItem::InitCheck() 34 { 35 return fStatus; 36 } 37 38 39 void 40 KUndoItem::Merge(const char* text, int32 length) 41 { 42 RedoText = (char*)realloc(RedoText, Length + length); 43 memcpy(&RedoText[Length], text, length); 44 Length += length; 45 } 46 47 48 KUndoBuffer::KUndoBuffer():BList(1024) 49 { 50 fIndex = 0; 51 Off(); 52 fNewItem = true; 53 } 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 72 bool 73 KUndoBuffer::AddItem(KUndoItem* item) 74 { 75 return BList::AddItem(item); 76 } 77 78 79 void 80 KUndoBuffer::MakeEmpty(void) 81 { 82 for (int32 i = CountItems() - 1; i >= 0; i--) 83 RemoveItem(i); 84 } 85 86 87 KUndoItem* 88 KUndoBuffer::RemoveItem(int32 index) 89 { 90 if (fIndex >= CountItems()) 91 fIndex--; 92 delete this->ItemAt(index); 93 return (KUndoItem*)BList::RemoveItem(index); 94 } 95 96 97 KUndoItem* 98 KUndoBuffer::ItemAt(int32 index) const 99 { 100 return (KUndoItem*)BList::ItemAt(index); 101 } 102 103 104 void 105 KUndoBuffer::On() 106 { 107 fNoTouch = false; 108 } 109 110 111 void 112 KUndoBuffer::Off() 113 { 114 fNoTouch = true; 115 } 116 117 118 status_t 119 KUndoBuffer::NewUndo(const char* text, int32 length, int32 offset, 120 undo_type history, int32 cursor_pos) 121 { 122 KUndoItem* NewUndoItem = new KUndoItem(text, length, offset, history, 123 cursor_pos); 124 125 status_t status = NewUndoItem->InitCheck(); 126 if (status != B_OK) { 127 delete NewUndoItem; 128 return status; 129 } 130 AddItem(NewUndoItem, fIndex); 131 fIndex++; 132 return status; 133 } 134 135 136 status_t 137 KUndoBuffer::AddUndo(const char* text, int32 length, int32 offset, 138 undo_type history, int32 cursor_pos) 139 { 140 if (fNoTouch) 141 return B_OK; 142 143 status_t status = B_OK; 144 145 if (fNewItem || fIndex < CountItems() || CountItems() == 0) { 146 status = NewUndo(text, length, offset, history, cursor_pos); 147 fNewItem = false; 148 } else { 149 KUndoItem* CurrentUndoItem; 150 CurrentUndoItem = ItemAt(fIndex - 1); 151 if (CurrentUndoItem != NULL) { 152 int32 c_length = CurrentUndoItem->Length; 153 int32 c_offset = CurrentUndoItem->Offset; 154 undo_type c_history = CurrentUndoItem->History; 155 if (c_history == history) { 156 switch(c_history) { 157 case K_INSERTED: 158 case K_REPLACED: 159 if ((c_offset + c_length) == offset) 160 CurrentUndoItem->Merge(text, length); 161 else { 162 status = NewUndo(text, length, offset, history, 163 cursor_pos); 164 } 165 break; 166 case K_DELETED: 167 status = NewUndo(text, length, offset, history, 168 cursor_pos); 169 break; 170 } 171 } else 172 status = NewUndo(text, length, offset, history, cursor_pos); 173 } 174 } 175 176 return status; 177 } 178 179 180 status_t 181 KUndoBuffer::MakeNewUndoItem() 182 { 183 if (fIndex >= CountItems()) { 184 fNewItem = true; 185 return B_OK; 186 } 187 return B_ERROR; 188 } 189 190 191 status_t 192 KUndoBuffer::Undo(char** text, int32* length, int32* offset, 193 undo_type* history, int32* cursor_pos) 194 { 195 KUndoItem* undoItem; 196 status_t status = B_ERROR; 197 198 if (fIndex > 0) { 199 undoItem = ItemAt(fIndex - 1); 200 if (undoItem != NULL) { 201 *text = undoItem->RedoText; 202 *length = undoItem->Length; 203 *offset = undoItem->Offset; 204 *history = undoItem->History; 205 *cursor_pos = undoItem->CursorPos + undoItem->Length; 206 status = B_OK; 207 } 208 fIndex--; 209 } 210 return status; 211 } 212 213 214 status_t 215 KUndoBuffer::Redo(char** text, int32* length, int32* offset, 216 undo_type* history, int32* cursor_pos, bool* replaced) 217 { 218 KUndoItem* undoItem; 219 status_t status = B_ERROR; 220 221 if (fIndex < CountItems()) { 222 undoItem = ItemAt(fIndex); 223 if (undoItem != NULL) { 224 *text = undoItem->RedoText; 225 *length = undoItem->Length; 226 *offset = undoItem->Offset; 227 *history = undoItem->History; 228 *cursor_pos = undoItem->CursorPos; 229 if (fIndex + 1 < CountItems()) 230 *replaced = ItemAt(fIndex + 1)->History == K_REPLACED; 231 else 232 *replaced = false; 233 status = B_OK; 234 } 235 fIndex++; 236 } 237 return status; 238 } 239 240 241 void 242 KUndoBuffer::PrintToStream() 243 { 244 for (int32 i = 0; i < CountItems(); i++) { 245 KUndoItem* item = ItemAt(i); 246 printf("%3.3d ", (int)i); 247 switch (item->History) { 248 case K_INSERTED: 249 printf("INSERTED "); 250 break; 251 case K_DELETED: 252 printf("DELETED "); 253 break; 254 case K_REPLACED: 255 printf("REPLACED "); 256 break; 257 } 258 printf("Offset = %d ", (int)item->Offset); 259 printf("Length = %d ", (int)item->Length); 260 printf("CursorPos = %d ", (int)item->CursorPos); 261 printf("RedoText = '"); 262 for (int32 j = 0; j < item->Length; j++) { 263 uchar c = (uchar)item->RedoText[j]; 264 if (c >= 0x20) 265 printf("%c", c); 266 else 267 printf("?"); 268 } 269 printf("'\n"); 270 } 271 } 272 273