• 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.getEditorDelegate().getEditor().wrapUndoEditXmlModel(label, new Runnable() {
126             @Override
127             public void run() {
128                 InsertType insertType = MoveGesture.getInsertType(event, targetNode);
129                 canvas.getRulesEngine().setInsertType(insertType);
130 
131                 Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas();
132                 boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas;
133                 BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal);
134                 targetNode.applyPendingChanges();
135 
136                 // Clean up drag if applicable
137                 if (event.detail == DND.DROP_MOVE) {
138                     GlobalCanvasDragInfo.getInstance().removeSource();
139                 }
140             }
141         });
142 
143         // Now find out which nodes were added, and look up their corresponding
144         // CanvasViewInfos
145         final List<INode> added = new ArrayList<INode>();
146         for (INode node : targetNode.getChildren()) {
147             if (!children.contains(node)) {
148                 added.add(node);
149             }
150         }
151         // Select the newly dropped nodes
152         final SelectionManager selectionManager = canvas.getSelectionManager();
153         selectionManager.setOutlineSelection(added);
154 
155         canvas.redraw();
156 
157         return true;
158     }
159 
160     @Override
validateDrop(Object target, int operation, TransferData transferType)161     public boolean validateDrop(Object target, int operation,
162             TransferData transferType) {
163         DropTargetEvent event = getCurrentEvent();
164         if (event == null) {
165             return false;
166         }
167         int location = determineLocation(event);
168         if (location == LOCATION_NONE) {
169             return false;
170         }
171 
172         SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
173         if (!sxt.isSupportedType(transferType)) {
174             return false;
175         }
176 
177         CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
178         if (parent == null) {
179             return false;
180         }
181 
182         UiViewElementNode parentNode = parent.getUiViewNode();
183 
184         if (location == LOCATION_ON) {
185             // Targeting the middle of an item means to add it as a new child
186             // of the given element. This is only allowed on some types of nodes.
187             if (!DescriptorsUtils.canInsertChildren(parentNode.getDescriptor(),
188                     parent.getViewObject())) {
189                 return false;
190             }
191         }
192 
193         // Check that the drop target position is not a child or identical to
194         // one of the dragged items
195         SelectionItem[] sel = GlobalCanvasDragInfo.getInstance().getCurrentSelection();
196         if (sel != null) {
197             for (SelectionItem item : sel) {
198                 if (isAncestor(item.getViewInfo().getUiViewNode(), parentNode)) {
199                     return false;
200                 }
201             }
202         }
203 
204         return true;
205     }
206 
207     /** Returns true if the given parent node is an ancestor of the given child node  */
isAncestor(UiElementNode parent, UiElementNode child)208     private boolean isAncestor(UiElementNode parent, UiElementNode child) {
209         while (child != null) {
210             if (child == parent) {
211                 return true;
212             }
213             child = child.getUiParent();
214         }
215         return false;
216     }
217 }
218