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 addStyleName("force-show-field-captions");
118 root = new VerticalLayout();
119 root.setSpacing(true);
120 root.setWidth(100, Unit.PERCENTAGE);
121 root.setHeight(-1, Unit.PIXELS);
122
123
124 addButton.setCaption(buttonCaptionAdd);
125 addButton.addStyleNames("magnoliabutton", "add");
126 addButton.addClickListener(clickEvent -> {
127 int newPropertyId;
128 Property<?> property = null;
129
130 Transformer<?> transformer = ((TransformedProperty<?>) getPropertyDataSource()).getTransformer();
131 PropertysetItem item = (PropertysetItem) getPropertyDataSource().getValue();
132
133 if (transformer instanceof MultiTransformer) {
134
135 property = ((MultiTransformer) transformer).createProperty();
136 newPropertyId = findPropertyId(item, property);
137 } else {
138
139 newPropertyId = item.getItemPropertyIds().size();
140 }
141
142 if (newPropertyId == -1) {
143 log.warn("Could not resolve new propertyId; cannot add new multifield entry to item '{}'.", item);
144 return;
145 }
146
147 root.addComponent(createEntryComponent(newPropertyId, property), root.getComponentCount() - 1);
148 });
149
150
151 initFields();
152
153 return root;
154 }
155
156
157
158
159
160 @Override
161 protected void initFields(PropertysetItem newValue) {
162 root.removeAllComponents();
163 for (Object propertyId : newValue.getItemPropertyIds()) {
164 Property<?> property = newValue.getItemProperty(propertyId);
165 root.addComponent(createEntryComponent(propertyId, property));
166 }
167 if (!this.definition.isReadOnly()) {
168 root.addComponent(addButton);
169 }
170 }
171
172
173
174
175
176
177
178 private Component createEntryComponent(Object propertyId, Property<?> property) {
179 final HorizontalLayout layout = new HorizontalLayout();
180 layout.setWidth(100, Unit.PERCENTAGE);
181 layout.setHeight(-1, Unit.PIXELS);
182
183 final Field<?> field = createLocalField(fieldDefinition, property, true);
184 layout.addComponent(field);
185
186
187 if (property == null) {
188 property = field.getPropertyDataSource();
189 ((PropertysetItem) getPropertyDataSource().getValue()).addItemProperty(propertyId, property);
190 }
191 final Property<?> propertyReference = property;
192
193 layout.setWidth(100, Unit.PERCENTAGE);
194
195
196 layout.setExpandRatio(field, 1);
197 if (definition.isReadOnly()) {
198 return layout;
199 }
200
201 if (isOrderable()) {
202
203 Button moveUpButton = new Button(MagnoliaIcons.ARROW2_N, clickEvent -> {
204 onMove(layout, propertyReference, true);
205 clickEvent.getButton().focus();
206 });
207 moveUpButton.addStyleNames("inline", "move-up");
208 moveUpButton.setDescription(buttonCaptionMoveUp);
209
210
211 final Button moveDownButton = new Button(MagnoliaIcons.ARROW2_S, clickEvent -> {
212 onMove(layout, propertyReference, false);
213 clickEvent.getButton().focus();
214 });
215 moveDownButton.addStyleNames("inline", "move-down");
216 moveDownButton.setDescription(buttonCaptionMoveDown);
217
218 layout.addComponents(moveUpButton, moveDownButton);
219
220 layout.setComponentAlignment(moveUpButton, Alignment.BOTTOM_RIGHT);
221 layout.setComponentAlignment(moveDownButton, Alignment.BOTTOM_RIGHT);
222 }
223
224
225 Button deleteButton = new Button(MagnoliaIcons.TRASH, clickEvent -> onDelete(layout, propertyReference));
226 deleteButton.addStyleNames("inline", "trash");
227 deleteButton.setDescription(buttonCaptionRemove);
228
229 layout.addComponents(deleteButton);
230 layout.setComponentAlignment(deleteButton, Alignment.BOTTOM_RIGHT);
231
232 if (!AdmincentralFlavour.get().isM5()) {
233 StreamSupport.stream(layout.spliterator(), false)
234 .filter(Button.class::isInstance)
235 .forEach(button -> {
236 button.addStyleName(ResurfaceTheme.BUTTON_ICON);
237 layout.setComponentAlignment(button, Alignment.MIDDLE_RIGHT);
238 });
239 }
240
241 return layout;
242 }
243
244 @Override
245 public Class<? extends PropertysetItem> getType() {
246 return PropertysetItem.class;
247 }
248
249
250
251
252 public void setButtonCaptionAdd(String buttonCaptionAdd) {
253 this.buttonCaptionAdd = buttonCaptionAdd;
254 }
255
256 public void setButtonCaptionRemove(String buttonCaptionRemove) {
257 this.buttonCaptionRemove = buttonCaptionRemove;
258 }
259
260
261
262
263
264
265
266 private void removeValueProperty(int fromIndex) {
267 getValue().removeItemProperty(fromIndex);
268 int valuesSize = getValue().getItemPropertyIds().size();
269 if (fromIndex == valuesSize) {
270 return;
271 }
272 while (fromIndex < valuesSize) {
273 int toIndex = fromIndex;
274 fromIndex +=1;
275 getValue().addItemProperty(toIndex, getValue().getItemProperty(fromIndex));
276 getValue().removeItemProperty(fromIndex);
277 }
278 }
279
280
281
282
283 private void switchItemProperties(Object firstPropertyId, Object secondPropertyId) {
284 Property propertyFirst = getValue().getItemProperty(firstPropertyId);
285 Property propertySecond = getValue().getItemProperty(secondPropertyId);
286
287 try {
288 PropertysetItem storedValues = (PropertysetItem) getValue().clone();
289 if (storedValues != null) {
290 for (Object propertyId : storedValues.getItemPropertyIds()) {
291 getValue().removeItemProperty(propertyId);
292 if (propertyId == firstPropertyId) {
293 getValue().addItemProperty(firstPropertyId, propertySecond);
294 } else if (propertyId == secondPropertyId) {
295 getValue().addItemProperty(secondPropertyId, propertyFirst);
296 } else {
297 getValue().addItemProperty(propertyId, storedValues.getItemProperty(propertyId));
298 }
299 }
300 getPropertyDataSource().setValue(getValue());
301 }
302 } catch (CloneNotSupportedException e) {
303 log.error("Unable to switch properties on MultiField. Unable to clone PropertysetItem.", e);
304 }
305
306 }
307
308 private void onDelete(Component layout, Property<?> propertyReference) {
309 root.removeComponent(layout);
310 Transformer<?> transformer = ((TransformedProperty<?>) getPropertyDataSource()).getTransformer();
311
312
313 Object propertyId = findPropertyId(getValue(), propertyReference);
314
315 if (transformer instanceof MultiTransformer) {
316 ((MultiTransformer) transformer).removeProperty(propertyId);
317 } else {
318 if (propertyId.getClass().isAssignableFrom(Integer.class)) {
319 removeValueProperty((Integer) propertyId);
320 } else {
321 log.error("Property id {} is not an integer and as such property can't be removed", propertyId);
322 }
323 getPropertyDataSource().setValue(getValue());
324 }
325 }
326
327
328
329
330
331 private void onMove(Component layout, Property<?> propertyReference, boolean moveUp) {
332 int currentPosition = root.getComponentIndex(layout);
333 int switchPosition = currentPosition + (moveUp ? -1 : 1);
334
335 Field[] fields = Iterators.toArray(Iterators.filter(Iterators.transform(root.iterator(), new Function<Component, Field>() {
336 @Override
337 public Field apply(Component input) {
338 if (input instanceof HasComponents) {
339 Optional<Component> field = Iterators.tryFind(((HasComponents) input).iterator(), Predicates.instanceOf(Field.class));
340 if (field.isPresent()) {
341 return (Field) field.get();
342 }
343 }
344 return null;
345 }
346 }), Predicates.notNull()), Field.class);
347
348 if (moveUp && currentPosition != 0 || (!moveUp && currentPosition != fields.length - 1)) {
349 Field switchField = fields[switchPosition];
350 Object currentPropertyId = MultiField.this.findPropertyId(getValue(), propertyReference);
351 Object switchPropertyId = MultiField.this.findPropertyId(getValue(), switchField.getPropertyDataSource());
352
353 root.replaceComponent(root.getComponent(currentPosition), root.getComponent(switchPosition));
354 switchItemProperties(currentPropertyId, switchPropertyId);
355 }
356 }
357
358 public boolean isOrderable() {
359 return isOrderable;
360 }
361
362 public void setOrderable(boolean orderable) {
363 isOrderable = orderable;
364 }
365 }