1#include <stdlib.h> 2#include <stdio.h> 3#include <memory.h> 4#include "KUndoBuffer.h" 5 6 7KUndoItem::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 27KUndoItem::~KUndoItem() 28{ 29 free(RedoText); 30} 31 32 33status_t 34KUndoItem::InitCheck() 35{ 36 return fStatus; 37} 38 39 40void 41KUndoItem::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 49KUndoBuffer::KUndoBuffer():BList(1024) 50{ 51 fIndex = 0; 52 Off(); 53 fNewItem = true; 54} 55 56 57KUndoBuffer::~KUndoBuffer() 58{ 59 MakeEmpty(); 60} 61 62 63bool 64KUndoBuffer::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 73bool 74KUndoBuffer::AddItem(KUndoItem* item) 75{ 76 return BList::AddItem(item); 77} 78 79 80void 81KUndoBuffer::MakeEmpty(void) 82{ 83 for (int32 i = CountItems() - 1; i >= 0; i--) 84 RemoveItem(i); 85} 86 87 88KUndoItem* 89KUndoBuffer::RemoveItem(int32 index) 90{ 91 if (fIndex >= CountItems()) 92 fIndex--; 93 delete this->ItemAt(index); 94 return (KUndoItem*)BList::RemoveItem(index); 95} 96 97 98KUndoItem* 99KUndoBuffer::ItemAt(int32 index) const 100{ 101 return (KUndoItem*)BList::ItemAt(index); 102} 103 104 105void 106KUndoBuffer::On() 107{ 108 fNoTouch = false; 109} 110 111 112void 113KUndoBuffer::Off() 114{ 115 fNoTouch = true; 116} 117 118 119status_t 120KUndoBuffer::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 137status_t 138KUndoBuffer::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 181status_t 182KUndoBuffer::MakeNewUndoItem() 183{ 184 if (fIndex >= CountItems()) { 185 fNewItem = true; 186 return B_OK; 187 } 188 return B_ERROR; 189} 190 191 192status_t 193KUndoBuffer::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 215status_t 216KUndoBuffer::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 242void 243KUndoBuffer::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