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.stream.Collectors.*;
37
38 import info.magnolia.ui.CloseHandler;
39 import info.magnolia.ui.api.app.SubAppContext;
40 import info.magnolia.ui.api.i18n.I18NAuthoringSupport;
41 import info.magnolia.ui.api.location.DefaultLocation;
42 import info.magnolia.ui.api.location.Location;
43 import info.magnolia.ui.contentapp.ItemDescriber;
44 import info.magnolia.ui.ValueContext;
45 import info.magnolia.ui.dialog.ActionExecution;
46 import info.magnolia.ui.dialog.EditorActionBar;
47 import info.magnolia.ui.field.LocaleSelector;
48 import info.magnolia.ui.editor.FormDefinition;
49 import info.magnolia.ui.editor.LocaleContext;
50 import info.magnolia.ui.framework.ContextProperty;
51 import info.magnolia.ui.UIComponent;
52 import info.magnolia.ui.framework.UiComponentContext;
53 import info.magnolia.ui.editor.ItemProviderStrategy;
54 import info.magnolia.ui.editor.EditorView;
55 import info.magnolia.ui.editor.FormView;
56
57 import java.util.List;
58 import java.util.Map;
59 import java.util.Optional;
60 import java.util.stream.Collectors;
61
62 import javax.inject.Inject;
63
64 import org.apache.commons.lang3.StringUtils;
65
66 import com.vaadin.event.ShortcutListener;
67 import com.vaadin.ui.Component;
68 import com.vaadin.ui.CssLayout;
69 import com.vaadin.ui.Panel;
70
71 import lombok.AccessLevel;
72 import lombok.Getter;
73
74
75
76
77
78
79 public class ContentDetailSubApp<T> extends AbstractDetailSubApp<ContentDetailSubApp.SubAppView> {
80
81 private final DetailDescriptor<T, ?> subAppDescriptor;
82 private final I18NAuthoringSupport<T> i18NAuthoringSupport;
83 private final LocaleContext localeContext;
84 private final ValueContext<T> valueContext;
85 private final ItemDescriber<T> itemDescriber;
86
87 @Inject
88 protected ContentDetailSubApp(
89 SubAppContext subAppContext,
90 I18NAuthoringSupport<T> i18NAuthoringSupport,
91 DetailDescriptor<T, ?> descriptor,
92 LocaleContext localeContext,
93 ValueContext<T> valueContext,
94 ItemDescriber<T> itemDescriber) {
95 super(subAppContext, new SubAppView());
96 this.valueContext = valueContext;
97 this.localeContext = localeContext;
98 this.subAppDescriptor = descriptor;
99 this.i18NAuthoringSupport = i18NAuthoringSupport;
100 this.itemDescriber = itemDescriber;
101 }
102
103 @Override
104 public SubAppView start(Location location) {
105 super.start(location);
106
107 final SubAppView view = getView();
108
109 localeContext.defaultLocale().set(getSubAppContext().getAuthoringLocale());
110
111 bindInstance(UIComponent.class, view);
112 bindInstance(CloseHandler.class, () -> getSubAppContext().close());
113
114 ItemProviderStrategy<T, DetailLocation> itemProviderStrategy = create(subAppDescriptor.getItemProvider());
115 Optional<T> item = itemProviderStrategy.read(DetailLocation.wrap(location));
116
117 item.ifPresent(it -> localeContext.populateFromI18NAuthoringSupport(it, i18NAuthoringSupport));
118
119 FormDefinition<T> formDefinition = subAppDescriptor.getForm();
120 FormView<T> form = (FormView<T>) create(formDefinition);
121
122 EditorActionBar<T> editorActionBar = view.create(EditorActionBar.class);
123 List<ActionExecution<T>> actionExecutions =
124 ActionExecution.<T>fromDefinitions(subAppDescriptor.getActions().values(), getComponentProvider())
125 .collect(toList());
126
127 editorActionBar
128 .withActions(actionExecutions)
129 .withLayoutDefinition(subAppDescriptor.getFooterLayout());
130
131 if (formDefinition.hasI18NProperties()) {
132 editorActionBar = editorActionBar.withLabeledControl("localeSelector", create(LocaleSelector.class));
133 }
134
135 Map<Integer, Runnable> shortcuts = actionExecutions.stream()
136 .filter(execution -> execution.getDefinition().getShortcut() > 0)
137 .collect(toMap(execution -> execution.getDefinition().getShortcut(), actionExecution -> (Runnable) actionExecution::execute));
138
139 view.bindInstance(EditorView.class, form);
140 view.setShortcuts(shortcuts);
141
142 view.getLayout().setTitle(subAppDescriptor.getLabel());
143 view.getLayout().setMargin(false);
144 view.getLayout().setForm(form.asVaadinComponent());
145 view.getLayout().setFooter(editorActionBar.layout());
146 view.getLayout().construct();
147
148 item.ifPresent(it -> {
149 valueContext.set(it);
150 form.populate(it);
151 });
152
153 return view;
154 }
155
156 @Override
157 public String getCaption() {
158 return itemDescriber.apply(valueContext.get().collect(Collectors.toList()));
159 }
160
161 @Override
162 public void locationChanged(Location location) {
163
164
165 }
166
167
168
169
170 public interface LocationContext extends UiComponentContext {
171 ContextProperty<DetailLocation> location();
172 }
173
174
175
176
177
178
179
180
181
182
183
184
185 public static class DetailLocation extends DefaultLocation {
186
187 private String viewType;
188 private String nodePath;
189 private String version;
190
191 private final static int NODE_PATH_PARAM_POSITION = 0;
192 private final static int VIEW_TYPE_PARAM_POSITION = 1;
193 private final static int VERSION_PARAM_POSITION = 2;
194
195 public DetailLocation(String appName, String subAppId, String parameter) {
196 super(LOCATION_TYPE_APP, appName, subAppId, parameter);
197
198 setNodePath(extractNodePath(parameter));
199 setViewType(extractViewType(parameter));
200 setVersion(extractVersion(parameter));
201 }
202
203 public DetailLocation(String appName, String subAppId, String viewType, String nodePath, String version) {
204 super(LOCATION_TYPE_APP, appName, subAppId);
205
206 setNodePath(nodePath);
207 setViewType(viewType);
208 setVersion(version);
209 updateParameter();
210 }
211
212 public String getNodePath() {
213 return unescapeSpecialCharacters(nodePath);
214 }
215
216
217
218
219 private void setNodePath(String nodePath) {
220 this.nodePath = (nodePath == null || nodePath.isEmpty()) ? "/" : escapeSpecialCharacters(nodePath);
221 }
222
223 public String getViewType() {
224 return viewType;
225 }
226
227 public void setViewType(String viewType) {
228 this.viewType = viewType;
229 }
230
231 public String getVersion() {
232 return unescapeSpecialCharacters(version);
233 }
234
235 public void setVersion(String version) {
236 this.version = escapeSpecialCharacters(version);
237 }
238
239 public boolean hasVersion() {
240 return StringUtils.isNotBlank(version);
241 }
242
243
244
245
246
247
248
249 private String extractNodePath(String parameter) {
250 return getParameter(parameter, NODE_PATH_PARAM_POSITION);
251 }
252
253
254
255
256
257
258
259 private String extractViewType(String parameter) {
260 String action = getParameter(parameter, VIEW_TYPE_PARAM_POSITION);
261 return action;
262 }
263
264
265
266
267
268
269
270 private String extractVersion(String parameter) {
271 return getParameter(parameter, VERSION_PARAM_POSITION);
272 }
273
274 protected String getParameter(String parameter, int position) {
275 String arguments[] = StringUtils.split(parameter, ':');
276 if (position <= arguments.length - 1) {
277 return arguments[position];
278 }
279 return "";
280 }
281
282 protected void updateParameter() {
283 StringBuilder sb = new StringBuilder();
284 sb.append(nodePath);
285 sb.append(":");
286 sb.append(viewType);
287 if (StringUtils.isNotBlank(version)) {
288 sb.append(":");
289 sb.append(version);
290 }
291 super.setParameter(sb.toString());
292 }
293
294 public static DetailLocation wrap(Location location) {
295 return new DetailLocation(location.getAppName(), location.getSubAppId(), location.getParameter());
296 }
297
298 public void updateNodePath(String newNodePath) {
299 setNodePath(newNodePath);
300 updateParameter();
301 }
302
303 public void updateViewtype(String newViewType) {
304 setViewType(newViewType);
305 updateParameter();
306 }
307
308 public void updateVersion(String newVersion) {
309 setVersion(newVersion);
310 updateParameter();
311 }
312 }
313
314 @Getter(AccessLevel.PACKAGE)
315 public static class SubAppView extends Panel implements UIComponent {
316
317 private DetailViewLayoutDetailViewLayout.html#DetailViewLayout">DetailViewLayout layout = new DetailViewLayout();
318
319 public SubAppView() {
320 setSizeFull();
321 addStyleName("detail");
322 CssLayout contentViewWrapper = new CssLayout();
323 contentViewWrapper.addStyleName("detailview");
324 contentViewWrapper.setSizeFull();
325 contentViewWrapper.addComponent(layout);
326 layout.setSizeFull();
327
328 setContent(contentViewWrapper);
329 }
330
331 @Override
332 public Component asVaadinComponent() {
333 return this;
334 }
335
336 public void setShortcuts(Map<Integer, Runnable> shortcuts) {
337 shortcuts.forEach((keyCode, execution) -> {
338 addShortcutListener(new ShortcutListener("", keyCode, new int[]{}) {
339 @Override
340 public void handleAction(Object sender, Object target) {
341 execution.run();
342 }
343 });
344 });
345 }
346 }
347 }