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