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