1 #include "Commands.h" 2 #include "FSUndoRedo.h" 3 #include "FSUtils.h" 4 5 #include <Autolock.h> 6 #include <Volume.h> 7 #include <Node.h> 8 #include <Path.h> 9 10 11 static const int32 kUndoRedoListMaxCount = 20; 12 13 14 namespace BPrivate { 15 16 class UndoItem { 17 public: 18 virtual ~UndoItem() {} 19 20 virtual status_t Undo() = 0; 21 virtual status_t Redo() = 0; 22 23 virtual void UpdateEntry(BEntry */*entry*/, const char */*name*/) {} 24 // updates the name of the target from the source entry "entry" 25 }; 26 27 static BObjectList<UndoItem> sUndoList, sRedoList; 28 static BLocker sLock("undo"); 29 30 class UndoItemCopy : public UndoItem { 31 public: 32 UndoItemCopy(BObjectList<entry_ref> *sourceList, BDirectory &target, 33 BList *pointList, uint32 moveMode); 34 virtual ~UndoItemCopy(); 35 36 virtual status_t Undo(); 37 virtual status_t Redo(); 38 virtual void UpdateEntry(BEntry *entry, const char *name); 39 40 private: 41 BObjectList<entry_ref> fSourceList; 42 BObjectList<entry_ref> fTargetList; 43 entry_ref fSourceRef, fTargetRef; 44 uint32 fMoveMode; 45 }; 46 47 class UndoItemMove : public UndoItem { 48 public: 49 /** source - list of file(s) that were moved. Assumes ownership. 50 * origfolder - location it was moved from 51 */ 52 UndoItemMove(BObjectList<entry_ref> *sourceList, BDirectory &target, BList *pointList); 53 virtual ~UndoItemMove(); 54 55 virtual status_t Undo(); 56 virtual status_t Redo(); 57 58 private: 59 BObjectList<entry_ref> fSourceList; 60 entry_ref fSourceRef, fTargetRef; 61 }; 62 63 class UndoItemFolder : public UndoItem { 64 public: 65 UndoItemFolder(const entry_ref &ref); 66 // ref - entry_ref indicating the folder created 67 virtual ~UndoItemFolder(); 68 69 virtual status_t Undo(); 70 virtual status_t Redo(); 71 72 private: 73 /* this ref has two different meanings in the different states of this object: 74 - Undo() - fRef indicates the folder that was created via FSCreateNewFolderIn(...) 75 - Redo() - fRef indicates the folder in which FSCreateNewFolderIn() should be performed 76 */ 77 entry_ref fRef; 78 }; 79 80 class UndoItemRename : public UndoItem { 81 public: 82 UndoItemRename(const entry_ref &origRef, const entry_ref &ref); 83 UndoItemRename(const BEntry &entry, const char *newName); 84 virtual ~UndoItemRename(); 85 86 virtual status_t Undo(); 87 virtual status_t Redo(); 88 89 private: 90 entry_ref fRef, fOrigRef; 91 }; 92 93 class UndoItemRenameVolume : public UndoItem { 94 public: 95 UndoItemRenameVolume(BVolume &volume, const char *newName); 96 virtual ~UndoItemRenameVolume(); 97 98 virtual status_t Undo(); 99 virtual status_t Redo(); 100 101 private: 102 BVolume fVolume; 103 BString fOldName, fNewName; 104 }; 105 106 107 //-------------------------- 108 109 110 static status_t 111 ChangeListSource(BObjectList<entry_ref> &list, BEntry &entry) 112 { 113 node_ref source; 114 if (entry.GetNodeRef(&source) != B_OK) 115 return B_ERROR; 116 117 for (int32 index = 0; index < list.CountItems(); index++) { 118 entry_ref *ref = list.ItemAt(index); 119 120 ref->device = source.device; 121 ref->directory = source.node; 122 } 123 124 return B_OK; 125 } 126 127 128 static void 129 AddUndoItem(UndoItem *item) 130 { 131 BAutolock locker(sLock); 132 133 // we have a restricted number of possible undos 134 if (sUndoList.CountItems() == kUndoRedoListMaxCount) 135 sUndoList.RemoveItem(sUndoList.LastItem()); 136 137 sUndoList.AddItem(item, 0); 138 sRedoList.MakeEmpty(); 139 } 140 141 142 // #pragma mark - 143 144 145 Undo::~Undo() 146 { 147 if (fUndo != NULL) 148 AddUndoItem(fUndo); 149 } 150 151 152 void 153 Undo::UpdateEntry(BEntry *entry, const char *destName) 154 { 155 if (fUndo != NULL) 156 fUndo->UpdateEntry(entry, destName); 157 } 158 159 160 void 161 Undo::Remove() 162 { 163 delete fUndo; 164 fUndo = NULL; 165 } 166 167 168 MoveCopyUndo::MoveCopyUndo(BObjectList<entry_ref> *sourceList, BDirectory &dest, 169 BList *pointList, uint32 moveMode) 170 { 171 if (moveMode == kMoveSelectionTo) 172 fUndo = new UndoItemMove(sourceList, dest, pointList); 173 else 174 fUndo = new UndoItemCopy(sourceList, dest, pointList, moveMode); 175 } 176 177 178 NewFolderUndo::NewFolderUndo(const entry_ref &ref) 179 { 180 fUndo = new UndoItemFolder(ref); 181 } 182 183 184 RenameUndo::RenameUndo(BEntry &entry, const char *newName) 185 { 186 fUndo = new UndoItemRename(entry, newName); 187 } 188 189 190 RenameVolumeUndo::RenameVolumeUndo(BVolume &volume, const char *newName) 191 { 192 fUndo = new UndoItemRenameVolume(volume, newName); 193 } 194 195 196 // #pragma mark - 197 198 199 UndoItemCopy::UndoItemCopy(BObjectList<entry_ref> *sourceList, BDirectory &target, 200 BList */*pointList*/, uint32 moveMode) 201 : 202 fSourceList(*sourceList), 203 fTargetList(*sourceList), 204 fMoveMode(moveMode) 205 { 206 BEntry entry(sourceList->ItemAt(0)); 207 208 BEntry sourceEntry; 209 entry.GetParent(&sourceEntry); 210 sourceEntry.GetRef(&fSourceRef); 211 212 BEntry targetEntry; 213 target.GetEntry(&targetEntry); 214 targetEntry.GetRef(&fTargetRef); 215 ChangeListSource(fTargetList, targetEntry); 216 } 217 218 219 UndoItemCopy::~UndoItemCopy() 220 { 221 } 222 223 224 status_t 225 UndoItemCopy::Undo() 226 { 227 FSDeleteRefList(new BObjectList<entry_ref>(fTargetList), true, false); 228 return B_OK; 229 } 230 231 232 status_t 233 UndoItemCopy::Redo() 234 { 235 FSMoveToFolder(new BObjectList<entry_ref>(fSourceList), new BEntry(&fTargetRef), 236 FSUndoMoveMode(fMoveMode), NULL); 237 238 return B_OK; 239 } 240 241 242 void 243 UndoItemCopy::UpdateEntry(BEntry *entry, const char *name) 244 { 245 entry_ref changedRef; 246 if (entry->GetRef(&changedRef) != B_OK) 247 return; 248 249 for (int32 index = 0; index < fSourceList.CountItems(); index++) { 250 entry_ref *ref = fSourceList.ItemAt(index); 251 if (changedRef != *ref) 252 continue; 253 254 ref = fTargetList.ItemAt(index); 255 ref->set_name(name); 256 } 257 } 258 259 260 // #pragma mark - 261 262 263 UndoItemMove::UndoItemMove(BObjectList<entry_ref> *sourceList, BDirectory &target, 264 BList */*pointList*/) 265 : 266 fSourceList(*sourceList) 267 { 268 BEntry entry(sourceList->ItemAt(0)); 269 BEntry source; 270 entry.GetParent(&source); 271 source.GetRef(&fSourceRef); 272 273 BEntry targetEntry; 274 target.GetEntry(&targetEntry); 275 targetEntry.GetRef(&fTargetRef); 276 } 277 278 279 UndoItemMove::~UndoItemMove() 280 { 281 } 282 283 284 status_t 285 UndoItemMove::Undo() 286 { 287 BObjectList<entry_ref> *list = new BObjectList<entry_ref>(fSourceList); 288 BEntry entry(&fTargetRef); 289 ChangeListSource(*list, entry); 290 291 // FSMoveToFolder() owns its arguments 292 FSMoveToFolder(list, new BEntry(&fSourceRef), FSUndoMoveMode(kMoveSelectionTo), NULL); 293 294 return B_OK; 295 } 296 297 298 status_t 299 UndoItemMove::Redo() 300 { 301 // FSMoveToFolder() owns its arguments 302 FSMoveToFolder(new BObjectList<entry_ref>(fSourceList), new BEntry(&fTargetRef), 303 FSUndoMoveMode(kMoveSelectionTo), NULL); 304 305 return B_OK; 306 } 307 308 309 // #pragma mark - 310 311 312 UndoItemFolder::UndoItemFolder(const entry_ref &ref) 313 : 314 fRef(ref) 315 { 316 } 317 318 319 UndoItemFolder::~UndoItemFolder() 320 { 321 } 322 323 324 status_t 325 UndoItemFolder::Undo() 326 { 327 FSDelete(new entry_ref(fRef), false, false); 328 return B_OK; 329 } 330 331 332 status_t 333 UndoItemFolder::Redo() 334 { 335 return FSCreateNewFolder(&fRef); 336 } 337 338 339 // #pragma mark - 340 341 342 UndoItemRename::UndoItemRename(const entry_ref &origRef, const entry_ref &ref) 343 : 344 fRef(ref), 345 fOrigRef(origRef) 346 { 347 } 348 349 350 UndoItemRename::UndoItemRename(const BEntry &entry, const char *newName) 351 { 352 entry.GetRef(&fOrigRef); 353 354 fRef = fOrigRef; 355 fRef.set_name(newName); 356 } 357 358 359 UndoItemRename::~UndoItemRename() 360 { 361 } 362 363 364 status_t 365 UndoItemRename::Undo() 366 { 367 BEntry entry(&fRef, false); 368 return entry.Rename(fOrigRef.name); 369 } 370 371 372 status_t 373 UndoItemRename::Redo() 374 { 375 BEntry entry(&fOrigRef, false); 376 return entry.Rename(fRef.name); 377 } 378 379 380 // #pragma mark - 381 382 383 UndoItemRenameVolume::UndoItemRenameVolume(BVolume &volume, const char *newName) 384 : 385 fVolume(volume), 386 fNewName(newName) 387 { 388 char *buffer = fOldName.LockBuffer(B_FILE_NAME_LENGTH); 389 if (buffer != NULL) { 390 fVolume.GetName(buffer); 391 fOldName.UnlockBuffer(); 392 } 393 } 394 395 396 UndoItemRenameVolume::~UndoItemRenameVolume() 397 { 398 } 399 400 401 status_t 402 UndoItemRenameVolume::Undo() 403 { 404 return fVolume.SetName(fOldName.String()); 405 } 406 407 408 status_t 409 UndoItemRenameVolume::Redo() 410 { 411 return fVolume.SetName(fNewName.String()); 412 } 413 414 415 // #pragma mark - 416 417 418 void 419 FSUndo() 420 { 421 BAutolock locker(sLock); 422 423 UndoItem *undoItem = sUndoList.FirstItem(); 424 if (undoItem == NULL) 425 return; 426 427 undoItem->Undo(); 428 // ToDo: evaluate return code 429 430 sUndoList.RemoveItem(undoItem); 431 432 if (sRedoList.CountItems() == kUndoRedoListMaxCount) 433 sRedoList.RemoveItem(sRedoList.LastItem()); 434 435 sRedoList.AddItem(undoItem, 0); 436 } 437 438 439 void 440 FSRedo() 441 { 442 BAutolock locker(sLock); 443 444 UndoItem *undoItem = sRedoList.FirstItem(); 445 if (undoItem == NULL) 446 return; 447 448 undoItem->Redo(); 449 // ToDo: evaluate return code 450 451 sRedoList.RemoveItem(undoItem); 452 453 if (sUndoList.CountItems() == kUndoRedoListMaxCount) 454 sUndoList.RemoveItem(sUndoList.LastItem()); 455 456 sUndoList.AddItem(undoItem, 0); 457 } 458 459 } // namespace BPrivate 460