/* * 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.getLayoutEditor().wrapUndoEditXmlModel(label, new Runnable() { public void run() { Object sourceCanvas = GlobalCanvasDragInfo.getInstance().getSourceCanvas(); InsertType insertType; if (event.detail == DND.DROP_MOVE) { insertType = InsertType.MOVE; } else if (sourceCanvas != null) { insertType = InsertType.PASTE; } else { insertType = InsertType.CREATE; } canvas.getRulesEngine().setInsertType(insertType); boolean createNew = event.detail == DND.DROP_COPY || sourceCanvas != canvas; BaseLayoutRule.insertAt(targetNode, elements, createNew, indexFinal); // 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.updateOutlineSelection(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; } }