xref: /haiku/src/kits/tracker/FSUndoRedo.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
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