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) return B_OK; 135 136 status_t status; 137 138 if (fNewItem || (fIndex < CountItems()) || (CountItems()==0)) { 139 status = NewUndo(text, length, offset, history, cursor_pos); 140 fNewItem = false; 141 } else { 142 KUndoItem* CurrentUndoItem; 143 CurrentUndoItem = ItemAt(fIndex-1); 144 if (CurrentUndoItem!=NULL) { 145 int32 c_length = CurrentUndoItem->Length; 146 int32 c_offset = CurrentUndoItem->Offset; 147 undo_type c_history = CurrentUndoItem->History; 148 if (c_history == history) { 149 switch(c_history) { 150 case K_INSERTED: 151 case K_REPLACED: 152 if ((c_offset + c_length) == offset) { 153 CurrentUndoItem->Merge(text, length); 154 } else { 155 status = NewUndo(text, length, offset, history, 156 cursor_pos); 157 } 158 break; 159 case K_DELETED: 160 status = NewUndo(text, length, offset, history, 161 cursor_pos); 162 break; 163 } 164 } else { 165 status = NewUndo(text, length, offset, history, cursor_pos); 166 } 167 } 168 } 169 170 return B_OK; 171 } 172 173 174 status_t 175 KUndoBuffer::MakeNewUndoItem() 176 { 177 if (fIndex >= CountItems()) { 178 fNewItem = true; 179 return B_OK; 180 } 181 return B_ERROR; 182 } 183 184 185 status_t 186 KUndoBuffer::Undo(char** text, 187 int32* length, 188 int32* offset, 189 undo_type* history, 190 int32* cursor_pos) 191 { 192 KUndoItem* undoItem; 193 status_t status; 194 195 if (fIndex>0) { 196 undoItem = ItemAt(fIndex-1); 197 if (undoItem!=NULL) { 198 *text = undoItem->RedoText; 199 *length = undoItem->Length; 200 *offset = undoItem->Offset; 201 *history = undoItem->History; 202 *cursor_pos = undoItem->CursorPos + undoItem->Length; 203 status = B_OK; 204 } else { 205 status = B_ERROR; 206 } 207 fIndex--; 208 } else { 209 status = B_ERROR; 210 } 211 return status; 212 } 213 214 status_t 215 KUndoBuffer::Redo(char** text, 216 int32* length, 217 int32* offset, 218 undo_type* history, 219 int32* cursor_pos, 220 bool* replaced) 221 { 222 KUndoItem* undoItem; 223 status_t status; 224 225 if (fIndex < CountItems()) { 226 undoItem = ItemAt(fIndex); 227 if (undoItem!=NULL) { 228 *text = undoItem->RedoText; 229 *length = undoItem->Length; 230 *offset = undoItem->Offset; 231 *history = undoItem->History; 232 *cursor_pos = undoItem->CursorPos; 233 if ((fIndex+1) < CountItems()) { 234 *replaced = ItemAt(fIndex+1)->History==K_REPLACED; 235 } else { 236 *replaced = false; 237 } 238 status = B_OK; 239 } else { 240 status = B_ERROR; 241 } 242 fIndex++; 243 } else { 244 status = B_ERROR; 245 } 246 return status; 247 } 248 249 250 void 251 KUndoBuffer::PrintToStream() 252 { 253 for(int32 i=0; i<CountItems(); i++) { 254 KUndoItem* item = ItemAt(i); 255 printf("%3.3d ", (int)i); 256 switch(item->History) { 257 case K_INSERTED: 258 printf("INSERTED "); 259 break; 260 case K_DELETED: 261 printf("DELETED "); 262 break; 263 case K_REPLACED: 264 printf("REPLACED "); 265 break; 266 } 267 printf("Offset = %d ", (int)item->Offset); 268 printf("Length = %d ", (int)item->Length); 269 printf("CursorPos = %d ", (int)item->CursorPos); 270 printf("RedoText = '"); 271 for(int32 j=0;j<item->Length;j++) { 272 uchar c = (uchar)item->RedoText[j]; 273 if (c >= 0x20) { 274 printf("%c", c); 275 } else { 276 printf("?"); 277 } 278 } 279 printf("'\n"); 280 } 281 } 282 283