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