xref: /haiku/src/kits/tracker/FSUndoRedo.cpp (revision d64b771b96050fca8ff1859daa5ec44ff3493af7)
1 /*
2 Open Tracker License
3 
4 Terms and Conditions
5 
6 Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7 
8 Permission is hereby granted, free of charge, to any person obtaining a copy of
9 this software and associated documentation files (the "Software"), to deal in
10 the Software without restriction, including without limitation the rights to
11 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12 of the Software, and to permit persons to whom the Software is furnished to do
13 so, subject to the following conditions:
14 
15 The above copyright notice and this permission notice applies to all licensees
16 and shall be included in all copies or substantial portions of the Software.
17 
18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21 BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24 
25 Except as contained in this notice, the name of Be Incorporated shall not be
26 used in advertising or otherwise to promote the sale, use or other dealings in
27 this Software without prior written authorization from Be Incorporated.
28 
29 Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30 of Be Incorporated in the United States and other countries. Other brand product
31 names are registered trademarks or trademarks of their respective holders.
32 All rights reserved.
33 */
34 
35 
36 #include "Commands.h"
37 #include "FSUndoRedo.h"
38 #include "FSUtils.h"
39 
40 #include <Autolock.h>
41 #include <Volume.h>
42 #include <Node.h>
43 #include <Path.h>
44 
45 
46 static const int32 kUndoRedoListMaxCount = 20;
47 
48 
49 namespace BPrivate {
50 
51 class UndoItem {
52 	public:
53 		virtual ~UndoItem() {}
54 
55 		virtual status_t Undo() = 0;
56 		virtual status_t Redo() = 0;
57 
58 		virtual void UpdateEntry(BEntry* /*entry*/, const char* /*name*/) {}
59 			// updates the name of the target from the source entry "entry"
60 };
61 
62 static BObjectList<UndoItem> sUndoList, sRedoList;
63 static BLocker sLock("undo");
64 
65 class UndoItemCopy : public UndoItem {
66 	public:
67 		UndoItemCopy(BObjectList<entry_ref>* sourceList, BDirectory &target,
68 			BList* pointList, uint32 moveMode);
69 		virtual ~UndoItemCopy();
70 
71 		virtual status_t Undo();
72 		virtual status_t Redo();
73 		virtual void UpdateEntry(BEntry* entry, const char* name);
74 
75 	private:
76 		BObjectList<entry_ref> fSourceList;
77 		BObjectList<entry_ref> fTargetList;
78 		entry_ref	fSourceRef, fTargetRef;
79 		uint32		fMoveMode;
80 };
81 
82 
83 class UndoItemMove : public UndoItem {
84 	public:
85 		/** source - list of file(s) that were moved.  Assumes ownership.
86 		 *	origfolder - location it was moved from
87 		 */
88 		UndoItemMove(BObjectList<entry_ref>* sourceList, BDirectory &target,
89 			BList* pointList);
90 		virtual ~UndoItemMove();
91 
92 		virtual status_t Undo();
93 		virtual status_t Redo();
94 
95 	private:
96 		BObjectList<entry_ref> fSourceList;
97 		entry_ref	fSourceRef, fTargetRef;
98 };
99 
100 
101 class UndoItemFolder : public UndoItem {
102 	public:
103 		UndoItemFolder(const entry_ref &ref);
104 			// ref - entry_ref indicating the folder created
105 		virtual ~UndoItemFolder();
106 
107 		virtual status_t Undo();
108 		virtual status_t Redo();
109 
110 	private:
111 		// this ref has two different meanings in the different states of
112 		// this object:
113 		//  - Undo() - fRef indicates the folder that was created via
114 		//    FSCreateNewFolderIn(...)
115 		//  - Redo() - fRef indicates the folder in which
116 		//    FSCreateNewFolderIn() should be performed
117 		entry_ref	fRef;
118 };
119 
120 
121 class UndoItemRename : public UndoItem {
122 	public:
123 		UndoItemRename(const entry_ref &origRef, const entry_ref &ref);
124 		UndoItemRename(const BEntry &entry, const char* newName);
125 		virtual ~UndoItemRename();
126 
127 		virtual status_t Undo();
128 		virtual status_t Redo();
129 
130 	private:
131 		entry_ref	fRef, fOrigRef;
132 };
133 
134 
135 class UndoItemRenameVolume : public UndoItem {
136 	public:
137 		UndoItemRenameVolume(BVolume &volume, const char* newName);
138 		virtual ~UndoItemRenameVolume();
139 
140 		virtual status_t Undo();
141 		virtual status_t Redo();
142 
143 	private:
144 		BVolume	fVolume;
145 		BString	fOldName, fNewName;
146 };
147 
148 
149 //--------------------------
150 
151 
152 static status_t
153 ChangeListSource(BObjectList<entry_ref> &list, BEntry &entry)
154 {
155 	node_ref source;
156 	if (entry.GetNodeRef(&source) != B_OK)
157 		return B_ERROR;
158 
159 	for (int32 index = 0; index < list.CountItems(); index++) {
160 		entry_ref* ref = list.ItemAt(index);
161 
162 		ref->device = source.device;
163 		ref->directory = source.node;
164 	}
165 
166 	return B_OK;
167 }
168 
169 
170 static void
171 AddUndoItem(UndoItem* item)
172 {
173 	BAutolock locker(sLock);
174 
175 	// we have a restricted number of possible undos
176 	if (sUndoList.CountItems() == kUndoRedoListMaxCount)
177 		sUndoList.RemoveItem(sUndoList.LastItem());
178 
179 	sUndoList.AddItem(item, 0);
180 	sRedoList.MakeEmpty();
181 }
182 
183 
184 //	#pragma mark - Undo
185 
186 
187 Undo::~Undo()
188 {
189 	if (fUndo != NULL)
190 		AddUndoItem(fUndo);
191 }
192 
193 
194 void
195 Undo::UpdateEntry(BEntry* entry, const char* destName)
196 {
197 	if (fUndo != NULL)
198 		fUndo->UpdateEntry(entry, destName);
199 }
200 
201 
202 void
203 Undo::Remove()
204 {
205 	delete fUndo;
206 	fUndo = NULL;
207 }
208 
209 
210 MoveCopyUndo::MoveCopyUndo(BObjectList<entry_ref>* sourceList,
211 	BDirectory &dest, BList* pointList, uint32 moveMode)
212 {
213 	if (moveMode == kMoveSelectionTo)
214 		fUndo = new UndoItemMove(sourceList, dest, pointList);
215 	else
216 		fUndo = new UndoItemCopy(sourceList, dest, pointList, moveMode);
217 }
218 
219 
220 NewFolderUndo::NewFolderUndo(const entry_ref &ref)
221 {
222 	fUndo = new UndoItemFolder(ref);
223 }
224 
225 
226 RenameUndo::RenameUndo(BEntry &entry, const char* newName)
227 {
228 	fUndo = new UndoItemRename(entry, newName);
229 }
230 
231 
232 RenameVolumeUndo::RenameVolumeUndo(BVolume &volume, const char* newName)
233 {
234 	fUndo = new UndoItemRenameVolume(volume, newName);
235 }
236 
237 
238 //	#pragma mark - UndoItemCopy
239 
240 
241 UndoItemCopy::UndoItemCopy(BObjectList<entry_ref>* sourceList,
242 	BDirectory &target, BList* /*pointList*/, uint32 moveMode)
243 	:
244 	fSourceList(*sourceList),
245 	fTargetList(*sourceList),
246 	fMoveMode(moveMode)
247 {
248 	BEntry entry(sourceList->ItemAt(0));
249 
250 	BEntry sourceEntry;
251 	entry.GetParent(&sourceEntry);
252 	sourceEntry.GetRef(&fSourceRef);
253 
254 	BEntry targetEntry;
255 	target.GetEntry(&targetEntry);
256 	targetEntry.GetRef(&fTargetRef);
257 	ChangeListSource(fTargetList, targetEntry);
258 }
259 
260 
261 UndoItemCopy::~UndoItemCopy()
262 {
263 }
264 
265 
266 status_t
267 UndoItemCopy::Undo()
268 {
269 	FSDeleteRefList(new BObjectList<entry_ref>(fTargetList), true, false);
270 	return B_OK;
271 }
272 
273 
274 status_t
275 UndoItemCopy::Redo()
276 {
277 	FSMoveToFolder(new BObjectList<entry_ref>(fSourceList),
278 		new BEntry(&fTargetRef), FSUndoMoveMode(fMoveMode), NULL);
279 
280 	return B_OK;
281 }
282 
283 
284 void
285 UndoItemCopy::UpdateEntry(BEntry* entry, const char* name)
286 {
287 	entry_ref changedRef;
288 	if (entry->GetRef(&changedRef) != B_OK)
289 		return;
290 
291 	for (int32 index = 0; index < fSourceList.CountItems(); index++) {
292 		entry_ref* ref = fSourceList.ItemAt(index);
293 		if (changedRef != *ref)
294 			continue;
295 
296 		ref = fTargetList.ItemAt(index);
297 		ref->set_name(name);
298 	}
299 }
300 
301 
302 //	#pragma mark - UndoItemMove
303 
304 
305 UndoItemMove::UndoItemMove(BObjectList<entry_ref>* sourceList,
306 	BDirectory &target, BList* /*pointList*/)
307 	:
308 	fSourceList(*sourceList)
309 {
310 	BEntry entry(sourceList->ItemAt(0));
311 	BEntry source;
312 	entry.GetParent(&source);
313 	source.GetRef(&fSourceRef);
314 
315 	BEntry targetEntry;
316 	target.GetEntry(&targetEntry);
317 	targetEntry.GetRef(&fTargetRef);
318 }
319 
320 
321 UndoItemMove::~UndoItemMove()
322 {
323 }
324 
325 
326 status_t
327 UndoItemMove::Undo()
328 {
329 	BObjectList<entry_ref>* list = new BObjectList<entry_ref>(fSourceList);
330 	BEntry entry(&fTargetRef);
331 	ChangeListSource(*list, entry);
332 
333 	// FSMoveToFolder() owns its arguments
334 	FSMoveToFolder(list, new BEntry(&fSourceRef),
335 		FSUndoMoveMode(kMoveSelectionTo), NULL);
336 
337 	return B_OK;
338 }
339 
340 
341 status_t
342 UndoItemMove::Redo()
343 {
344 	// FSMoveToFolder() owns its arguments
345 	FSMoveToFolder(new BObjectList<entry_ref>(fSourceList),
346 		new BEntry(&fTargetRef), FSUndoMoveMode(kMoveSelectionTo), NULL);
347 
348 	return B_OK;
349 }
350 
351 
352 //	#pragma mark -
353 
354 
355 UndoItemFolder::UndoItemFolder(const entry_ref &ref)
356 	:
357 	fRef(ref)
358 {
359 }
360 
361 
362 UndoItemFolder::~UndoItemFolder()
363 {
364 }
365 
366 
367 status_t
368 UndoItemFolder::Undo()
369 {
370 	FSDelete(new entry_ref(fRef), false, false);
371 	return B_OK;
372 }
373 
374 
375 status_t
376 UndoItemFolder::Redo()
377 {
378 	return FSCreateNewFolder(&fRef);
379 }
380 
381 
382 //	#pragma mark -
383 
384 
385 UndoItemRename::UndoItemRename(const entry_ref &origRef, const entry_ref &ref)
386 	:
387 	fRef(ref),
388 	fOrigRef(origRef)
389 {
390 }
391 
392 
393 UndoItemRename::UndoItemRename(const BEntry &entry, const char* newName)
394 {
395 	entry.GetRef(&fOrigRef);
396 
397 	fRef = fOrigRef;
398 	fRef.set_name(newName);
399 }
400 
401 
402 UndoItemRename::~UndoItemRename()
403 {
404 }
405 
406 
407 status_t
408 UndoItemRename::Undo()
409 {
410 	BEntry entry(&fRef, false);
411 	return entry.Rename(fOrigRef.name);
412 }
413 
414 
415 status_t
416 UndoItemRename::Redo()
417 {
418 	BEntry entry(&fOrigRef, false);
419 	return entry.Rename(fRef.name);
420 }
421 
422 
423 //	#pragma mark - UndoItemRenameVolume
424 
425 
426 UndoItemRenameVolume::UndoItemRenameVolume(BVolume &volume,
427 	const char* newName)
428 	:
429 	fVolume(volume),
430 	fNewName(newName)
431 {
432 	char* buffer = fOldName.LockBuffer(B_FILE_NAME_LENGTH);
433 	if (buffer != NULL) {
434 		fVolume.GetName(buffer);
435 		fOldName.UnlockBuffer();
436 	}
437 }
438 
439 
440 UndoItemRenameVolume::~UndoItemRenameVolume()
441 {
442 }
443 
444 
445 status_t
446 UndoItemRenameVolume::Undo()
447 {
448 	return fVolume.SetName(fOldName.String());
449 }
450 
451 
452 status_t
453 UndoItemRenameVolume::Redo()
454 {
455 	return fVolume.SetName(fNewName.String());
456 }
457 
458 
459 //	#pragma mark - FSUndo() and FSRedo() functions
460 
461 
462 void
463 FSUndo()
464 {
465 	BAutolock locker(sLock);
466 
467 	UndoItem* undoItem = sUndoList.FirstItem();
468 	if (undoItem == NULL)
469 		return;
470 
471 	undoItem->Undo();
472 		// ToDo: evaluate return code
473 
474 	sUndoList.RemoveItem(undoItem);
475 
476 	if (sRedoList.CountItems() == kUndoRedoListMaxCount)
477 		sRedoList.RemoveItem(sRedoList.LastItem());
478 
479 	sRedoList.AddItem(undoItem, 0);
480 }
481 
482 
483 void
484 FSRedo()
485 {
486 	BAutolock locker(sLock);
487 
488 	UndoItem* undoItem = sRedoList.FirstItem();
489 	if (undoItem == NULL)
490 		return;
491 
492 	undoItem->Redo();
493 		// ToDo: evaluate return code
494 
495 	sRedoList.RemoveItem(undoItem);
496 
497 	if (sUndoList.CountItems() == kUndoRedoListMaxCount)
498 		sUndoList.RemoveItem(sUndoList.LastItem());
499 
500 	sUndoList.AddItem(undoItem, 0);
501 }
502 
503 }	// namespace BPrivate
504