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.workbench.tree.drop;
35
36 import static info.magnolia.jcr.util.NodeUtil.*;
37
38 import info.magnolia.jcr.util.NodeUtil;
39 import info.magnolia.ui.vaadin.integration.jcr.JcrItemAdapter;
40 import info.magnolia.ui.vaadin.integration.jcr.JcrItemUtil;
41 import info.magnolia.ui.workbench.definition.WorkbenchDefinition;
42 import info.magnolia.ui.workbench.tree.HierarchicalJcrContainer;
43 import info.magnolia.ui.workbench.tree.MoveHandler;
44 import info.magnolia.ui.workbench.tree.MoveLocation;
45
46 import java.util.Arrays;
47 import java.util.Collection;
48 import java.util.Iterator;
49 import java.util.Set;
50
51 import javax.jcr.Item;
52 import javax.jcr.Node;
53 import javax.jcr.Property;
54 import javax.jcr.RepositoryException;
55
56 import org.slf4j.Logger;
57 import org.slf4j.LoggerFactory;
58
59 import com.vaadin.event.Transferable;
60 import com.vaadin.event.dd.DragAndDropEvent;
61 import com.vaadin.event.dd.DropHandler;
62 import com.vaadin.event.dd.acceptcriteria.AcceptCriterion;
63 import com.vaadin.event.dd.acceptcriteria.ServerSideCriterion;
64 import com.vaadin.shared.ui.dd.VerticalDropLocation;
65 import com.vaadin.v7.event.DataBoundTransferable;
66 import com.vaadin.v7.ui.AbstractSelect.AbstractSelectTargetDetails;
67 import com.vaadin.v7.ui.TreeTable;
68
69
70
71
72
73
74
75 public class TreeViewDropHandler implements MoveHandler, DropHandler {
76
77 private final Logger log = LoggerFactory.getLogger(getClass());
78
79 private TreeTable tree;
80 private DropConstraint constraint;
81 private AcceptCriterion serverSideCriterion;
82
83 public TreeViewDropHandler() {
84 createAcceptCriterion();
85 }
86
87 public TreeViewDropHandler(TreeTable tree, DropConstraint constraint) {
88 this.tree = tree;
89 this.constraint = constraint;
90 createAcceptCriterion();
91 }
92
93 @Override
94 public void drop(DragAndDropEvent dropEvent) {
95
96
97
98 Transferable t = dropEvent.getTransferable();
99
100
101
102 if (t.getSourceComponent() != tree || !(t instanceof DataBoundTransferable)) {
103 return;
104 }
105
106 AbstractSelectTargetDetails target = (AbstractSelectTargetDetails) dropEvent.getTargetDetails();
107
108 Object targetItemId = target.getItemIdOver();
109
110 VerticalDropLocation location = target.getDropLocation();
111 if (location == null) {
112 log.debug("DropLocation is null. Do nothing.");
113 return;
114 }
115
116 Iterator<Object> selected = getItemIdsToMove(dropEvent).iterator();
117 while (selected.hasNext()) {
118 Object sourceItemId = selected.next();
119 moveNode(sourceItemId, targetItemId, location);
120 }
121 }
122
123
124
125
126
127
128
129
130 private Collection<Object> getItemIdsToMove(DragAndDropEvent dropEvent) {
131 Transferable t = dropEvent.getTransferable();
132 Object draggingItemId = ((DataBoundTransferable) t).getItemId();
133
134
135 Set<Object> selectedItemIds = (Set<Object>) ((TreeTable) t.getSourceComponent()).getValue();
136 if (selectedItemIds.contains(draggingItemId)) {
137 return selectedItemIds;
138 }
139
140
141 return Arrays.asList(draggingItemId);
142 }
143
144
145
146
147 @Override
148 public AcceptCriterion getAcceptCriterion() {
149 return serverSideCriterion;
150 }
151
152
153
154
155
156
157
158
159
160
161
162
163
164 private void moveNode(Object sourceItemId, Object targetItemId, VerticalDropLocation location) {
165 log.debug("DropLocation: {}", location.name());
166
167 HierarchicalJcrContainero/magnolia/ui/workbench/tree/HierarchicalJcrContainer.html#HierarchicalJcrContainer">HierarchicalJcrContainer container = (HierarchicalJcrContainer) tree.getContainerDataSource();
168 JcrItemAdapter../../info/magnolia/ui/vaadin/integration/jcr/JcrItemAdapter.html#JcrItemAdapter">JcrItemAdapter sourceItem = (JcrItemAdapter) container.getItem(sourceItemId);
169 JcrItemAdapter../../info/magnolia/ui/vaadin/integration/jcr/JcrItemAdapter.html#JcrItemAdapter">JcrItemAdapter targetItem = (JcrItemAdapter) container.getItem(targetItemId);
170
171
172
173
174
175
176
177
178 if (location == VerticalDropLocation.MIDDLE) {
179 if (constraint.allowedAsChild(sourceItem, targetItem)) {
180
181 moveItem(sourceItem, targetItem, MoveLocation.INSIDE);
182 container.setParent(sourceItemId, targetItemId);
183 }
184 } else {
185 Object parentId = container.getParent(targetItemId);
186
187 if (parentId == null && targetItem.getJcrItem() != null) {
188 try {
189 parentId = JcrItemUtil.getItemId(targetItem.getJcrItem().getParent());
190 } catch (RepositoryException e) {
191 log.info("Cannot execute drag and drop node " + sourceItem.getJcrItem() + " to " + targetItem.getJcrItem(), e);
192 }
193 }
194 if (location == VerticalDropLocation.TOP) {
195 if (parentId != null && constraint.allowedBefore(sourceItem, targetItem)) {
196
197 moveItem(sourceItem, targetItem, MoveLocation.BEFORE);
198 container.setParent(sourceItemId, parentId);
199 }
200 } else if (location == VerticalDropLocation.BOTTOM) {
201 if (parentId != null && constraint.allowedAfter(sourceItem, targetItem)) {
202 moveItem(sourceItem, targetItem, MoveLocation.AFTER);
203 container.setParent(sourceItemId, parentId);
204 }
205 }
206 }
207 }
208
209
210
211
212 private void createAcceptCriterion() {
213 serverSideCriterion = new ServerSideCriterion() {
214
215 @Override
216 public boolean accept(DragAndDropEvent dragEvent) {
217 boolean res = true;
218 Iterator<Object> selected = getItemIdsToMove(dragEvent).iterator();
219 while (selected.hasNext()) {
220 Object sourceItemId = selected.next();
221 HierarchicalJcrContainero/magnolia/ui/workbench/tree/HierarchicalJcrContainer.html#HierarchicalJcrContainer">HierarchicalJcrContainer container = (HierarchicalJcrContainer) tree.getContainerDataSource();
222 JcrItemAdapter../../info/magnolia/ui/vaadin/integration/jcr/JcrItemAdapter.html#JcrItemAdapter">JcrItemAdapter sourceItem = (JcrItemAdapter) container.getItem(sourceItemId);
223 res &= constraint.allowedToMove(sourceItem);
224 }
225 return res;
226 }
227 };
228
229 }
230
231
232
233
234 public boolean basicMoveCheck(Item source, Item target) {
235 try {
236
237 if (!target.isNode()) {
238 return false;
239 }
240
241 if (target.getPath().equals(source.getPath()) && target.getSession().getWorkspace().getName().equals(source.getSession().getWorkspace().getName())) {
242 return false;
243 }
244
245
246 Node targetNode = (Node) target;
247 if (!source.isNode() && (NodeUtil.isSame(targetNode, source.getParent()) || targetNode.hasProperty(source.getName()))) {
248 return false;
249 }
250
251 return true;
252 } catch (RepositoryException re) {
253 log.debug("Cannot determine whether drag and drop is possible due to: {}", re.getMessage(), re);
254 return false;
255 }
256 }
257
258
259
260
261
262 public void moveNode(Node nodeToMove, Node newParent, MoveLocation location) throws RepositoryException {
263 if (!basicMoveCheck(nodeToMove, newParent)) {
264 return;
265 }
266 switch (location) {
267 case INSIDE:
268 String newPath = combinePathAndName(newParent.getPath(), nodeToMove.getName());
269 nodeToMove.getSession().move(nodeToMove.getPath(), newPath);
270 break;
271 case BEFORE:
272 moveNodeBefore(nodeToMove, newParent);
273 break;
274 case AFTER:
275 moveNodeAfter(nodeToMove, newParent);
276 break;
277 }
278 }
279
280
281
282
283
284 @Override
285 public boolean moveItem(com.vaadin.v7.data.Item source, com.vaadin.v7.data.Item target, MoveLocation location) {
286 Item sourceItem = ((JcrItemAdapter) source).getJcrItem();
287 Item targetItem = ((JcrItemAdapter) target).getJcrItem();
288 if (!basicMoveCheck(sourceItem, targetItem)) {
289 return false;
290 }
291 try {
292 final Node targetNode = (Node) targetItem;
293 if (sourceItem.isNode()) {
294 moveNode((Node) sourceItem, targetNode, location);
295 } else if (location == MoveLocation.INSIDE) {
296 NodeUtil.moveProperty((Property) sourceItem, targetNode);
297 } else {
298 return false;
299 }
300 sourceItem.getSession().save();
301 return true;
302 } catch (RepositoryException re) {
303 log.debug("Cannot execute drag and drop action", re);
304 return false;
305 }
306 }
307
308 @Override
309 public DropHandler asDropHandler() {
310 return this;
311 }
312 }