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