• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Eclipse Public License, Version 1.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.eclipse.org/org/documents/epl-v10.php
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
17 
18 import com.android.ide.common.api.INode;
19 import com.android.ide.common.api.InsertType;
20 import com.android.ide.common.layout.BaseLayoutRule;
21 import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
22 import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
23 import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
24 import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
25 
26 import org.eclipse.jface.viewers.TreeViewer;
27 import org.eclipse.jface.viewers.ViewerDropAdapter;
28 import org.eclipse.swt.dnd.DND;
29 import org.eclipse.swt.dnd.DropTargetEvent;
30 import org.eclipse.swt.dnd.TransferData;
31 
32 import java.util.ArrayList;
33 import java.util.HashSet;
34 import java.util.List;
35 import java.util.Set;
36 
37 /** Drop listener for the outline page */
38 /*package*/ class OutlineDropListener extends ViewerDropAdapter {
39     private final OutlinePage mOutlinePage;
40 
OutlineDropListener(OutlinePage outlinePage, TreeViewer treeViewer)41     public OutlineDropListener(OutlinePage outlinePage, TreeViewer treeViewer) {
42         super(treeViewer);
43         mOutlinePage = outlinePage;
44     }
45 
46     @Override
dragEnter(DropTargetEvent event)47     public void dragEnter(DropTargetEvent event) {
48         if (event.detail == DND.DROP_NONE && GlobalCanvasDragInfo.getInstance().isDragging()) {
49             // For some inexplicable reason, we get DND.DROP_NONE from the palette
50             // even though in its drag start we set DND.DROP_COPY, so correct that here...
51             int operation = DND.DROP_COPY;
52             event.detail = operation;
53         }
54         super.dragEnter(event);
55     }
56 
57     @Override
performDrop(Object data)58     public boolean performDrop(Object data) {
59         final DropTargetEvent event = getCurrentEvent();
60         if (event == null) {
61             return false;
62         }
63         int location = determineLocation(event);
64         if (location == LOCATION_NONE) {
65             return false;
66         }
67 
68         final SimpleElement[] elements;
69         SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
70         if (sxt.isSupportedType(event.currentDataType)) {
71             if (data instanceof SimpleElement[]) {
72                 elements = (SimpleElement[]) data;
73             } else {
74                 return false;
75             }
76         } else {
77             return false;
78         }
79         if (elements.length == 0) {
80             return false;
81         }
82 
83         // Determine target:
84         CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
85         if (parent == null) {
86             return false;
87         }
88 
89         int index = -1;
90         UiViewElementNode parentNode = parent.getUiViewNode();
91         if (location == LOCATION_BEFORE || location == LOCATION_AFTER) {
92             UiViewElementNode node = parentNode;
93             parent = parent.getParent();
94             if (parent == null) {
95                 return false;
96             }
97             parentNode = parent.getUiViewNode();
98 
99             // Determine index
100             index = 0;
101             for (UiElementNode child : parentNode.getUiChildren()) {
102                 if (child == node) {
103                     break;
104                 }
105                 index++;
106             }
107             if (location == LOCATION_AFTER) {
108                 index++;
109             }
110         }
111 
112         // Copy into new position.
113         final LayoutCanvas canvas = mOutlinePage.getEditor().getCanvasControl();
114         final NodeProxy targetNode = canvas.getNodeFactory().create(parentNode);
115 
116         // Record children of the target right before the drop (such that we can
117         // find out after the drop which exact children were inserted)
118         Set<INode> children = new HashSet<INode>();
119         for (INode node : targetNode.getChildren()) {
120             children.add(node);
121         }
122 
123         String label = MoveGesture.computeUndoLabel(targetNode, elements, event.detail);
124         final int indexFinal = index;
125         canvas.getLayoutEditor().wrapUndoEditXmlModel(label, new Runnable() {
126             public void run() {
127                 InsertType insertType = MoveGesture.getInsertType(event, targetNode);
128                 canvas.getRulesEngine().setInsertType(insertType);
129 
130                 Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas();
131                 boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas;
132                 BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal);
133                 targetNode.applyPendingChanges();
134 
135                 // Clean up drag if applicable
136                 if (event.detail == DND.DROP_MOVE) {
137                     GlobalCanvasDragInfo.getInstance().removeSource();
138                 }
139             }
140         });
141 
142         // Now find out which nodes were added, and look up their corresponding
143         // CanvasViewInfos
144         final List<INode> added = new ArrayList<INode>();
145         for (INode node : targetNode.getChildren()) {
146             if (!children.contains(node)) {
147                 added.add(node);
148             }
149         }
150         // Select the newly dropped nodes
151         final SelectionManager selectionManager = canvas.getSelectionManager();
152         selectionManager.setOutlineSelection(added);
153 
154         canvas.redraw();
155 
156         return true;
157     }
158 
159     @Override
validateDrop(Object target, int operation, TransferData transferType)160     public boolean validateDrop(Object target, int operation,
161             TransferData transferType) {
162         DropTargetEvent event = getCurrentEvent();
163         if (event == null) {
164             return false;
165         }
166         int location = determineLocation(event);
167         if (location == LOCATION_NONE) {
168             return false;
169         }
170 
171         SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
172         if (!sxt.isSupportedType(transferType)) {
173             return false;
174         }
175 
176         CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
177         if (parent == null) {
178             return false;
179         }
180 
181         UiViewElementNode parentNode = parent.getUiViewNode();
182 
183         if (location == LOCATION_ON) {
184             // Targeting the middle of an item means to add it as a new child
185             // of the given element. This is only allowed on some types of nodes.
186             if (!DescriptorsUtils.canInsertChildren(parentNode.getDescriptor(),
187                     parent.getViewObject())) {
188                 return false;
189             }
190         }
191 
192         // Check that the drop target position is not a child or identical to
193         // one of the dragged items
194         SelectionItem[] sel = GlobalCanvasDragInfo.getInstance().getCurrentSelection();
195         if (sel != null) {
196             for (SelectionItem item : sel) {
197                 if (isAncestor(item.getViewInfo().getUiViewNode(), parentNode)) {
198                     return false;
199                 }
200             }
201         }
202 
203         return true;
204     }
205 
206     /** Returns true if the given parent node is an ancestor of the given child node  */
isAncestor(UiElementNode parent, UiElementNode child)207     private boolean isAncestor(UiElementNode parent, UiElementNode child) {
208         while (child != null) {
209             if (child == parent) {
210                 return true;
211             }
212             child = child.getUiParent();
213         }
214         return false;
215     }
216 }
217