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.contentapp.detail;
35
36 import static java.util.Comparator.comparing;
37 import static java.util.stream.Collectors.toList;
38
39 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
40 import info.magnolia.ui.api.app.SubAppContext;
41 import info.magnolia.ui.api.app.SubAppDescriptor;
42 import info.magnolia.ui.api.location.DefaultLocation;
43 import info.magnolia.ui.api.location.Location;
44 import info.magnolia.ui.contentapp.browser.ActionExecutionService;
45 import info.magnolia.ui.framework.ContextProperty;
46 import info.magnolia.ui.framework.UiFrameworkView;
47 import info.magnolia.ui.framework.ViewContext;
48 import info.magnolia.ui.framework.app.BaseSubApp;
49 import info.magnolia.ui.framework.databinding.ItemProviderStrategy;
50 import info.magnolia.ui.framework.databinding.view.EditorView;
51 import info.magnolia.ui.framework.databinding.view.FormView;
52
53 import java.util.Collections;
54 import java.util.List;
55 import java.util.Locale;
56
57 import javax.inject.Inject;
58
59 import org.apache.commons.lang3.StringUtils;
60
61 import com.vaadin.ui.Button;
62 import com.vaadin.ui.ComboBox;
63 import com.vaadin.ui.Component;
64 import com.vaadin.ui.CssLayout;
65
66
67
68
69
70
71 public class ContentDetailSubApp<T> extends BaseSubApp<ContentDetailSubApp.DetailSubAppView> {
72
73 private final DetailDescriptor<T, ?> subAppDescriptor;
74 private final I18NAuthoringSupport i18NAuthoringSupport;
75 private final ActionExecutionService actionExecutionService;
76 private LocationContext locationContext;
77 private ItemProviderStrategy<T> itemProviderStrategy;
78
79 @Inject
80 protected ContentDetailSubApp(SubAppContext subAppContext, I18NAuthoringSupport i18NAuthoringSupport, ActionExecutionService actionExecutionService) {
81 super(subAppContext, new DetailSubAppView());
82 this.actionExecutionService = actionExecutionService;
83 this.subAppDescriptor = (DetailDescriptor<T, ?>) getSubAppContext().getSubAppDescriptor();
84 this.i18NAuthoringSupport = i18NAuthoringSupport;
85 }
86
87 @Override
88 public DetailSubAppView start(Location location) {
89 super.start(location);
90
91 final DetailSubAppView view = getView();
92
93 view.bindDatasourceDefinition(subAppDescriptor.getDatasource());
94
95 final LocaleContext localeContext = view.bindContext(LocaleContext.class);
96 final Locale currentLocale = getSubAppContext().getAuthoringLocale() != null ?
97 getSubAppContext().getAuthoringLocale() :
98 i18NAuthoringSupport.getDefaultLocale();
99 localeContext.current().set(currentLocale);
100
101 this.locationContext = view.bindContext(LocationContext.class);
102 this.locationContext.location().set(DetailLocation.wrap(location));
103
104 this.itemProviderStrategy = view.create(subAppDescriptor.getItemProvider(), subAppDescriptor.getDatasource());
105
106 view.bindInstance(SubAppDescriptor.class, this.subAppDescriptor);
107 view.bindInstance(ItemProviderStrategy.class, itemProviderStrategy);
108
109 final FormView<T> form = (FormView<T>) view.getViewProvider().create(subAppDescriptor.getForm(), subAppDescriptor.getDatasource());
110
111 view.bindInstance(EditorView.class, form);
112
113
114 final CssLayout content = new CssLayout();
115 content.setSizeFull();
116 content.addComponent(form.asVaadinComponent());
117
118 view.setForm(content);
119
120 locationContext.location().observeNullable(l -> itemProviderStrategy.read().ifPresent(form::populate));
121 localeContext.current().observeNullable(locale -> {
122 content.removeAllComponents();
123 content.addComponent(form.getLayout(locale));
124 });
125
126
127
128 return view;
129 }
130
131 private List<Component> createPrimaryActions() {
132 return subAppDescriptor.getActions().entrySet().stream()
133 .map((action) -> {
134 Button button = new Button(action.getKey(), e -> actionExecutionService.executeAction(action.getKey(), action.getValue()));
135 button.addStyleName(action.getKey());
136 return button;
137 })
138
139 .sorted(comparing(button -> button.getStyleName().contains("commit")))
140 .collect(toList());
141 }
142
143 private Component createLocateSelector(LocaleContext localeContext) {
144
145 final ComboBox<Locale> locales = new ComboBox<>();
146
147 List<Locale> availableLocales = i18NAuthoringSupport.getAvailableLocales();
148 if (availableLocales.isEmpty()) {
149 availableLocales = Collections.singletonList(i18NAuthoringSupport.getDefaultLocale());
150 }
151
152 locales.setItems(availableLocales);
153 locales.setItemCaptionGenerator(Locale::getDisplayLanguage);
154 locales.setEmptySelectionAllowed(false);
155 locales.setSelectedItem(localeContext.current().value().orElse(i18NAuthoringSupport.getDefaultLocale()));
156 locales.addValueChangeListener(locale -> localeContext.current().set(locale.getValue()));
157
158 return locales;
159 }
160
161 @Override
162 public void locationChanged(Location location) {
163 super.locationChanged(location);
164 this.locationContext.location().set(DetailLocation.wrap(location));
165 }
166
167 @Override
168 public void stop() {
169 getView().destroy();
170 }
171
172
173
174
175 public interface LocationContext extends ViewContext {
176
177 ContextProperty<DetailLocation> location();
178 }
179
180
181
182
183 public interface LocaleContext extends ViewContext {
184
185 ContextProperty<Locale> current();
186 }
187
188
189
190
191 protected static class DetailSubAppView implements UiFrameworkView {
192
193 private Component form;
194
195 @Override
196 public Component asVaadinComponent() {
197 return form;
198 }
199
200 public void setForm(Component form) {
201 this.form = form;
202 }
203 }
204
205
206
207
208
209
210
211
212
213
214
215
216 public static class DetailLocation extends DefaultLocation {
217
218 private String viewType;
219 private String nodePath;
220 private String version;
221
222 private final static int NODE_PATH_PARAM_POSITION = 0;
223 private final static int VIEW_TYPE_PARAM_POSITION = 1;
224 private final static int VERSION_PARAM_POSITION = 2;
225
226 public DetailLocation(String appName, String subAppId, String parameter) {
227 super(LOCATION_TYPE_APP, appName, subAppId, parameter);
228
229 setNodePath(extractNodePath(parameter));
230 setViewType(extractViewType(parameter));
231 setVersion(extractVersion(parameter));
232 }
233
234 public DetailLocation(String appName, String subAppId, String viewType, String nodePath, String version) {
235 super(LOCATION_TYPE_APP, appName, subAppId);
236
237 setNodePath(nodePath);
238 setViewType(viewType);
239 setVersion(version);
240 updateParameter();
241 }
242
243 public String getNodePath() {
244 return unescapeSpecialCharacters(nodePath);
245 }
246
247
248
249
250 private void setNodePath(String nodePath) {
251 this.nodePath = (nodePath == null || nodePath.isEmpty()) ? "/" : escapeSpecialCharacters(nodePath);
252 }
253
254 public String getViewType() {
255 return viewType;
256 }
257
258 public void setViewType(String viewType) {
259 this.viewType = viewType;
260 }
261
262 public String getVersion() {
263 return unescapeSpecialCharacters(version);
264 }
265
266 public void setVersion(String version) {
267 this.version = escapeSpecialCharacters(version);
268 }
269
270 public boolean hasVersion() {
271 return StringUtils.isNotBlank(version);
272 }
273
274
275
276
277
278
279
280 private String extractNodePath(String parameter) {
281 return getParameter(parameter, NODE_PATH_PARAM_POSITION);
282 }
283
284
285
286
287
288
289
290 private String extractViewType(String parameter) {
291 String action = getParameter(parameter, VIEW_TYPE_PARAM_POSITION);
292 return action;
293 }
294
295
296
297
298
299
300
301 private String extractVersion(String parameter) {
302 return getParameter(parameter, VERSION_PARAM_POSITION);
303 }
304
305 protected String getParameter(String parameter, int position) {
306 String arguments[] = StringUtils.split(parameter, ':');
307 if (position <= arguments.length - 1) {
308 return arguments[position];
309 }
310 return "";
311 }
312
313 protected void updateParameter() {
314 StringBuilder sb = new StringBuilder();
315 sb.append(nodePath);
316 sb.append(":");
317 sb.append(viewType);
318 if (StringUtils.isNotBlank(version)) {
319 sb.append(":");
320 sb.append(version);
321 }
322 super.setParameter(sb.toString());
323 }
324
325 public static DetailLocation wrap(Location location) {
326 return new DetailLocation(location.getAppName(), location.getSubAppId(), location.getParameter());
327 }
328
329 public void updateNodePath(String newNodePath) {
330 setNodePath(newNodePath);
331 updateParameter();
332 }
333
334 public void updateViewtype(String newViewType) {
335 setViewType(newViewType);
336 updateParameter();
337 }
338
339 public void updateVersion(String newVersion) {
340 setVersion(newVersion);
341 updateParameter();
342 }
343 }
344 }