1/*
2Open Tracker License
3
4Terms and Conditions
5
6Copyright (c) 1991-2000, Be Incorporated. All rights reserved.
7
8Permission is hereby granted, free of charge, to any person obtaining a copy of
9this software and associated documentation files (the "Software"), to deal in
10the Software without restriction, including without limitation the rights to
11use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
12of the Software, and to permit persons to whom the Software is furnished to do
13so, subject to the following conditions:
14
15The above copyright notice and this permission notice applies to all licensees
16and shall be included in all copies or substantial portions of the Software.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF TITLE, MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
21BE INCORPORATED BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
22AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION
23WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24
25Except as contained in this notice, the name of Be Incorporated shall not be
26used in advertising or otherwise to promote the sale, use or other dealings in
27this Software without prior written authorization from Be Incorporated.
28
29Tracker(TM), Be(R), BeOS(R), and BeIA(TM) are trademarks or registered trademarks
30of Be Incorporated in the United States and other countries. Other brand product
31names are registered trademarks or trademarks of their respective holders.
32All 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
46static const int32 kUndoRedoListMaxCount = 20;
47
48
49namespace BPrivate {
50
51class 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
62static BObjectList<UndoItem> sUndoList, sRedoList;
63static BLocker sLock("undo");
64
65class 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
83class 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
101class 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
121class 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
135class 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
152static status_t
153ChangeListSource(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
170static void
171AddUndoItem(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
187Undo::~Undo()
188{
189	if (fUndo != NULL)
190		AddUndoItem(fUndo);
191}
192
193
194void
195Undo::UpdateEntry(BEntry* entry, const char* destName)
196{
197	if (fUndo != NULL)
198		fUndo->UpdateEntry(entry, destName);
199}
200
201
202void
203Undo::Remove()
204{
205	delete fUndo;
206	fUndo = NULL;
207}
208
209
210MoveCopyUndo::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
220NewFolderUndo::NewFolderUndo(const entry_ref &ref)
221{
222	fUndo = new UndoItemFolder(ref);
223}
224
225
226RenameUndo::RenameUndo(BEntry &entry, const char* newName)
227{
228	fUndo = new UndoItemRename(entry, newName);
229}
230
231
232RenameVolumeUndo::RenameVolumeUndo(BVolume &volume, const char* newName)
233{
234	fUndo = new UndoItemRenameVolume(volume, newName);
235}
236
237
238//	#pragma mark - UndoItemCopy
239
240
241UndoItemCopy::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
261UndoItemCopy::~UndoItemCopy()
262{
263}
264
265
266status_t
267UndoItemCopy::Undo()
268{
269	FSDeleteRefList(new BObjectList<entry_ref>(fTargetList), true, false);
270	return B_OK;
271}
272
273
274status_t
275UndoItemCopy::Redo()
276{
277	FSMoveToFolder(new BObjectList<entry_ref>(fSourceList),
278		new BEntry(&fTargetRef), FSUndoMoveMode(fMoveMode), NULL);
279
280	return B_OK;
281}
282
283
284void
285UndoItemCopy::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
305UndoItemMove::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
321UndoItemMove::~UndoItemMove()
322{
323}
324
325
326status_t
327UndoItemMove::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
341status_t
342UndoItemMove::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
355UndoItemFolder::UndoItemFolder(const entry_ref &ref)
356	:
357	fRef(ref)
358{
359}
360
361
362UndoItemFolder::~UndoItemFolder()
363{
364}
365
366
367status_t
368UndoItemFolder::Undo()
369{
370	FSDelete(new entry_ref(fRef), false, false);
371	return B_OK;
372}
373
374
375status_t
376UndoItemFolder::Redo()
377{
378	return FSCreateNewFolder(&fRef);
379}
380
381
382//	#pragma mark -
383
384
385UndoItemRename::UndoItemRename(const entry_ref &origRef, const entry_ref &ref)
386	:
387	fRef(ref),
388	fOrigRef(origRef)
389{
390}
391
392
393UndoItemRename::UndoItemRename(const BEntry &entry, const char* newName)
394{
395	entry.GetRef(&fOrigRef);
396
397	fRef = fOrigRef;
398	fRef.set_name(newName);
399}
400
401
402UndoItemRename::~UndoItemRename()
403{
404}
405
406
407status_t
408UndoItemRename::Undo()
409{
410	BEntry entry(&fRef, false);
411	return entry.Rename(fOrigRef.name);
412}
413
414
415status_t
416UndoItemRename::Redo()
417{
418	BEntry entry(&fOrigRef, false);
419	return entry.Rename(fRef.name);
420}
421
422
423//	#pragma mark - UndoItemRenameVolume
424
425
426UndoItemRenameVolume::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
440UndoItemRenameVolume::~UndoItemRenameVolume()
441{
442}
443
444
445status_t
446UndoItemRenameVolume::Undo()
447{
448	return fVolume.SetName(fOldName.String());
449}
450
451
452status_t
453UndoItemRenameVolume::Redo()
454{
455	return fVolume.SetName(fNewName.String());
456}
457
458
459//	#pragma mark - FSUndo() and FSRedo() functions
460
461
462void
463FSUndo()
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
483void
484FSRedo()
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