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 48 class 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 66 class 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 86 class 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 100 class 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 117 static status_t 118 ChangeListSource(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 135 static void 136 AddUndoItem(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 152 Undo::~Undo() 153 { 154 if (fUndo != NULL) 155 AddUndoItem(fUndo); 156 } 157 158 159 void 160 Undo::UpdateEntry(BEntry* entry, const char* destName) 161 { 162 if (fUndo != NULL) 163 fUndo->UpdateEntry(entry, destName); 164 } 165 166 167 void 168 Undo::Remove() 169 { 170 delete fUndo; 171 fUndo = NULL; 172 } 173 174 175 MoveCopyUndo::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 185 NewFolderUndo::NewFolderUndo(const entry_ref &ref) 186 { 187 fUndo = new UndoItemFolder(ref); 188 } 189 190 191 RenameUndo::RenameUndo(BEntry &entry, const char* newName) 192 { 193 fUndo = new UndoItemRename(entry, newName); 194 } 195 196 197 RenameVolumeUndo::RenameVolumeUndo(BVolume &volume, const char* newName) 198 { 199 fUndo = new UndoItemRenameVolume(volume, newName); 200 } 201 202 203 // #pragma mark - 204 205 206 UndoItemCopy::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 226 UndoItemCopy::~UndoItemCopy() 227 { 228 } 229 230 231 status_t 232 UndoItemCopy::Undo() 233 { 234 FSDeleteRefList(new BObjectList<entry_ref>(fTargetList), true, false); 235 return B_OK; 236 } 237 238 239 status_t 240 UndoItemCopy::Redo() 241 { 242 FSMoveToFolder(new BObjectList<entry_ref>(fSourceList), 243 new BEntry(&fTargetRef), FSUndoMoveMode(fMoveMode), NULL); 244 245 return B_OK; 246 } 247 248 249 void 250 UndoItemCopy::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 270 UndoItemMove::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 286 UndoItemMove::~UndoItemMove() 287 { 288 } 289 290 291 status_t 292 UndoItemMove::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 306 status_t 307 UndoItemMove::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 320 UndoItemFolder::UndoItemFolder(const entry_ref &ref) 321 : 322 fRef(ref) 323 { 324 } 325 326 327 UndoItemFolder::~UndoItemFolder() 328 { 329 } 330 331 332 status_t 333 UndoItemFolder::Undo() 334 { 335 FSDelete(new entry_ref(fRef), false, false); 336 return B_OK; 337 } 338 339 340 status_t 341 UndoItemFolder::Redo() 342 { 343 return FSCreateNewFolder(&fRef); 344 } 345 346 347 // #pragma mark - 348 349 350 UndoItemRename::UndoItemRename(const entry_ref &origRef, const entry_ref &ref) 351 : 352 fRef(ref), 353 fOrigRef(origRef) 354 { 355 } 356 357 358 UndoItemRename::UndoItemRename(const BEntry &entry, const char* newName) 359 { 360 entry.GetRef(&fOrigRef); 361 362 fRef = fOrigRef; 363 fRef.set_name(newName); 364 } 365 366 367 UndoItemRename::~UndoItemRename() 368 { 369 } 370 371 372 status_t 373 UndoItemRename::Undo() 374 { 375 BEntry entry(&fRef, false); 376 return entry.Rename(fOrigRef.name); 377 } 378 379 380 status_t 381 UndoItemRename::Redo() 382 { 383 BEntry entry(&fOrigRef, false); 384 return entry.Rename(fRef.name); 385 } 386 387 388 // #pragma mark - 389 390 391 UndoItemRenameVolume::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 405 UndoItemRenameVolume::~UndoItemRenameVolume() 406 { 407 } 408 409 410 status_t 411 UndoItemRenameVolume::Undo() 412 { 413 return fVolume.SetName(fOldName.String()); 414 } 415 416 417 status_t 418 UndoItemRenameVolume::Redo() 419 { 420 return fVolume.SetName(fNewName.String()); 421 } 422 423 424 // #pragma mark - 425 426 427 void 428 FSUndo() 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 448 void 449 FSRedo() 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