diff options
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.java | 217 |
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; + } +} |