Home | History | Annotate | Download | only in gle2
      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 
     41     public OutlineDropListener(OutlinePage outlinePage, TreeViewer treeViewer) {
     42         super(treeViewer);
     43         mOutlinePage = outlinePage;
     44     }
     45 
     46     @Override
     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
     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
    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  */
    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