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>
MoveCommand(Container<Type> * container,Type ** items,int32 count,int32 toIndex)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>
~MoveCommand()90 MoveCommand<Type>::~MoveCommand()
91 {
92 delete[] fItems;
93 delete[] fIndices;
94 }
95
96
97 template <class Type>
98 status_t
InitCheck()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
Perform()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
Undo()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
GetName(BString & name)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