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