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