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.dialog.formdialog;
35
36 import static com.vaadin.server.Sizeable.Unit.PERCENTAGE;
37 import static java.util.stream.Collectors.toList;
38 import static java.util.stream.StreamSupport.stream;
39
40 import info.magnolia.context.Context;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.ui.dialog.ResurfaceDialogViewImpl;
43 import info.magnolia.ui.vaadin.extension.FocusFieldCaption;
44 import info.magnolia.ui.vaadin.form.FormSection;
45 import info.magnolia.ui.vaadin.form.FormViewReduced;
46 import info.magnolia.ui.vaadin.form.field.FieldLayout;
47
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Iterator;
51 import java.util.List;
52 import java.util.Locale;
53 import java.util.Optional;
54 import java.util.function.Supplier;
55 import java.util.stream.Stream;
56
57 import javax.inject.Inject;
58
59 import com.vaadin.server.ErrorMessage;
60 import com.vaadin.server.Sizeable;
61 import com.vaadin.shared.ui.ContentMode;
62 import com.vaadin.ui.AbstractComponent;
63 import com.vaadin.ui.ComboBox;
64 import com.vaadin.ui.Component;
65 import com.vaadin.ui.ComponentContainer;
66 import com.vaadin.ui.FormLayout;
67 import com.vaadin.ui.TabSheet;
68 import com.vaadin.ui.themes.ValoTheme;
69 import com.vaadin.v7.data.Item;
70 import com.vaadin.v7.data.Validatable;
71 import com.vaadin.v7.ui.AbstractField;
72 import com.vaadin.v7.ui.Field;
73
74
75
76
77 public class ResurfaceFormViewImpl extends ResurfaceDialogViewImpl implements FormView {
78
79 private final SimpleTranslator i18n;
80 private final Supplier<Locale> userLanguage;
81
82 private Item itemDatasource;
83
84 private String title;
85 private TabSheet tabSheet = new TabSheet();
86 private ComboBox<Locale> languageSelector;
87 private FormViewReduced.Listener listener;
88 private boolean invalidFieldFocused;
89
90 @Inject
91 public ResurfaceFormViewImpl(SimpleTranslator i18n, Context context) {
92 this.i18n = i18n;
93 this.userLanguage = context::getLocale;
94
95 tabSheet.setSizeFull();
96 tabSheet.addStyleName("content");
97 tabSheet.addStyleName(ValoTheme.TABSHEET_FRAMED);
98
99 createLocaleSelector();
100 this.setContent(() -> tabSheet);
101 }
102
103 @Override
104 public void setCurrentLocale(Locale locale) {
105 this.languageSelector.setValue(locale);
106 }
107
108 @Override
109 public void setAvailableLocales(List<Locale> locales) {
110 if (locales != null && !locales.isEmpty()) {
111 languageSelector.clear();
112 languageSelector.setItems(locales);
113 getActionAreaView().setToolbarComponent(languageSelector);
114 }
115 }
116
117 @Override
118 public void setItemDataSource(Item newDataSource) {
119 this.itemDatasource = newDataSource;
120 }
121
122 @Override
123 public Item getItemDataSource() {
124 return this.itemDatasource;
125 }
126
127 @Override
128 public void setCaption(String caption) {
129 this.title = caption;
130 }
131
132 @Override
133 public String getTitle() {
134 return this.title;
135 }
136
137 @Override
138 public void addField(Field<?> field) {
139
140 }
141
142 @Override
143 public void addFormSection(String tabName, FormSection inputFields) {
144 final Component formLayout = new FormLayout(new ArrayList<>(inputFields.getComponents())
145 .stream()
146 .map(component -> createFieldLayout(component, inputFields.getComponentHelpDescription(component)))
147 .toArray(Component[]::new)
148 );
149 final TabSheet.Tab tab = this.tabSheet.addTab(formLayout, tabName);
150 tab.setId(inputFields.getName());
151 formLayout.setWidth(95, PERCENTAGE);
152 FocusFieldCaption.focusCaptionOf((FormLayout) formLayout);
153 }
154
155 private Component createFieldLayout(Component field, String componentHelpDescription) {
156 FieldLayout fieldLayout = FieldLayout.of(field, componentHelpDescription);
157 fieldLayout.setCaption(field.getCaption());
158 if (field instanceof AbstractField) {
159 fieldLayout.setRequiredIndicatorVisible(((AbstractField) field).isRequired());
160 }
161 return fieldLayout;
162 }
163
164 @Override
165 public void showValidation(boolean isVisible) {
166 invalidFieldFocused = false;
167 getComponents().forEach(field -> {
168 FieldLayout fieldLayout = null;
169 if (field instanceof FieldLayout) {
170 fieldLayout = (FieldLayout) field;
171 field = fieldLayout.getField();
172 }
173 if (field instanceof AbstractField) {
174 AbstractField abstractField = (AbstractField) field;
175 abstractField.setValidationVisible(isVisible);
176 if (fieldLayout != null) {
177 fieldLayout.getValidationStatusHandler().accept(
178 Optional.ofNullable(abstractField.getErrorMessage())
179 .map(ErrorMessage::getFormattedHtmlMessage)
180 .orElse("")
181 );
182 if (!invalidFieldFocused && !abstractField.isValid()) {
183 fieldLayout.focus();
184 invalidFieldFocused = true;
185 }
186 }
187 }
188 });
189 }
190
191 @Override
192 public void setShowAllEnabled(boolean enabled) {
193
194 }
195
196 @Override
197 public void setDescriptionVisibility(boolean isVisible) {
198
199 }
200
201 @Override
202 public boolean isValid() {
203 return getFields().stream().allMatch(Validatable::isValid);
204 }
205
206 @Override
207 public List<FormSection> getFormSections() {
208 return stream(tabSheet.spliterator(), false)
209 .map(component -> new FormSectionAdapter((ComponentContainer) component, tabSheet.getTab(component).getId()))
210 .collect(toList());
211 }
212
213 @Override
214 @Deprecated
215 public Collection<Field<?>> getFields() {
216 return getComponents()
217 .map(component -> component instanceof FieldLayout ? ((FieldLayout) component).getField() : component)
218 .filter(component -> component instanceof Field)
219 .map(component -> (Field<?>) component)
220 .collect(toList());
221 }
222
223 private Stream<Component> getComponents() {
224 return getFormSections().stream()
225 .flatMap(sections -> sections.getComponents().stream());
226 }
227
228 @Override
229 public void setListener(FormViewReduced.Listener listener) {
230 this.listener = listener;
231 }
232
233 @Override
234 public AbstractComponent asVaadinComponent() {
235
236
237
238
239
240 if (tabSheet.getComponentCount() == 1) {
241 tabSheet.addStyleName("single-tab");
242 } else {
243 tabSheet.removeStyleName("single-tab");
244 }
245
246 return tabSheet;
247 }
248
249 private void createLocaleSelector() {
250 languageSelector = new ComboBox<>();
251
252 languageSelector.setWidth(150, Sizeable.Unit.PIXELS);
253 languageSelector.setDescription(i18n.translate("languageSelector.description"), ContentMode.HTML);
254 languageSelector.setItemCaptionGenerator(locale -> {
255
256 Locale preferredLocale = userLanguage.get();
257 String label = locale.getDisplayLanguage(preferredLocale);
258 if (!locale.getDisplayCountry(preferredLocale).isEmpty()) {
259 label += " (" + locale.getDisplayCountry(preferredLocale) + ")";
260 }
261 return label;
262 });
263 languageSelector.setEmptySelectionAllowed(false);
264 languageSelector.setTextInputAllowed(false);
265 languageSelector.addValueChangeListener(event -> {
266 if (this.listener != null) {
267 this.listener.localeChanged(event.getValue());
268 }
269 });
270 }
271
272 void updateFormView(List<FormSection> sections) {
273 tabSheet.removeAllComponents();
274 sections.forEach(section -> addFormSection(section.getName(), section));
275 }
276
277 private final class FormSectionAdapter extends FormSection {
278
279 private final ComponentContainer layout;
280
281 FormSectionAdapter(ComponentContainer layout, String name) {
282 this.layout = layout;
283 setName(name);
284 }
285
286 @Override
287 public void setComponentHelpDescription(Component c, String description) {
288 getState().helpDescriptions.put(c, description);
289 }
290
291 @Override
292 public String getComponentHelpDescription(Component c) {
293 return getState().helpDescriptions.get(c);
294 }
295
296 @Override
297 public void addComponent(Component c) {
298 accessTabLayout().addComponent(c);
299 }
300
301 ComponentContainer accessTabLayout() {
302 return layout;
303 }
304
305 @Override
306 public void removeAllComponents() {
307 accessTabLayout().removeAllComponents();
308 }
309
310 @Override
311 public void removeComponent(Component c) {
312 accessTabLayout().removeComponent(c);
313 }
314
315 @Override
316 public Iterator<Component> iterator() {
317 return accessTabLayout().iterator();
318 }
319
320 @Override
321 public int getComponentCount() {
322 return accessTabLayout().getComponentCount();
323 }
324
325 @Override
326 public List<Component> getComponents() {
327 return stream(accessTabLayout().spliterator(), false).collect(toList());
328 }
329 }
330 }