aboutsummaryrefslogtreecommitdiff
path: root/eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.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/MoveGesture.java')
-rw-r--r--eclipse/plugins/com.android.ide.eclipse.adt/src/com/android/ide/eclipse/adt/internal/editors/layout/gle2/MoveGesture.java852
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 &amp; 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;
- }
- }
- }
-}