diff options
Diffstat (limited to 'eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java')
-rw-r--r-- | eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java | 852 |
1 files changed, 0 insertions, 852 deletions
diff --git a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java b/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java deleted file mode 100644 index 7cf3a647a..000000000 --- a/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java +++ /dev/null @@ -1,852 +0,0 @@ -/* - * 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.DropFeedback; -import com.android.ide.common.api.INode; -import com.android.ide.common.api.InsertType; -import com.android.ide.common.api.Point; -import com.android.ide.common.api.Rect; -import com.android.ide.eclipse.adt.AdtPlugin; -import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeFactory; -import com.android.ide.eclipse.adt.internal.editors.layout.gre.NodeProxy; -import com.android.ide.eclipse.adt.internal.editors.layout.gre.RulesEngine; -import com.android.ide.eclipse.adt.internal.editors.layout.uimodel.UiViewElementNode; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode; -import com.android.ide.eclipse.adt.internal.editors.uimodel.UiElementNode.NodeCreationListener; - -import org.eclipse.jface.viewers.ISelection; -import org.eclipse.jface.viewers.TreePath; -import org.eclipse.jface.viewers.TreeSelection; -import org.eclipse.swt.dnd.DND; -import org.eclipse.swt.dnd.DropTargetEvent; -import org.eclipse.swt.dnd.TransferData; -import org.eclipse.swt.graphics.GC; -import org.eclipse.swt.widgets.Display; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -/** - * The Move gesture provides the operation for moving widgets around in the canvas. - */ -public class MoveGesture extends DropGesture { - /** The associated {@link LayoutCanvas}. */ - private LayoutCanvas mCanvas; - - /** Overlay which paints the drag & drop feedback. */ - private MoveOverlay mOverlay; - - private static final boolean DEBUG = false; - - /** - * The top view right under the drag'n'drop cursor. - * This can only be null during a drag'n'drop when there is no view under the cursor - * or after the state was all cleared. - */ - private CanvasViewInfo mCurrentView; - - /** - * The elements currently being dragged. This will always be non-null for a valid - * drag'n'drop that happens within the same instance of Eclipse. - * <p/> - * In the event that the drag and drop happens between different instances of Eclipse - * this will remain null. - */ - private SimpleElement[] mCurrentDragElements; - - /** - * The first view under the cursor that responded to onDropEnter is called the "target view". - * It can differ from mCurrentView, typically because a terminal View doesn't - * accept drag'n'drop so its parent layout became the target drag'n'drop receiver. - * <p/> - * The target node is the proxy node associated with the target view. - * This can be null if no view under the cursor accepted the drag'n'drop or if the node - * factory couldn't create a proxy for it. - */ - private NodeProxy mTargetNode; - - /** - * The latest drop feedback returned by IViewRule.onDropEnter/Move. - */ - private DropFeedback mFeedback; - - /** - * {@link #dragLeave(DropTargetEvent)} is unfortunately called right before data is - * about to be dropped (between the last {@link #dragOver(DropTargetEvent)} and the - * next {@link #dropAccept(DropTargetEvent)}). That means we can't just - * trash the current DropFeedback from the current view rule in dragLeave(). - * Instead we preserve it in mLeaveTargetNode and mLeaveFeedback in case a dropAccept - * happens next. - */ - private NodeProxy mLeaveTargetNode; - - /** - * @see #mLeaveTargetNode - */ - private DropFeedback mLeaveFeedback; - - /** - * @see #mLeaveTargetNode - */ - private CanvasViewInfo mLeaveView; - - /** Singleton used to keep track of drag selection in the same Eclipse instance. */ - private final GlobalCanvasDragInfo mGlobalDragInfo; - - /** - * Constructs a new {@link MoveGesture}, tied to the given canvas. - * - * @param canvas The canvas to associate the {@link MoveGesture} with. - */ - public MoveGesture(LayoutCanvas canvas) { - mCanvas = canvas; - mGlobalDragInfo = GlobalCanvasDragInfo.getInstance(); - } - - @Override - public List<Overlay> createOverlays() { - mOverlay = new MoveOverlay(); - return Collections.<Overlay> singletonList(mOverlay); - } - - @Override - public void begin(ControlPoint pos, int startMask) { - super.begin(pos, startMask); - - // Hide selection overlays during a move drag - mCanvas.getSelectionOverlay().setHidden(true); - } - - @Override - public void end(ControlPoint pos, boolean canceled) { - super.end(pos, canceled); - - mCanvas.getSelectionOverlay().setHidden(false); - - // Ensure that the outline is back to showing the current selection, since during - // a drag gesture we temporarily set it to show the current target node instead. - mCanvas.getSelectionManager().syncOutlineSelection(); - } - - /* TODO: Pass modifier mask to drag rules as well! This doesn't work yet since - the drag & drop code seems to steal keyboard events. - @Override - public boolean keyPressed(KeyEvent event) { - update(mCanvas.getGestureManager().getCurrentControlPoint()); - mCanvas.redraw(); - return true; - } - - @Override - public boolean keyReleased(KeyEvent event) { - update(mCanvas.getGestureManager().getCurrentControlPoint()); - mCanvas.redraw(); - return true; - } - */ - - /* - * The cursor has entered the drop target boundaries. - * {@inheritDoc} - */ - @Override - public void dragEnter(DropTargetEvent event) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "drag enter", event); - - // Make sure we don't have any residual data from an earlier operation. - clearDropInfo(); - mLeaveTargetNode = null; - mLeaveFeedback = null; - mLeaveView = null; - - // Get the dragged elements. - // - // The current transfered type can be extracted from the event. - // As described in dragOver(), this works basically works on Windows but - // not on Linux or Mac, in which case we can't get the type until we - // receive dropAccept/drop(). - // For consistency we try to use the GlobalCanvasDragInfo instance first, - // and if it fails we use the event transfer type as a backup (but as said - // before it will most likely work only on Windows.) - // In any case this can be null even for a valid transfer. - - mCurrentDragElements = mGlobalDragInfo.getCurrentElements(); - - if (mCurrentDragElements == null) { - SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance(); - if (sxt.isSupportedType(event.currentDataType)) { - mCurrentDragElements = (SimpleElement[]) sxt.nativeToJava(event.currentDataType); - } - } - - // if there is no data to transfer, invalidate the drag'n'drop. - // The assumption is that the transfer should have at least one element with a - // a non-null non-empty FQCN. Everything else is optional. - if (mCurrentDragElements == null || - mCurrentDragElements.length == 0 || - mCurrentDragElements[0] == null || - mCurrentDragElements[0].getFqcn() == null || - mCurrentDragElements[0].getFqcn().length() == 0) { - event.detail = DND.DROP_NONE; - } - - dragOperationChanged(event); - } - - /* - * The operation being performed has changed (e.g. modifier key). - * {@inheritDoc} - */ - @Override - public void dragOperationChanged(DropTargetEvent event) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "drag changed", event); - - checkDataType(event); - recomputeDragType(event); - } - - private void recomputeDragType(DropTargetEvent event) { - if (event.detail == DND.DROP_DEFAULT) { - // Default means we can now choose the default operation, either copy or move. - // If the drag comes from the same canvas we default to move, otherwise we - // default to copy. - - if (mGlobalDragInfo.getSourceCanvas() == mCanvas && - (event.operations & DND.DROP_MOVE) != 0) { - event.detail = DND.DROP_MOVE; - } else if ((event.operations & DND.DROP_COPY) != 0) { - event.detail = DND.DROP_COPY; - } - } - - // We don't support other types than copy and move - if (event.detail != DND.DROP_COPY && event.detail != DND.DROP_MOVE) { - event.detail = DND.DROP_NONE; - } - } - - /* - * The cursor has left the drop target boundaries OR data is about to be dropped. - * {@inheritDoc} - */ - @Override - public void dragLeave(DropTargetEvent event) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "drag leave"); - - // dragLeave is unfortunately called right before data is about to be dropped - // (between the last dropMove and the next dropAccept). That means we can't just - // trash the current DropFeedback from the current view rule, we need to preserve - // it in case a dropAccept happens next. - // See the corresponding kludge in dropAccept(). - mLeaveTargetNode = mTargetNode; - mLeaveFeedback = mFeedback; - mLeaveView = mCurrentView; - - clearDropInfo(); - } - - /* - * The cursor is moving over the drop target. - * {@inheritDoc} - */ - @Override - public void dragOver(DropTargetEvent event) { - processDropEvent(event); - } - - /* - * The drop is about to be performed. - * The drop target is given a last chance to change the nature of the drop. - * {@inheritDoc} - */ - @Override - public void dropAccept(DropTargetEvent event) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "drop accept"); - - checkDataType(event); - - // If we have a valid target node and it matches the one we saved in - // dragLeave then we restore the DropFeedback that we saved in dragLeave. - if (mLeaveTargetNode != null) { - mTargetNode = mLeaveTargetNode; - mFeedback = mLeaveFeedback; - mCurrentView = mLeaveView; - } - - if (mFeedback != null && mFeedback.invalidTarget) { - // The script said we can't drop here. - event.detail = DND.DROP_NONE; - } - - if (mLeaveTargetNode == null || event.detail == DND.DROP_NONE) { - clearDropInfo(); - } - - mLeaveTargetNode = null; - mLeaveFeedback = null; - mLeaveView = null; - } - - /* - * The data is being dropped. - * {@inheritDoc} - */ - @Override - public void drop(final DropTargetEvent event) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "dropped"); - - SimpleElement[] elements = null; - - SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance(); - - if (sxt.isSupportedType(event.currentDataType)) { - if (event.data instanceof SimpleElement[]) { - elements = (SimpleElement[]) event.data; - } - } - - if (elements == null || elements.length < 1) { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "drop missing drop data"); - return; - } - - if (mCurrentDragElements != null && Arrays.equals(elements, mCurrentDragElements)) { - elements = mCurrentDragElements; - } - - if (mTargetNode == null) { - ViewHierarchy viewHierarchy = mCanvas.getViewHierarchy(); - if (viewHierarchy.isValid() && viewHierarchy.isEmpty()) { - // There is no target node because the drop happens on an empty document. - // Attempt to create a root node accordingly. - createDocumentRoot(elements); - } else { - if (DEBUG) AdtPlugin.printErrorToConsole("DEBUG", "dropped on null targetNode"); - } - return; - } - - updateDropFeedback(mFeedback, event); - - final SimpleElement[] elementsFinal = elements; - final LayoutPoint canvasPoint = getDropLocation(event).toLayout(); - String label = computeUndoLabel(mTargetNode, elements, event.detail); - - // Create node listener which (during the drop) listens for node additions - // and stores the list of added node such that they can be selected afterwards. - final List<UiElementNode> added = new ArrayList<UiElementNode>(); - // List of "index within parent" for each node - final List<Integer> indices = new ArrayList<Integer>(); - NodeCreationListener listener = new NodeCreationListener() { - @Override - public void nodeCreated(UiElementNode parent, UiElementNode child, int index) { - if (parent == mTargetNode.getNode()) { - added.add(child); - - // Adjust existing indices - for (int i = 0, n = indices.size(); i < n; i++) { - int idx = indices.get(i); - if (idx >= index) { - indices.set(i, idx + 1); - } - } - - indices.add(index); - } - } - - @Override - public void nodeDeleted(UiElementNode parent, UiElementNode child, int previousIndex) { - if (parent == mTargetNode.getNode()) { - // Adjust existing indices - for (int i = 0, n = indices.size(); i < n; i++) { - int idx = indices.get(i); - if (idx >= previousIndex) { - indices.set(i, idx - 1); - } - } - - // Make sure we aren't removing the same nodes that are being added - // No, that can happen when canceling out of a drop handler such as - // when dropping an included layout, then canceling out of the - // resource chooser. - //assert !added.contains(child); - } - } - }; - - try { - UiElementNode.addNodeCreationListener(listener); - mCanvas.getEditorDelegate().getEditor().wrapUndoEditXmlModel(label, new Runnable() { - @Override - public void run() { - InsertType insertType = getInsertType(event, mTargetNode); - mCanvas.getRulesEngine().callOnDropped(mTargetNode, - elementsFinal, - mFeedback, - new Point(canvasPoint.x, canvasPoint.y), - insertType); - mTargetNode.applyPendingChanges(); - // Clean up drag if applicable - if (event.detail == DND.DROP_MOVE) { - GlobalCanvasDragInfo.getInstance().removeSource(); - } - mTargetNode.applyPendingChanges(); - } - }); - } finally { - UiElementNode.removeNodeCreationListener(listener); - } - - final List<INode> nodes = new ArrayList<INode>(); - NodeFactory nodeFactory = mCanvas.getNodeFactory(); - for (UiElementNode uiNode : added) { - if (uiNode instanceof UiViewElementNode) { - NodeProxy node = nodeFactory.create((UiViewElementNode) uiNode); - if (node != null) { - nodes.add(node); - } - } - } - - // Select the newly dropped nodes: - // Find out which nodes were added, and look up their corresponding - // CanvasViewInfos. - final SelectionManager selectionManager = mCanvas.getSelectionManager(); - // Don't use the indices to search for corresponding nodes yet, since a - // render may not have happened yet and we'd rather use an up to date - // view hierarchy than indices to look up the right view infos. - if (!selectionManager.selectDropped(nodes, null /* indices */)) { - // In some scenarios we can't find the actual view infos yet; this - // seems to happen when you drag from one canvas to another (see the - // related comment next to the setFocus() call below). In that case - // defer selection briefly until the view hierarchy etc is up to - // date. - Display.getDefault().asyncExec(new Runnable() { - @Override - public void run() { - selectionManager.selectDropped(nodes, indices); - } - }); - } - - clearDropInfo(); - mCanvas.redraw(); - // Request focus: This is *necessary* when you are dragging from one canvas editor - // to another, because without it, the redraw does not seem to be processed (the change - // is invisible until you click on the target canvas to give it focus). - mCanvas.setFocus(); - } - - /** - * Returns the right {@link InsertType} to use for the given drop target event and the - * given target node - * - * @param event the drop target event - * @param mTargetNode the node targeted by the drop - * @return the {link InsertType} to use for the drop - */ - public static InsertType getInsertType(DropTargetEvent event, NodeProxy mTargetNode) { - GlobalCanvasDragInfo dragInfo = GlobalCanvasDragInfo.getInstance(); - if (event.detail == DND.DROP_MOVE) { - SelectionItem[] selection = dragInfo.getCurrentSelection(); - if (selection != null) { - for (SelectionItem item : selection) { - if (item.getNode() != null - && item.getNode().getParent() == mTargetNode) { - return InsertType.MOVE_WITHIN; - } - } - } - - return InsertType.MOVE_INTO; - } else if (dragInfo.getSourceCanvas() != null) { - return InsertType.PASTE; - } else { - return InsertType.CREATE; - } - } - - /** - * Computes a suitable Undo label to use for a drop operation, such as - * "Drop Button in LinearLayout" and "Move Widgets in RelativeLayout". - * - * @param targetNode The target of the drop - * @param elements The dragged widgets - * @param detail The DnD mode, as used in {@link DropTargetEvent#detail}. - * @return A string suitable as an undo-label for the drop event - */ - public static String computeUndoLabel(NodeProxy targetNode, - SimpleElement[] elements, int detail) { - // Decide whether it's a move or a copy; we'll label moves specifically - // as a move and consider everything else a "Drop" - String verb = (detail == DND.DROP_MOVE) ? "Move" : "Drop"; - - // Get the type of widget being dropped/moved, IF there is only one. If - // there is more than one, just reference it as "Widgets". - String object; - if (elements != null && elements.length == 1) { - object = getSimpleName(elements[0].getFqcn()); - } else { - object = "Widgets"; - } - - String where = getSimpleName(targetNode.getFqcn()); - - // When we localize this: $1 is the verb (Move or Drop), $2 is the - // object (such as "Button"), and $3 is the place we are doing it (such - // as "LinearLayout"). - return String.format("%1$s %2$s in %3$s", verb, object, where); - } - - /** - * Returns simple name (basename, following last dot) of a fully qualified - * class name. - * - * @param fqcn The fqcn to reduce - * @return The base name of the fqcn - */ - public static String getSimpleName(String fqcn) { - // Note that the following works even when there is no dot, since - // lastIndexOf will return -1 so we get fcqn.substring(-1+1) = - // fcqn.substring(0) = fqcn - return fqcn.substring(fqcn.lastIndexOf('.') + 1); - } - - /** - * Updates the {@link DropFeedback#isCopy} and {@link DropFeedback#sameCanvas} fields - * of the given {@link DropFeedback}. This is generally called right before invoking - * one of the callOnXyz methods of GRE to refresh the fields. - * - * @param df The current {@link DropFeedback}. - * @param event An optional event to determine if the current operation is copy or move. - */ - private void updateDropFeedback(DropFeedback df, DropTargetEvent event) { - if (event != null) { - df.isCopy = event.detail == DND.DROP_COPY; - } - df.sameCanvas = mCanvas == mGlobalDragInfo.getSourceCanvas(); - df.invalidTarget = false; - df.dipScale = mCanvas.getEditorDelegate().getGraphicalEditor().getDipScale(); - df.modifierMask = mCanvas.getGestureManager().getRuleModifierMask(); - - // Set the drag bounds, after converting it from control coordinates to - // layout coordinates - GlobalCanvasDragInfo dragInfo = GlobalCanvasDragInfo.getInstance(); - Rect dragBounds = null; - Rect controlDragBounds = dragInfo.getDragBounds(); - if (controlDragBounds != null) { - CanvasTransform ht = mCanvas.getHorizontalTransform(); - CanvasTransform vt = mCanvas.getVerticalTransform(); - double horizScale = ht.getScale(); - double verticalScale = vt.getScale(); - int x = (int) (controlDragBounds.x / horizScale); - int y = (int) (controlDragBounds.y / verticalScale); - int w = (int) (controlDragBounds.w / horizScale); - int h = (int) (controlDragBounds.h / verticalScale); - dragBounds = new Rect(x, y, w, h); - } - int baseline = dragInfo.getDragBaseline(); - if (baseline != -1) { - df.dragBaseline = baseline; - } - df.dragBounds = dragBounds; - } - - /** - * Verifies that event.currentDataType is of type {@link SimpleXmlTransfer}. - * If not, try to find a valid data type. - * Otherwise set the drop to {@link DND#DROP_NONE} to cancel it. - * - * @return True if the data type is accepted. - */ - private static boolean checkDataType(DropTargetEvent event) { - - SimpleXmlTransfer sxt = SimpleXmlTransfer.getInstance(); - - TransferData current = event.currentDataType; - - if (sxt.isSupportedType(current)) { - return true; - } - - // We only support SimpleXmlTransfer and the current data type is not right. - // Let's see if we can find another one. - - for (TransferData td : event.dataTypes) { - if (td != current && sxt.isSupportedType(td)) { - // We like this type better. - event.currentDataType = td; - return true; - } - } - - // We failed to find any good transfer type. - event.detail = DND.DROP_NONE; - return false; - } - - /** - * Returns the mouse location of the drop target event. - * - * @param event the drop target event - * @return a {@link ControlPoint} location corresponding to the top left corner - */ - private ControlPoint getDropLocation(DropTargetEvent event) { - return ControlPoint.create(mCanvas, event); - } - - /** - * Called on both dragEnter and dragMove. - * Generates the onDropEnter/Move/Leave events depending on the currently - * selected target node. - */ - private void processDropEvent(DropTargetEvent event) { - if (!mCanvas.getViewHierarchy().isValid()) { - // We don't allow drop on an invalid layout, even if we have some obsolete - // layout info for it. - event.detail = DND.DROP_NONE; - clearDropInfo(); - return; - } - - LayoutPoint p = getDropLocation(event).toLayout(); - - // Is the mouse currently captured by a DropFeedback.captureArea? - boolean isCaptured = false; - if (mFeedback != null) { - Rect r = mFeedback.captureArea; - isCaptured = r != null && r.contains(p.x, p.y); - } - - // We can't switch views/nodes when the mouse is captured - CanvasViewInfo vi; - if (isCaptured) { - vi = mCurrentView; - } else { - vi = mCanvas.getViewHierarchy().findViewInfoAt(p); - - // When dragging into the canvas, if you are not over any other view, target - // the root element (since it may not "fill" the screen, e.g. if you have a linear - // layout but have layout_height wrap_content, then the layout will only extend - // to cover the children in the layout, not the whole visible screen area, which - // may be surprising - if (vi == null) { - vi = mCanvas.getViewHierarchy().getRoot(); - } - } - - boolean isMove = true; - boolean needRedraw = false; - - if (vi != mCurrentView) { - // Current view has changed. Does that also change the target node? - // Note that either mCurrentView or vi can be null. - - if (vi == null) { - // vi is null but mCurrentView is not, no view is a target anymore - // We don't need onDropMove in this case - isMove = false; - needRedraw = true; - event.detail = DND.DROP_NONE; - clearDropInfo(); // this will call callDropLeave. - - } else { - // vi is a new current view. - // Query GRE for onDropEnter on the ViewInfo hierarchy, starting from the child - // towards its parent, till we find one that returns a non-null drop feedback. - - DropFeedback df = null; - NodeProxy targetNode = null; - - for (CanvasViewInfo targetVi = vi; - targetVi != null && df == null; - targetVi = targetVi.getParent()) { - targetNode = mCanvas.getNodeFactory().create(targetVi); - df = mCanvas.getRulesEngine().callOnDropEnter(targetNode, - targetVi.getViewObject(), mCurrentDragElements); - - if (df != null) { - // We should also dispatch an onDropMove() call to the initial enter - // position, such that the view is notified of the position where - // we are within the node immediately (before we for example attempt - // to draw feedback). This is necessary since most views perform the - // guideline computations in onDropMove (since only onDropMove is handed - // the -position- of the mouse), and we want this computation to happen - // before we ask the view to draw its feedback. - updateDropFeedback(df, event); - df = mCanvas.getRulesEngine().callOnDropMove(targetNode, - mCurrentDragElements, df, new Point(p.x, p.y)); - } - - if (df != null && - event.detail == DND.DROP_MOVE && - mCanvas == mGlobalDragInfo.getSourceCanvas()) { - // You can't move an object into itself in the same canvas. - // E.g. case of moving a layout and the node under the mouse is the - // layout itself: a copy would be ok but not a move operation of the - // layout into himself. - - SelectionItem[] selection = mGlobalDragInfo.getCurrentSelection(); - if (selection != null) { - for (SelectionItem cs : selection) { - if (cs.getViewInfo() == targetVi) { - // The node that responded is one of the selection roots. - // Simply invalidate the drop feedback and move on the - // parent in the ViewInfo chain. - - updateDropFeedback(df, event); - mCanvas.getRulesEngine().callOnDropLeave( - targetNode, mCurrentDragElements, df); - df = null; - targetNode = null; - } - } - } - } - } - - if (df == null) { - // Provide visual feedback that we are refusing the drop - event.detail = DND.DROP_NONE; - clearDropInfo(); - - } else if (targetNode != mTargetNode) { - // We found a new target node for the drag'n'drop. - // Release the previous one, if any. - callDropLeave(); - - // And assign the new one - mTargetNode = targetNode; - mFeedback = df; - - // We don't need onDropMove in this case - isMove = false; - } - } - - mCurrentView = vi; - } - - if (isMove && mTargetNode != null && mFeedback != null) { - // this is a move inside the same view - com.android.ide.common.api.Point p2 = - new com.android.ide.common.api.Point(p.x, p.y); - updateDropFeedback(mFeedback, event); - DropFeedback df = mCanvas.getRulesEngine().callOnDropMove( - mTargetNode, mCurrentDragElements, mFeedback, p2); - mCanvas.getGestureManager().updateMessage(mFeedback); - - if (df == null) { - // The target is no longer interested in the drop move. - event.detail = DND.DROP_NONE; - callDropLeave(); - - } else if (df != mFeedback) { - mFeedback = df; - } - } - - if (mFeedback != null) { - if (event.detail == DND.DROP_NONE && !mFeedback.invalidTarget) { - // If we previously provided visual feedback that we were refusing - // the drop, we now need to change it to mean we're accepting it. - event.detail = DND.DROP_DEFAULT; - recomputeDragType(event); - - } else if (mFeedback.invalidTarget) { - // Provide visual feedback that we are refusing the drop - event.detail = DND.DROP_NONE; - } - } - - if (needRedraw || (mFeedback != null && mFeedback.requestPaint)) { - mCanvas.redraw(); - } - - // Update outline to show the target node there - OutlinePage outline = mCanvas.getOutlinePage(); - TreeSelection newSelection = TreeSelection.EMPTY; - if (mCurrentView != null && mTargetNode != null) { - // Find the view corresponding to the target node. The current view can be a leaf - // view whereas the target node is always a parent layout. - if (mCurrentView.getUiViewNode() != mTargetNode.getNode()) { - mCurrentView = mCurrentView.getParent(); - } - if (mCurrentView != null && mCurrentView.getUiViewNode() == mTargetNode.getNode()) { - TreePath treePath = SelectionManager.getTreePath(mCurrentView); - newSelection = new TreeSelection(treePath); - } - } - - ISelection currentSelection = outline.getSelection(); - if (currentSelection == null || !currentSelection.equals(newSelection)) { - outline.setSelection(newSelection); - } - } - - /** - * Calls onDropLeave on mTargetNode with the current mFeedback. <br/> - * Then clears mTargetNode and mFeedback. - */ - private void callDropLeave() { - if (mTargetNode != null && mFeedback != null) { - updateDropFeedback(mFeedback, null); - mCanvas.getRulesEngine().callOnDropLeave(mTargetNode, mCurrentDragElements, mFeedback); - } - - mTargetNode = null; - mFeedback = null; - } - - private void clearDropInfo() { - callDropLeave(); - mCurrentView = null; - mCanvas.redraw(); - } - - /** - * Creates a root element in an empty document. - * Only the first element's FQCN of the dragged elements is used. - * <p/> - * Actual XML handling is done by {@link LayoutCanvas#createDocumentRoot(String)}. - */ - private void createDocumentRoot(SimpleElement[] elements) { - if (elements == null || elements.length < 1 || elements[0] == null) { - return; - } - - mCanvas.createDocumentRoot(elements[0]); - } - - /** - * An {@link Overlay} to paint the move feedback. This just delegates to the - * layout rules. - */ - private class MoveOverlay extends Overlay { - @Override - public void paint(GC gc) { - if (mTargetNode != null && mFeedback != null) { - RulesEngine rulesEngine = mCanvas.getRulesEngine(); - rulesEngine.callDropFeedbackPaint(mCanvas.getGcWrapper(), mTargetNode, mFeedback); - mFeedback.requestPaint = false; - } - } - } -} |