xref: /haiku/src/apps/icon-o-matic/generic/command/MoveCommand.h (revision e1c4049fed1047bdb957b0529e1921e97ef94770)
1 /*
2  * Copyright 2006-2007, 2023, Haiku.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Stephan Aßmus <superstippi@gmx.de>
7  *		Zardshard
8  */
9 #ifndef MOVE_COMMAND_H
10 #define MOVE_COMMAND_H
11 
12 #include <new>
13 #include <stdio.h>
14 
15 #include <Catalog.h>
16 #include <Locale.h>
17 #include <StringFormat.h>
18 
19 #include "Command.h"
20 #include "Container.h"
21 #include "IconBuild.h"
22 
23 #undef B_TRANSLATION_CONTEXT
24 #define B_TRANSLATION_CONTEXT "Icon-O-Matic-MoveItemsCmd"
25 
26 using std::nothrow;
27 
28 _USING_ICON_NAMESPACE
29 
30 
31 /*! Moves a set of \c items to a different location in a \c container.
32 
33 	\note This class should be subclassed and the \c GetName member overridden.
34 */
35 template <class Type>
36 class MoveCommand : public Command {
37  public:
38 								MoveCommand(
39 									Container<Type>* container,
40 									Type** items,
41 									int32 count,
42 									int32 toIndex);
43 	virtual						~MoveCommand();
44 
45 	virtual	status_t			InitCheck();
46 
47 	virtual	status_t			Perform();
48 	virtual status_t			Undo();
49 
50 	virtual void				GetName(BString& name);
51 
52  protected:
53 			Container<Type>*	fContainer;
54 			Type**				fItems;
55 			int32*				fIndices;
56 			int32				fToIndex;
57 			int32				fCount;
58 };
59 
60 
61 template <class Type>
62 MoveCommand<Type>::MoveCommand(Container<Type>* container,
63 		Type** items,
64 		int32 count,
65 		int32 toIndex)
66 	: Command(),
67 	  fContainer(container),
68 	  fItems(items),
69 	  fIndices(count > 0 ? new (nothrow) int32[count] : NULL),
70 	  fToIndex(toIndex),
71 	  fCount(count)
72 {
73 	if (!fContainer || !fItems || !fIndices)
74 		return;
75 
76 	// init original shape indices and
77 	// adjust toIndex compensating for items that
78 	// are removed before that index
79 	int32 itemsBeforeIndex = 0;
80 	for (int32 i = 0; i < fCount; i++) {
81 		fIndices[i] = fContainer->IndexOf(fItems[i]);
82 		if (fIndices[i] >= 0 && fIndices[i] < fToIndex)
83 			itemsBeforeIndex++;
84 	}
85 	fToIndex -= itemsBeforeIndex;
86 }
87 
88 
89 template <class Type>
90 MoveCommand<Type>::~MoveCommand()
91 {
92 	delete[] fItems;
93 	delete[] fIndices;
94 }
95 
96 
97 template <class Type>
98 status_t
99 MoveCommand<Type>::InitCheck()
100 {
101 	if (!fContainer || !fItems || !fIndices)
102 		return B_NO_INIT;
103 
104 	// analyse the move, don't return B_OK in case
105 	// the container state does not change...
106 
107 	int32 index = fIndices[0];
108 		// NOTE: fIndices == NULL if fCount < 1
109 
110 	if (index != fToIndex) {
111 		// a change is guaranteed
112 		return B_OK;
113 	}
114 
115 	// the insertion index is the same as the index of the first
116 	// moved item, a change only occures if the indices of the
117 	// moved items is not contiguous
118 	bool isContiguous = true;
119 	for (int32 i = 1; i < fCount; i++) {
120 		if (fIndices[i] != index + 1) {
121 			isContiguous = false;
122 			break;
123 		}
124 		index = fIndices[i];
125 	}
126 	if (isContiguous) {
127 		// the container state will not change because of the move
128 		return B_ERROR;
129 	}
130 
131 	return B_OK;
132 }
133 
134 
135 template <class Type>
136 status_t
137 MoveCommand<Type>::Perform()
138 {
139 	status_t ret = B_OK;
140 
141 	// remove paths from container
142 	for (int32 i = 0; i < fCount; i++) {
143 		if (fItems[i] && !fContainer->RemoveItem(fItems[i])) {
144 			ret = B_ERROR;
145 			break;
146 		}
147 	}
148 	if (ret < B_OK)
149 		return ret;
150 
151 	// add paths to container at the insertion index
152 	int32 index = fToIndex;
153 	for (int32 i = 0; i < fCount; i++) {
154 		if (fItems[i] && !fContainer->AddItem(fItems[i], index++)) {
155 			ret = B_ERROR;
156 			break;
157 		}
158 	}
159 
160 	return ret;
161 }
162 
163 
164 template <class Type>
165 status_t
166 MoveCommand<Type>::Undo()
167 {
168 	status_t ret = B_OK;
169 
170 	// remove paths from container
171 	for (int32 i = 0; i < fCount; i++) {
172 		if (fItems[i] && !fContainer->RemoveItem(fItems[i])) {
173 			ret = B_ERROR;
174 			break;
175 		}
176 	}
177 	if (ret < B_OK)
178 		return ret;
179 
180 	// add paths to container at remembered indices
181 	for (int32 i = 0; i < fCount; i++) {
182 		if (fItems[i] && !fContainer->AddItem(fItems[i], fIndices[i])) {
183 			ret = B_ERROR;
184 			break;
185 		}
186 	}
187 
188 	return ret;
189 }
190 
191 
192 template <class Type>
193 void
194 MoveCommand<Type>::GetName(BString& name)
195 {
196 	static BStringFormat format(B_TRANSLATE("Move {0, plural, "
197 		"one{item} other{items}}"));
198 	format.Format(name, fCount);
199 }
200 #endif // MOVE_COMMAND_H
201