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