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