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