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.objectfactory.ComponentProvider;
38 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
39 import info.magnolia.ui.form.field.definition.ConfiguredFieldDefinition;
40 import info.magnolia.ui.form.field.definition.FieldDefinition;
41 import info.magnolia.ui.form.field.factory.FieldFactory;
42 import info.magnolia.ui.form.field.factory.FieldFactoryFactory;
43 import info.magnolia.ui.vaadin.integration.ItemAdapter;
44 import info.magnolia.ui.vaadin.integration.NullItem;
45
46 import java.util.ArrayList;
47 import java.util.Iterator;
48 import java.util.List;
49 import java.util.Locale;
50
51 import org.apache.commons.lang3.StringUtils;
52 import org.slf4j.Logger;
53 import org.slf4j.LoggerFactory;
54
55 import com.vaadin.data.Item;
56 import com.vaadin.data.Property;
57 import com.vaadin.data.util.PropertysetItem;
58 import com.vaadin.server.ErrorMessage;
59 import com.vaadin.ui.AbstractComponent;
60 import com.vaadin.ui.AbstractField;
61 import com.vaadin.ui.AbstractOrderedLayout;
62 import com.vaadin.ui.Component;
63 import com.vaadin.ui.CustomField;
64 import com.vaadin.ui.Field;
65 import com.vaadin.ui.HasComponents;
66
67
68
69
70
71
72
73
74
75
76
77 public abstract class AbstractCustomMultiField<D extends FieldDefinition, T> extends CustomField<T> {
78
79 private static final Logger log = LoggerFactory.getLogger(AbstractCustomMultiField.class);
80
81 protected final FieldFactoryFactory fieldFactoryFactory;
82
83
84 @Deprecated
85 protected final I18nContentSupport i18nContentSupport = null;
86 private final I18NAuthoringSupport i18nAuthoringSupport;
87
88 protected final ComponentProvider componentProvider;
89 protected final D definition;
90 protected final Item relatedFieldItem;
91 protected AbstractOrderedLayout root;
92
93 protected AbstractCustomMultiField(D definition, FieldFactoryFactory fieldFactoryFactory, ComponentProvider componentProvider, Item relatedFieldItem, I18NAuthoringSupport i18nAuthoringSupport) {
94 this.definition = definition;
95 this.fieldFactoryFactory = fieldFactoryFactory;
96 this.componentProvider = componentProvider;
97 this.relatedFieldItem = relatedFieldItem;
98 this.i18nAuthoringSupport = i18nAuthoringSupport;
99 }
100
101
102
103
104 @Deprecated
105 protected AbstractCustomMultiField(D definition, FieldFactoryFactory fieldFactoryFactory, I18nContentSupport i18nContentSupport, ComponentProvider componentProvider, Item relatedFieldItem) {
106 this(definition, fieldFactoryFactory, componentProvider, relatedFieldItem, componentProvider.getComponent(I18NAuthoringSupport.class));
107 }
108
109
110
111
112
113
114
115
116 protected abstract void initFields(T fieldValues);
117
118
119
120
121
122 @Override
123 public void setLocale(Locale locale) {
124 if (root != null) {
125 initFields();
126 }
127 super.setLocale(locale);
128 }
129
130 @SuppressWarnings("unchecked")
131 protected void initFields() {
132 T fieldValues = (T) getPropertyDataSource().getValue();
133 initFields(fieldValues);
134
135 if (relatedFieldItem instanceof ItemAdapter && ((ItemAdapter) relatedFieldItem).isNew()) {
136 getPropertyDataSource().setValue(getValue());
137 }
138 }
139
140
141
142
143 protected int findPropertyId(Item item, Property<?> property) {
144 Iterator<?> it = item.getItemPropertyIds().iterator();
145 while (it.hasNext()) {
146 Object pos = it.next();
147 if (pos.getClass().isAssignableFrom(Integer.class) && property == item.getItemProperty(pos)) {
148 return (Integer) pos;
149 } else {
150 log.debug("Property id {} is not an integer and as such property can't be located", pos);
151 }
152 }
153 return -1;
154 }
155
156
157
158
159 protected Field<?> createLocalField(FieldDefinition fieldDefinition, Property<?> property, boolean setCaptionToNull) {
160
161
162 FieldFactory fieldfactory = fieldFactoryFactory.createFieldFactory(fieldDefinition, holdsItem(property) ? property.getValue() : new NullItem());
163 fieldfactory.setComponentProvider(componentProvider);
164
165 if (fieldDefinition instanceof ConfiguredFieldDefinition) {
166 ((ConfiguredFieldDefinition) fieldDefinition).setI18nBasename(definition.getI18nBasename());
167 }
168 Field<?> field = fieldfactory.createField();
169
170
171
172 if (!holdsItem(property)) {
173 if (property != null && property.getValue() != null) {
174 field.setPropertyDataSource(property);
175 }
176 field.addValueChangeListener(selectionListener);
177 }
178
179 if (field instanceof AbstractComponent) {
180 ((AbstractComponent) field).setImmediate(true);
181 }
182
183 if (setCaptionToNull) {
184 field.setCaption(null);
185 } else if (StringUtils.isNotBlank(fieldDefinition.getLabel())) {
186 field.setCaption(fieldDefinition.getLabel());
187 }
188
189 field.setWidth(100, Unit.PERCENTAGE);
190
191
192 if (field instanceof AbstractCustomMultiField) {
193 ((AbstractCustomMultiField) field).setLocale(getLocale());
194 }
195
196 if (fieldDefinition.isI18n()) {
197 field.addAttachListener(new AttachListener() {
198 @Override
199 public void attach(AttachEvent event) {
200 i18nAuthoringSupport.i18nize(((Component) event.getSource()).getParent(), getLocale());
201 }
202 });
203 }
204
205 return field;
206 }
207
208 boolean holdsItem(Property<?> property) {
209 return property != null && property.getValue() instanceof Item && !(property.getValue() instanceof PropertysetItem);
210 }
211
212
213
214
215 protected Property.ValueChangeListener selectionListener = new ValueChangeListener() {
216 @SuppressWarnings("unchecked")
217 @Override
218 public void valueChange(com.vaadin.data.Property.ValueChangeEvent event) {
219 fireValueChange(false);
220
221
222 getPropertyDataSource().setValue(getValue());
223 }
224 };
225
226
227
228
229
230
231
232 @SuppressWarnings("unchecked")
233 protected List<AbstractField<T>> getFields(HasComponents root, boolean onlyValid) {
234 Iterator<Component> it = root.iterator();
235 List<AbstractField<T>> fields = new ArrayList<AbstractField<T>>();
236 while (it.hasNext()) {
237 Component c = it.next();
238 if (c instanceof AbstractField) {
239 if (!onlyValid || (onlyValid && ((AbstractField<T>) c).isValid())) {
240 fields.add((AbstractField<T>) c);
241 }
242 } else if (c instanceof HasComponents) {
243 fields.addAll(getFields((HasComponents) c, onlyValid));
244 }
245 }
246 return fields;
247 }
248
249
250
251
252 @Override
253 public boolean isValid() {
254 boolean isValid = true;
255 List<AbstractField<T>> fields = getFields(this, false);
256 for (AbstractField<T> field : fields) {
257 isValid = field.isValid();
258 if (!isValid) {
259 return isValid;
260 }
261 }
262 return isValid;
263 }
264
265
266
267
268 @Override
269 public ErrorMessage getErrorMessage() {
270 ErrorMessage errorMessage = null;
271 List<AbstractField<T>> fields = getFields(this, false);
272 for (AbstractField<T> field : fields) {
273 errorMessage = field.getErrorMessage();
274 if (errorMessage != null) {
275 return errorMessage;
276 }
277 }
278 return errorMessage;
279 }
280
281 @Override
282 public boolean isEmpty() {
283 boolean isEmpty = false;
284 List<AbstractField<T>> fields = getFields(this, false);
285 for (AbstractField<T> field : fields) {
286 isEmpty = field.getValue() == null;
287 if (isEmpty) {
288 return isEmpty;
289 }
290 }
291 return isEmpty;
292 }
293
294 }