aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java
diff options
context:
space:
mode:
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java217
1 files changed, 217 insertions, 0 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java
new file mode 100644
index 000000000..f4a826fa2
--- /dev/null
+++ b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/OutlineDropListener.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Eclipse Public License, Version 1.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.eclipse.org/org/documents/epl-v10.php
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.ide.eclipse.adt.internal.editors.layout.gle2;
+
+import com.android.ide.common.api.INode;
+import com.android.ide.common.api.InsertType;
+import com.android.ide.common.layout.BaseLayoutRule;
+import com.android.ide.eclipse.adt.internal.editors.descriptors.DescriptorsUtils;
+import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy;
+import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode;
+import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode;
+
+import org.eclipse.jface.viewers.TreeViewer;
+import org.eclipse.jface.viewers.ViewerDropAdapter;
+import org.eclipse.swt.dnd.DND;
+import org.eclipse.swt.dnd.DropTargetEvent;
+import org.eclipse.swt.dnd.TransferData;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/** Drop listener for the outline page */
+/*package*/ class OutlineDropListener extends ViewerDropAdapter {
+ private final OutlinePage mOutlinePage;
+
+ public OutlineDropListener(OutlinePage outlinePage, TreeViewer treeViewer) {
+ super(treeViewer);
+ mOutlinePage = outlinePage;
+ }
+
+ @Override
+ public void dragEnter(DropTargetEvent event) {
+ if (event.detail == DND.DROP_NONE && GlobalCanvasDragInfo.getInstance().isDragging()) {
+ // For some inexplicable reason, we get DND.DROP_NONE from the palette
+ // even though in its drag start we set DND.DROP_COPY, so correct that here...
+ int operation = DND.DROP_COPY;
+ event.detail = operation;
+ }
+ super.dragEnter(event);
+ }
+
+ @Override
+ public boolean performDrop(Object data) {
+ final DropTargetEvent event = getCurrentEvent();
+ if (event == null) {
+ return false;
+ }
+ int location = determineLocation(event);
+ if (location == LOCATION_NONE) {
+ return false;
+ }
+
+ final SimpleElement[] elements;
+ SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
+ if (sxt.isSupportedType(event.currentDataType)) {
+ if (data instanceof SimpleElement[]) {
+ elements = (SimpleElement[]) data;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+ if (elements.length == 0) {
+ return false;
+ }
+
+ // Determine target:
+ CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
+ if (parent == null) {
+ return false;
+ }
+
+ int index = -1;
+ UiViewElementNode parentNode = parent.getUiViewNode();
+ if (location == LOCATION_BEFORE || location == LOCATION_AFTER) {
+ UiViewElementNode node = parentNode;
+ parent = parent.getParent();
+ if (parent == null) {
+ return false;
+ }
+ parentNode = parent.getUiViewNode();
+
+ // Determine index
+ index = 0;
+ for (UiElementNode child : parentNode.getUiChildren()) {
+ if (child == node) {
+ break;
+ }
+ index++;
+ }
+ if (location == LOCATION_AFTER) {
+ index++;
+ }
+ }
+
+ // Copy into new position.
+ final LayoutCanvas canvas = mOutlinePage.getEditor().getCanvasControl();
+ final NodeProxy targetNode = canvas.getNodeFactory().create(parentNode);
+
+ // Record children of the target right before the drop (such that we can
+ // find out after the drop which exact children were inserted)
+ Set<INode> children = new HashSet<INode>();
+ for (INode node : targetNode.getChildren()) {
+ children.add(node);
+ }
+
+ String label = MoveGesture.computeUndoLabel(targetNode, elements, event.detail);
+ final int indexFinal = index;
+ canvas.getEditorDelegate().getEditor().wrapUndoEditXmlModel(label, new Runnable() {
+ @Override
+ public void run() {
+ InsertType insertType = MoveGesture.getInsertType(event, targetNode);
+ canvas.getRulesEngine().setInsertType(insertType);
+
+ Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas();
+ boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas;
+ BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal);
+ targetNode.applyPendingChanges();
+
+ // Clean up drag if applicable
+ if (event.detail == DND.DROP_MOVE) {
+ GlobalCanvasDragInfo.getInstance().removeSource();
+ }
+ }
+ });
+
+ // Now find out which nodes were added, and look up their corresponding
+ // CanvasViewInfos
+ final List<INode> added = new ArrayList<INode>();
+ for (INode node : targetNode.getChildren()) {
+ if (!children.contains(node)) {
+ added.add(node);
+ }
+ }
+ // Select the newly dropped nodes
+ final SelectionManager selectionManager = canvas.getSelectionManager();
+ selectionManager.setOutlineSelection(added);
+
+ canvas.redraw();
+
+ return true;
+ }
+
+ @Override
+ public boolean validateDrop(Object target, int operation,
+ TransferData transferType) {
+ DropTargetEvent event = getCurrentEvent();
+ if (event == null) {
+ return false;
+ }
+ int location = determineLocation(event);
+ if (location == LOCATION_NONE) {
+ return false;
+ }
+
+ SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance();
+ if (!sxt.isSupportedType(transferType)) {
+ return false;
+ }
+
+ CanvasViewInfo parent = OutlinePage.getViewInfo(event.item.getData());
+ if (parent == null) {
+ return false;
+ }
+
+ UiViewElementNode parentNode = parent.getUiViewNode();
+
+ if (location == LOCATION_ON) {
+ // Targeting the middle of an item means to add it as a new child
+ // of the given element. This is only allowed on some types of nodes.
+ if (!DescriptorsUtils.canInsertChildren(parentNode.getDescriptor(),
+ parent.getViewObject())) {
+ return false;
+ }
+ }
+
+ // Check that the drop target position is not a child or identical to
+ // one of the dragged items
+ SelectionItem[] sel = GlobalCanvasDragInfo.getInstance().getCurrentSelection();
+ if (sel != null) {
+ for (SelectionItem item : sel) {
+ if (isAncestor(item.getViewInfo().getUiViewNode(), parentNode)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ /** Returns true if the given parent node is an ancestor of the given child node */
+ private boolean isAncestor(UiElementNode parent, UiElementNode child) {
+ while (child != null) {
+ if (child == parent) {
+ return true;
+ }
+ child = child.getUiParent();
+ }
+ return false;
+ }
+}