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.movedialog;
35
36 import info.magnolia.context.MgnlContext;
37 import info.magnolia.event.EventBus;
38 import info.magnolia.event.ResettableEventBus;
39 import info.magnolia.event.SimpleEventBus;
40 import info.magnolia.i18nsystem.I18nizer;
41 import info.magnolia.i18nsystem.SimpleTranslator;
42 import info.magnolia.objectfactory.ComponentProvider;
43 import info.magnolia.ui.api.action.ActionDefinition;
44 import info.magnolia.ui.api.action.ConfiguredActionDefinition;
45 import info.magnolia.ui.api.app.AppContext;
46 import info.magnolia.ui.api.overlay.OverlayLayer.ModalityLevel;
47 import info.magnolia.ui.contentapp.DefinitionCloner;
48 import info.magnolia.ui.contentapp.browser.BrowserSubAppDescriptor;
49 import info.magnolia.ui.contentapp.field.WorkbenchField;
50 import info.magnolia.ui.contentapp.movedialog.action.MoveCancelledAction;
51 import info.magnolia.ui.contentapp.movedialog.action.MoveNodeActionDefinition;
52 import info.magnolia.ui.contentapp.movedialog.predicate.MoveAfterPossibilityPredicate;
53 import info.magnolia.ui.contentapp.movedialog.predicate.MoveBeforePossibilityPredicate;
54 import info.magnolia.ui.contentapp.movedialog.predicate.MoveInsidePossibilityPredicate;
55 import info.magnolia.ui.contentapp.movedialog.predicate.MovePossibilityPredicate;
56 import info.magnolia.ui.dialog.BaseDialogPresenter;
57 import info.magnolia.ui.dialog.DialogCloseHandler;
58 import info.magnolia.ui.dialog.DialogView;
59 import info.magnolia.ui.dialog.actionarea.DialogActionExecutor;
60 import info.magnolia.ui.dialog.actionarea.definition.ConfiguredEditorActionAreaDefinition;
61 import info.magnolia.ui.dialog.definition.ConfiguredDialogDefinition;
62 import info.magnolia.ui.dialog.definition.DialogDefinition;
63 import info.magnolia.ui.dialog.definition.SecondaryActionDefinition;
64 import info.magnolia.ui.framework.overlay.ViewAdapter;
65 import info.magnolia.ui.imageprovider.definition.ConfiguredImageProviderDefinition;
66 import info.magnolia.ui.vaadin.dialog.BaseDialog;
67 import info.magnolia.ui.vaadin.integration.NullItem;
68 import info.magnolia.ui.vaadin.integration.contentconnector.ContentConnector;
69 import info.magnolia.ui.vaadin.integration.contentconnector.JcrContentConnector;
70 import info.magnolia.ui.vaadin.integration.jcr.JcrNodeAdapter;
71 import info.magnolia.ui.workbench.WorkbenchPresenter;
72 import info.magnolia.ui.workbench.column.definition.ColumnDefinition;
73 import info.magnolia.ui.workbench.definition.ConfiguredWorkbenchDefinition;
74 import info.magnolia.ui.workbench.definition.ContentPresenterDefinition;
75 import info.magnolia.ui.workbench.tree.MoveHandler;
76 import info.magnolia.ui.workbench.tree.MoveLocation;
77 import info.magnolia.ui.workbench.tree.TreePresenter;
78 import info.magnolia.ui.workbench.tree.drop.DropConstraint;
79
80 import java.util.HashMap;
81 import java.util.HashSet;
82 import java.util.Iterator;
83 import java.util.LinkedList;
84 import java.util.List;
85 import java.util.Map;
86 import java.util.Map.Entry;
87 import java.util.Set;
88
89 import javax.inject.Inject;
90 import javax.jcr.RepositoryException;
91
92 import com.vaadin.data.Item;
93 import com.vaadin.data.Property.ValueChangeEvent;
94 import com.vaadin.data.Property.ValueChangeListener;
95
96
97
98
99 public class MoveDialogPresenterImpl extends BaseDialogPresenter implements MoveDialogPresenter {
100
101 private final DialogView dialogView;
102
103 private final EventBus eventBus = new ResettableEventBus(new SimpleEventBus());
104
105 private final WorkbenchPresenter workbenchPresenter;
106
107 private final AppContext appContext;
108
109 private final I18nizer i18nizer;
110
111 private final ContentConnector contentConnector;
112
113 private final MoveHandler dropHandler;
114
115 private final DefinitionCloner cloner;
116
117 private final Map<MoveLocation, ActionDefinition> actionMap = new HashMap<>();
118
119 private final Map<MoveLocation, MovePossibilityPredicate> possibilityPredicates = new HashMap<>();
120
121 private List<Item> nodesToMove;
122
123 private DropConstraint constraint;
124
125 private MoveActionCallback callback;
126
127 private Item currentHostCandidate;
128
129 private ConfiguredWorkbenchDefinition workbenchDefinition;
130
131 @Inject
132 public MoveDialogPresenterImpl(ComponentProvider componentProvider, DialogView dialogView, WorkbenchPresenter workbenchPresenter, DialogActionExecutor executor, AppContext appContext, I18nizer i18nizer, SimpleTranslator simpleTranslator, ContentConnector contentConnector) {
133 super(componentProvider, executor, dialogView, i18nizer, simpleTranslator);
134 this.dialogView = dialogView;
135 this.workbenchPresenter = workbenchPresenter;
136 this.appContext = appContext;
137 this.i18nizer = i18nizer;
138 this.contentConnector = contentConnector;
139 this.dropHandler = componentProvider.newInstance(MoveHandler.class);
140 this.cloner = new DefinitionCloner();
141 }
142
143 @Override
144 public Object[] getActionParameters(String actionName) {
145 return new Object[] { nodesToMove, callback, appContext, getHostCandidate(), dropHandler };
146 }
147
148 @Override
149 public DialogView start(BrowserSubAppDescriptor subAppDescriptor, List<Item> nodesToMove, MoveActionCallback callback) {
150
151 final ConfiguredImageProviderDefinition imageProviderDefinition = prepareImageProviderDefinition(subAppDescriptor);
152 this.workbenchDefinition = prepareWorkbenchDefinition(subAppDescriptor);
153
154 this.nodesToMove = nodesToMove;
155 this.constraint = componentProvider.newInstance(workbenchDefinition.getDropConstraintClass());
156 this.callback = callback;
157
158 initActions();
159 initMovePossibilityPredicates();
160
161 final WorkbenchField field = new WorkbenchField(
162 workbenchDefinition,
163 imageProviderDefinition,
164 workbenchPresenter,
165 eventBus);
166 ViewAdapter viewAdapter = new ViewAdapter(field);
167 viewAdapter.asVaadinComponent().addStyleName("choose-dialog");
168 dialogView.setContent(viewAdapter);
169 field.addValueChangeListener(new ValueChangeListener() {
170 @Override
171 public void valueChange(ValueChangeEvent event) {
172 currentHostCandidate = contentConnector.getItem(event.getProperty().getValue());
173 updatePossibleMoveLocations(currentHostCandidate);
174
175 }
176 });
177
178 DialogDefinition dialogDefinition = prepareDialogDefinition();
179 getExecutor().setDialogDefinition(dialogDefinition);
180 dialogView.setCaption(dialogDefinition.getLabel());
181 dialogView.addDialogCloseHandler(new DialogCloseHandler() {
182 @Override
183 public void onDialogClose(DialogView dialogView) {
184 ((ResettableEventBus) eventBus).reset();
185 }
186 });
187 super.start(dialogDefinition, appContext);
188 updatePossibleMoveLocations(getHostCandidate());
189
190 getView().getActionAreaView().getViewForAction(MoveLocation.INSIDE.name()).asVaadinComponent().addStyleName("commit");
191 getView().setClosable(true);
192 return dialogView;
193 }
194
195 private ConfiguredImageProviderDefinition prepareImageProviderDefinition(BrowserSubAppDescriptor subAppDescriptor) {
196 return (ConfiguredImageProviderDefinition) cloner.deepClone(subAppDescriptor.getImageProvider());
197 }
198
199 private ConfiguredWorkbenchDefinition prepareWorkbenchDefinition(BrowserSubAppDescriptor subAppDescriptor) {
200 final ConfiguredWorkbenchDefinition workbenchDefinition =
201 (ConfiguredWorkbenchDefinition) cloner.deepClone(subAppDescriptor.getWorkbench());
202
203 workbenchDefinition.setDialogWorkbench(true);
204 workbenchDefinition.setEditable(false);
205
206 List<ContentPresenterDefinition> contentPresenters = workbenchDefinition.getContentViews();
207 Iterator<ContentPresenterDefinition> it = contentPresenters.iterator();
208 ContentPresenterDefinition treePresenterDef = null;
209 while (it.hasNext() && treePresenterDef == null) {
210 ContentPresenterDefinition contentPresenterDef = it.next();
211 if (TreePresenter.class.isAssignableFrom(contentPresenterDef.getImplementationClass())) {
212 treePresenterDef = prepareTreePresenter(contentPresenterDef);
213 }
214 }
215
216 if (treePresenterDef != null) {
217 contentPresenters.clear();
218 contentPresenters.add(treePresenterDef);
219 }
220
221 return workbenchDefinition;
222 }
223
224 private ContentPresenterDefinition prepareTreePresenter(ContentPresenterDefinition treePresenter) {
225 ContentPresenterDefinition def = cloner.deepClone(treePresenter);
226 if (!def.getColumns().isEmpty()) {
227 ColumnDefinition column = def.getColumns().get(0);
228 def.getColumns().clear();
229 def.getColumns().add(column);
230 }
231 return def;
232 }
233
234 protected void initMovePossibilityPredicates() {
235 possibilityPredicates.put(MoveLocation.AFTER, new MoveAfterPossibilityPredicate(constraint, nodesToMove));
236 possibilityPredicates.put(MoveLocation.BEFORE, new MoveBeforePossibilityPredicate(constraint, nodesToMove));
237 possibilityPredicates.put(MoveLocation.INSIDE, new MoveInsidePossibilityPredicate(constraint, nodesToMove));
238 }
239
240 protected void updatePossibleMoveLocations(Item possibleHost) {
241 Set<MoveLocation> possibleLocations = new HashSet<MoveLocation>();
242 if (possibleHost == null) {
243 possibleHost = new NullItem();
244 }
245
246 Iterator<Entry<MoveLocation, MovePossibilityPredicate>> it = possibilityPredicates.entrySet().iterator();
247 while (it.hasNext()) {
248 Entry<MoveLocation, MovePossibilityPredicate> entry = it.next();
249 if (entry.getValue().isMovePossible(possibleHost)) {
250 possibleLocations.add(entry.getKey());
251 }
252 }
253
254 getActionArea().setPossibleMoveLocations(possibleLocations);
255 }
256
257 private void initActions() {
258 for (MoveLocation location : MoveLocation.values()) {
259 ConfiguredActionDefinition definition = i18nizer.decorate(new MoveNodeActionDefinition(location));
260 definition.setName(location.name());
261 actionMap.put(location, definition);
262 }
263 }
264
265 private DialogDefinition prepareDialogDefinition() {
266 ConfiguredDialogDefinition def = new ConfiguredDialogDefinition();
267 def = i18nizer.decorate(def);
268 def.setId("ui-contentapp:code:MoveDialogPresenterImpl.moveDialog");
269
270 for (MoveLocation location : MoveLocation.values()) {
271 def.addAction(actionMap.get(location));
272 }
273
274 ConfiguredActionDefinition cancelDef = new ConfiguredActionDefinition();
275 cancelDef.setName("cancel");
276 cancelDef.setImplementationClass(MoveCancelledAction.class);
277 def.addAction(cancelDef);
278
279 ConfiguredEditorActionAreaDefinition actionAreaDefinition = new ConfiguredEditorActionAreaDefinition();
280 actionAreaDefinition.setPresenterClass(MoveDialogActionAreaPresenter.class);
281
282 List<SecondaryActionDefinition> secondaryActions = new LinkedList<SecondaryActionDefinition>();
283 secondaryActions.add(new SecondaryActionDefinition(MoveLocation.AFTER.name()));
284 secondaryActions.add(new SecondaryActionDefinition(MoveLocation.BEFORE.name()));
285 actionAreaDefinition.setSecondaryActions(secondaryActions);
286
287 def.setActionArea(actionAreaDefinition);
288 def.setModalityLevel(ModalityLevel.LIGHT);
289 return def;
290 }
291
292 @Override
293 public MoveDialogActionAreaPresenter getActionArea() {
294 return (MoveDialogActionAreaPresenter) super.getActionArea();
295 }
296
297 @Override
298 protected DialogActionExecutor getExecutor() {
299 return (DialogActionExecutor) super.getExecutor();
300 }
301
302 @Override
303 protected void executeAction(String actionName, Object[] actionContextParams) {
304 actionName = getCorrectActionName(actionName);
305 if (actionName != null) {
306 super.executeAction(actionName, actionContextParams);
307 }
308 }
309
310 public String getCorrectActionName(String actionName) {
311 if (actionName.equals(BaseDialog.COMMIT_ACTION_NAME)) {
312 boolean moveInsideActionEnabled = getView().getActionAreaView().getViewForAction(MoveLocation.INSIDE.name()).asVaadinComponent().isEnabled();
313 actionName = moveInsideActionEnabled ? MoveLocation.INSIDE.name() : null;
314 }
315 return actionName;
316 }
317
318 private Item getHostCandidate() {
319 if (currentHostCandidate != null) {
320 return currentHostCandidate;
321 } else {
322 try {
323 String workspace = ((JcrContentConnector) contentConnector).getContentConnectorDefinition().getWorkspace();
324 return new JcrNodeAdapter(MgnlContext.getJCRSession(workspace).getRootNode());
325 } catch (RepositoryException e) {
326 return null;
327 }
328 }
329 }
330
331 @Override
332 protected void onCancel () {
333 if (callback != null) {
334 callback.onMoveCancelled();
335 }
336 }
337 }