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