1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.ui.form.field;
35
36 import info.magnolia.cms.i18n.I18nContentSupport;
37 import info.magnolia.icons.MagnoliaIcons;
38 import info.magnolia.objectfactory.ComponentProvider;
39 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
40 import info.magnolia.ui.form.field.definition.ConfiguredFieldDefinition;
41 import info.magnolia.ui.form.field.definition.MultiValueFieldDefinition;
42 import info.magnolia.ui.form.field.factory.FieldFactoryFactory;
43 import info.magnolia.ui.form.field.transformer.TransformedProperty;
44 import info.magnolia.ui.form.field.transformer.Transformer;
45 import info.magnolia.ui.form.field.transformer.multi.MultiTransformer;
46 import info.magnolia.ui.framework.ioc.AdmincentralFlavour;
47 import info.magnolia.ui.theme.ResurfaceTheme;
48
49 import java.util.stream.StreamSupport;
50
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54 import com.google.common.base.Function;
55 import com.google.common.base.Optional;
56 import com.google.common.base.Predicates;
57 import com.google.common.collect.Iterators;
58 import com.vaadin.ui.Alignment;
59 import com.vaadin.ui.Button;
60 import com.vaadin.ui.Component;
61 import com.vaadin.ui.HasComponents;
62 import com.vaadin.ui.NativeButton;
63 import com.vaadin.v7.data.Item;
64 import com.vaadin.v7.data.Property;
65 import com.vaadin.v7.data.util.PropertysetItem;
66 import com.vaadin.v7.ui.Field;
67 import com.vaadin.v7.ui.HorizontalLayout;
68 import com.vaadin.v7.ui.VerticalLayout;
69
70
71
72
73
74
75
76
77
78
79
80
81
82 @Deprecated
83 public class MultiField extends AbstractCustomMultiField<MultiValueFieldDefinition, PropertysetItem> {
84
85 private static final Logger log = LoggerFactory.getLogger(MultiField.class);
86
87 private final ConfiguredFieldDefinition fieldDefinition;
88
89 private final Button addButton = new NativeButton();
90 private String buttonCaptionAdd;
91 private String buttonCaptionRemove;
92 private String buttonCaptionMoveUp = "Move Up";
93 private String buttonCaptionMoveDown = "Move Down";
94 private boolean isOrderable = true;
95
96 public MultiField(MultiValueFieldDefinition definition, FieldFactoryFactory fieldFactoryFactory, ComponentProvider componentProvider, Item relatedFieldItem, I18NAuthoringSupport i18nAuthoringSupport) {
97 super(definition, fieldFactoryFactory, componentProvider, relatedFieldItem, i18nAuthoringSupport);
98 this.fieldDefinition = definition.getField();
99
100 if (definition.isReadOnly()) {
101 fieldDefinition.setReadOnly(true);
102 }
103 }
104
105
106
107
108 @Deprecated
109 public MultiField(MultiValueFieldDefinition definition, FieldFactoryFactory fieldFactoryFactory, I18nContentSupport i18nContentSupport, ComponentProvider componentProvider, Item relatedFieldItem) {
110 this(definition, fieldFactoryFactory, componentProvider, relatedFieldItem, null);
111 }
112
113 @Override
114 protected Component initContent() {
115
116 addStyleNames("linkfield", "multifield");
117 root = new VerticalLayout();
118 root.setSpacing(true);
119 root.setWidth(100, Unit.PERCENTAGE);
120 root.setHeight(-1, Unit.PIXELS);
121
122
123 addButton.setCaption(buttonCaptionAdd);
124 addButton.addStyleNames("magnoliabutton", "add");
125 addButton.addClickListener(clickEvent -> {
126 int newPropertyId;
127 Property<?> property = null;
128
129 Transformer<?> transformer = ((TransformedProperty<?>) getPropertyDataSource()).getTransformer();
130 PropertysetItem item = (PropertysetItem) getPropertyDataSource().getValue();
131
132 if (transformer instanceof MultiTransformer) {
133
134 property = ((MultiTransformer) transformer).createProperty();
135 newPropertyId = findPropertyId(item, property);
136 } else {
137
138 newPropertyId = item.getItemPropertyIds().size();
139 }
140
141 if (newPropertyId == -1) {
142 log.warn("Could not resolve new propertyId; cannot add new multifield entry to item '{}'.", item);
143 return;
144 }
145
146 root.addComponent(createEntryComponent(newPropertyId, property), root.getComponentCount() - 1);
147 });
148
149
150 initFields();
151
152 return root;
153 }
154
155
156
157
158
159 @Override
160 protected void initFields(PropertysetItem newValue) {
161 root.removeAllComponents();
162 for (Object propertyId : newValue.getItemPropertyIds()) {
163 Property<?> property = newValue.getItemProperty(propertyId);
164 root.addComponent(createEntryComponent(propertyId, property));
165 }
166 if (!this.definition.isReadOnly()) {
167 root.addComponent(addButton);
168 }
169 }
170
171
172
173
174
175
176
177 private Component createEntryComponent(Object propertyId, Property<?> property) {
178 final HorizontalLayout layout = new HorizontalLayout();
179 layout.setWidth(100, Unit.PERCENTAGE);
180 layout.setHeight(-1, Unit.PIXELS);
181
182 final Field<?> field = createLocalField(fieldDefinition, property, true);
183 layout.addComponent(field);
184
185
186 if (property == null) {
187 property = field.getPropertyDataSource();
188 ((PropertysetItem) getPropertyDataSource().getValue()).addItemProperty(propertyId, property);
189 }
190 final Property<?> propertyReference = property;
191
192 layout.setWidth(100, Unit.PERCENTAGE);
193
194
195 layout.setExpandRatio(field, 1);
196 if (definition.isReadOnly()) {
197 return layout;
198 }
199
200 if (isOrderable()) {
201
202 Button moveUpButton = new Button(MagnoliaIcons.ARROW2_N, clickEvent -> {
203 onMove(layout, propertyReference, true);
204 clickEvent.getButton().focus();
205 });
206 moveUpButton.addStyleNames("inline", "move-up");
207 moveUpButton.setDescription(buttonCaptionMoveUp);
208
209
210 final Button moveDownButton = new Button(MagnoliaIcons.ARROW2_S, clickEvent -> {
211 onMove(layout, propertyReference, false);
212 clickEvent.getButton().focus();
213 });
214 moveDownButton.addStyleNames("inline", "move-down");
215 moveDownButton.setDescription(buttonCaptionMoveDown);
216
217 layout.addComponents(moveUpButton, moveDownButton);
218
219 layout.setComponentAlignment(moveUpButton, Alignment.BOTTOM_RIGHT);
220 layout.setComponentAlignment(moveDownButton, Alignment.BOTTOM_RIGHT);
221 }
222
223
224 Button deleteButton = new Button(MagnoliaIcons.TRASH, clickEvent -> onDelete(layout, propertyReference));
225 deleteButton.addStyleNames("inline", "trash");
226 deleteButton.setDescription(buttonCaptionRemove);
227
228 layout.addComponents(deleteButton);
229 layout.setComponentAlignment(deleteButton, Alignment.BOTTOM_RIGHT);
230
231 if (!AdmincentralFlavour.get().isM5()) {
232 StreamSupport.stream(layout.spliterator(), false)
233 .filter(Button.class::isInstance)
234 .forEach(button -> {
235 button.addStyleName(ResurfaceTheme.BUTTON_ICON);
236 layout.setComponentAlignment(button, Alignment.MIDDLE_RIGHT);
237 });
238 }
239
240 return layout;
241 }
242
243 @Override
244 public Class<? extends PropertysetItem> getType() {
245 return PropertysetItem.class;
246 }
247
248
249
250
251 public void setButtonCaptionAdd(String buttonCaptionAdd) {
252 this.buttonCaptionAdd = buttonCaptionAdd;
253 }
254
255 public void setButtonCaptionRemove(String buttonCaptionRemove) {
256 this.buttonCaptionRemove = buttonCaptionRemove;
257 }
258
259
260
261
262
263
264
265 private void removeValueProperty(int fromIndex) {
266 getValue().removeItemProperty(fromIndex);
267 int valuesSize = getValue().getItemPropertyIds().size();
268 if (fromIndex == valuesSize) {
269 return;
270 }
271 while (fromIndex < valuesSize) {
272 int toIndex = fromIndex;
273 fromIndex +=1;
274 getValue().addItemProperty(toIndex, getValue().getItemProperty(fromIndex));
275 getValue().removeItemProperty(fromIndex);
276 }
277 }
278
279
280
281
282 private void switchItemProperties(Object firstPropertyId, Object secondPropertyId) {
283 Property propertyFirst = getValue().getItemProperty(firstPropertyId);
284 Property propertySecond = getValue().getItemProperty(secondPropertyId);
285
286 try {
287 PropertysetItem storedValues = (PropertysetItem) getValue().clone();
288 if (storedValues != null) {
289 for (Object propertyId : storedValues.getItemPropertyIds()) {
290 getValue().removeItemProperty(propertyId);
291 if (propertyId == firstPropertyId) {
292 getValue().addItemProperty(firstPropertyId, propertySecond);
293 } else if (propertyId == secondPropertyId) {
294 getValue().addItemProperty(secondPropertyId, propertyFirst);
295 } else {
296 getValue().addItemProperty(propertyId, storedValues.getItemProperty(propertyId));
297 }
298 }
299 getPropertyDataSource().setValue(getValue());
300 }
301 } catch (CloneNotSupportedException e) {
302 log.error("Unable to switch properties on MultiField. Unable to clone PropertysetItem.", e);
303 }
304
305 }
306
307 private void onDelete(Component layout, Property<?> propertyReference) {
308 root.removeComponent(layout);
309 Transformer<?> transformer = ((TransformedProperty<?>) getPropertyDataSource()).getTransformer();
310
311
312 Object propertyId = findPropertyId(getValue(), propertyReference);
313
314 if (transformer instanceof MultiTransformer) {
315 ((MultiTransformer) transformer).removeProperty(propertyId);
316 } else {
317 if (propertyId.getClass().isAssignableFrom(Integer.class)) {
318 removeValueProperty((Integer) propertyId);
319 } else {
320 log.error("Property id {} is not an integer and as such property can't be removed", propertyId);
321 }
322 getPropertyDataSource().setValue(getValue());
323 }
324 }
325
326
327
328
329
330 private void onMove(Component layout, Property<?> propertyReference, boolean moveUp) {
331 int currentPosition = root.getComponentIndex(layout);
332 int switchPosition = currentPosition + (moveUp ? -1 : 1);
333
334 Field[] fields = Iterators.toArray(Iterators.filter(Iterators.transform(root.iterator(), new Function<Component, Field>() {
335 @Override
336 public Field apply(Component input) {
337 if (input instanceof HasComponents) {
338 Optional<Component> field = Iterators.tryFind(((HasComponents) input).iterator(), Predicates.instanceOf(Field.class));
339 if (field.isPresent()) {
340 return (Field) field.get();
341 }
342 }
343 return null;
344 }
345 }), Predicates.notNull()), Field.class);
346
347 if (moveUp && currentPosition != 0 || (!moveUp && currentPosition != fields.length - 1)) {
348 Field switchField = fields[switchPosition];
349 Object currentPropertyId = MultiField.this.findPropertyId(getValue(), propertyReference);
350 Object switchPropertyId = MultiField.this.findPropertyId(getValue(), switchField.getPropertyDataSource());
351
352 root.replaceComponent(root.getComponent(currentPosition), root.getComponent(switchPosition));
353 switchItemProperties(currentPropertyId, switchPropertyId);
354 }
355 }
356
357 public boolean isOrderable() {
358 return isOrderable;
359 }
360
361 public void setOrderable(boolean orderable) {
362 isOrderable = orderable;
363 }
364 }