1 #include <stdlib.h> 2 #include <stdio.h> 3 #include <memory.h> 4 #include "KUndoBuffer.h" 5 6 7 /* 8 KUndoItem 9 KUndoBuffer に格納される Undo/Redo 情報を記憶するクラス 10 (The class which remembers the Undo/Redo information which is housed in the KUndoBuffer) 11 */ 12 KUndoItem::KUndoItem(const char *redo_text, 13 int32 length, 14 int32 offset, 15 undo_type history, 16 int32 cursor_pos) 17 { 18 Offset = offset; 19 Length = length; 20 History = history; 21 CursorPos = cursor_pos; 22 23 if (redo_text!=NULL) { 24 RedoText = (char *)malloc(length); 25 memcpy(RedoText, redo_text, length); 26 if (RedoText!=NULL) { 27 Status = B_OK; 28 } else { 29 Status = B_ERROR; 30 } 31 } 32 } 33 34 KUndoItem::~KUndoItem() 35 { 36 free(RedoText); 37 } 38 39 status_t 40 KUndoItem::InitCheck() 41 { 42 return Status; 43 } 44 45 void 46 KUndoItem::Merge(const char *text, int32 length) 47 { 48 RedoText = (char *)realloc(RedoText, Length + length); 49 memcpy(&RedoText[Length], text, length); 50 Length += length; 51 } 52 53 54 /* 55 KUndoBuffer 56 Undo/Redo情報リストを管理するクラス。 57 (The class which manages the Undo/Redo information list.) 58 このクラス自体は、BTextViewに影響を及ぼすものではない。 59 (This class itself is not something which exerts influence on the BTextView.) 60 あくまで、アプリケーションがUndo/Redoを実装するための補助にすぎない。 61 (To the last, it is no more than an assistance because application mounts the Undo/Redo.) 62 */ 63 KUndoBuffer::KUndoBuffer():BList(1024) 64 { 65 FIndex = 0; 66 Off(); 67 FNewItem = true; 68 } 69 70 KUndoBuffer::~KUndoBuffer() 71 { 72 MakeEmpty(); 73 } 74 75 /* 76 Undo情報を追加する。 77 (Undo information is added.) 78 リスト途中に追加したら、以降はRedoの必要がなくなるため、 79 追加位置以降のUndo情報があれば削除する。 80 (When it adds on the list middle, if later because necessity of the Redo is 81 gone, there is Undo information after the additional position, it deletes.) 82 */ 83 bool 84 KUndoBuffer::AddItem(KUndoItem *item, int32 index) 85 { 86 for (int32 i=CountItems()-1; i>=index; i--) { 87 RemoveItem(i); 88 } 89 return AddItem(item); 90 } 91 92 bool 93 KUndoBuffer::AddItem(KUndoItem *item) 94 { 95 return BList::AddItem(item); 96 } 97 98 void 99 KUndoBuffer::MakeEmpty(void) 100 { 101 for(int32 i=CountItems()-1; i>=0;i--) { 102 RemoveItem(i); 103 } 104 } 105 106 KUndoItem * 107 KUndoBuffer::RemoveItem(int32 index) 108 { 109 if (FIndex>=CountItems()) FIndex--; 110 delete this->ItemAt(index); 111 return (KUndoItem *)BList::RemoveItem(index); 112 } 113 114 KUndoItem * 115 KUndoBuffer::ItemAt(int32 index) const 116 { 117 return (KUndoItem *)BList::ItemAt(index); 118 } 119 120 /* 121 Off() 呼び出し後は、On()を実行しないとUndo情報追加を行わない。 122 (Unless OFF () it calls after, ON () executes, Undo information addition is not done.) 123 */ 124 void 125 KUndoBuffer::On() 126 { 127 FNoTouch = false; 128 } 129 130 void 131 KUndoBuffer::Off() 132 { 133 FNoTouch = true; 134 } 135 136 status_t 137 KUndoBuffer::NewUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos) 138 { 139 KUndoItem *NewUndoItem = new KUndoItem(text, length, offset, history, cursor_pos); 140 status_t status = NewUndoItem->InitCheck(); 141 if ( status != B_OK) { 142 delete NewUndoItem; 143 return status; 144 } 145 AddItem(NewUndoItem, FIndex); 146 FIndex++; 147 return status; 148 } 149 150 /* 151 Undo情報をリストに追加する。 152 (Undo information is added to the list.) 153 */ 154 status_t 155 KUndoBuffer::AddUndo(const char *text, int32 length, int32 offset, undo_type history, int32 cursor_pos) 156 { 157 if (FNoTouch) return B_OK; 158 159 status_t status; 160 161 // 新たな追加予約がある(FNewItem)か、現在位置(FIndex)が最後尾でないか、Undoリストが空であれば 162 // 新たにUndo情報を追加する。 163 // (There is new additional reservation, if (the FNewItem), 現在位置 (the 164 // FIndex) is not the last tail or and the Undo list is the sky, Undo 165 // information is added anew.) 166 // さもなくば、最後尾Undo情報に結合すべきなら結合し、そうでなければ 167 // やはり新たにUndo情報を追加する。 168 // (Without, if it should connect to last tail Undo information, if it 169 // connects and so is not Undo information is added after all anew.) 170 if (FNewItem || (FIndex < CountItems()) || (CountItems()==0)) { 171 status = NewUndo(text, length, offset, history, cursor_pos); 172 FNewItem = false; 173 } else { 174 KUndoItem *CurrentUndoItem; 175 CurrentUndoItem = ItemAt(FIndex-1); 176 if (CurrentUndoItem!=NULL) { 177 int32 c_length = CurrentUndoItem->Length; 178 int32 c_offset = CurrentUndoItem->Offset; 179 undo_type c_history = CurrentUndoItem->History; 180 if (c_history == history) { 181 switch(c_history) { 182 case K_INSERTED: 183 case K_REPLACED: 184 if ((c_offset + c_length) == offset) { 185 CurrentUndoItem->Merge(text, length); 186 } else { 187 status = NewUndo(text, length, offset, history, cursor_pos); 188 } 189 break; 190 case K_DELETED: 191 status = NewUndo(text, length, offset, history, cursor_pos); 192 break; 193 } 194 } else { 195 status = NewUndo(text, length, offset, history, cursor_pos); 196 } 197 } 198 } 199 200 return B_OK; 201 } 202 203 // Enterを押した、矢印キーを押した等、Undoを一区切り起きたい場合に 204 // MakeNewUndoItem()を呼び出す。 205 // (The Enter was pushed, one you divide the Undo and the MakeNewUndoItem () 206 // you call when we would like to occur e.g., the arrow key was pushed.) 207 status_t 208 KUndoBuffer::MakeNewUndoItem() 209 { 210 if (FIndex >= CountItems()) { 211 FNewItem = true; 212 return B_OK; 213 } 214 return B_ERROR; 215 } 216 217 // Undo() Redo() は、FIndexをいったりきたりしながら 218 // 挿入位置、文字長、復元テキスト等の情報を返す。 219 // (The Undo () the Redo (), the FIndex, while going back and forth, it 220 // returns the information of insertion position, letter length and the 221 // restoration text et cetera.) 222 status_t 223 KUndoBuffer::Undo(char **text, 224 int32 *length, 225 int32 *offset, 226 undo_type *history, 227 int32 *cursor_pos) 228 { 229 KUndoItem *undoItem; 230 status_t status; 231 232 if (FIndex>0) { 233 undoItem = ItemAt(FIndex-1); 234 if (undoItem!=NULL) { 235 *text = undoItem->RedoText; 236 *length = undoItem->Length; 237 *offset = undoItem->Offset; 238 *history = undoItem->History; 239 *cursor_pos = undoItem->CursorPos + undoItem->Length; 240 status = B_OK; 241 } else { 242 status = B_ERROR; 243 } 244 FIndex--; 245 } else { 246 status = B_ERROR; 247 } 248 return status; 249 } 250 251 status_t 252 KUndoBuffer::Redo(char **text, 253 int32 *length, 254 int32 *offset, 255 undo_type *history, 256 int32 *cursor_pos, 257 bool *replaced) 258 { 259 KUndoItem *undoItem; 260 status_t status; 261 262 if (FIndex < CountItems()) { 263 undoItem = ItemAt(FIndex); 264 if (undoItem!=NULL) { 265 *text = undoItem->RedoText; 266 *length = undoItem->Length; 267 *offset = undoItem->Offset; 268 *history = undoItem->History; 269 *cursor_pos = undoItem->CursorPos; 270 if ((FIndex+1) < CountItems()) { 271 *replaced = ItemAt(FIndex+1)->History==K_REPLACED; 272 } else { 273 *replaced = false; 274 } 275 status = B_OK; 276 } else { 277 status = B_ERROR; 278 } 279 FIndex++; 280 } else { 281 status = B_ERROR; 282 } 283 return status; 284 } 285 286 // Undo/Redo 情報を標準出力に書きだす。 287 // (It starts writing Undo/Redo information on standard output.) 288 // デバッグ時のみ。 289 // (Only when debugging.) 290 void 291 KUndoBuffer::PrintToStream() 292 { 293 for(int32 i=0; i<CountItems(); i++) { 294 KUndoItem *item = ItemAt(i); 295 printf("%3.3d ", (int)i); 296 switch(item->History) { 297 case K_INSERTED: 298 printf("INSERTED "); 299 break; 300 case K_DELETED: 301 printf("DELETED "); 302 break; 303 case K_REPLACED: 304 printf("REPLACED "); 305 break; 306 } 307 printf("Offset = %d ", (int)item->Offset); 308 printf("Length = %d ", (int)item->Length); 309 printf("CursorPos = %d ", (int)item->CursorPos); 310 printf("RedoText = '"); 311 for(int32 j=0;j<item->Length;j++) { 312 uchar c = (uchar)item->RedoText[j]; 313 if (c >= 0x20) { 314 printf("%c", c); 315 } else { 316 printf("?"); 317 } 318 } 319 printf("'\n"); 320 } 321 } 322