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