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