All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.eclipse.jface.viewers.ViewerDropAdapter Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2000, 2019 IBM Corporation and others.
 *
 * This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License 2.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/legal/epl-2.0/
 *
 * SPDX-License-Identifier: EPL-2.0
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *******************************************************************************/
package org.eclipse.jface.viewers;

import org.eclipse.core.runtime.Assert;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.Rectangle;
import org.eclipse.swt.widgets.Item;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.swt.widgets.TreeItem;

/**
 * This adapter class provides generic drag-and-drop support for a viewer.
 * 

* Subclasses must implement the following methods: *

*
    *
  • validateDrop - identifies valid drop targets in viewer
  • *
  • performDrop - carries out a drop into a viewer
  • *
* The setFeedbackEnabled method can be called to turn on and off * visual insertion feedback (on by default). */ public abstract class ViewerDropAdapter extends DropTargetAdapter { /** * Constant describing the position of the cursor relative * to the target object. This means the mouse is positioned * slightly before the target. * @see #getCurrentLocation() */ public static final int LOCATION_BEFORE = 1; /** * Constant describing the position of the cursor relative * to the target object. This means the mouse is positioned * slightly after the target. * @see #getCurrentLocation() */ public static final int LOCATION_AFTER = 2; /** * Constant describing the position of the cursor relative * to the target object. This means the mouse is positioned * directly on the target. * @see #getCurrentLocation() */ public static final int LOCATION_ON = 3; /** * Constant describing the position of the cursor relative * to the target object. This means the mouse is not positioned * over or near any valid target. * @see #getCurrentLocation() */ public static final int LOCATION_NONE = 4; /** * The viewer to which this drop support has been added. */ private Viewer viewer; /** * The current operation. */ private int currentOperation = DND.DROP_NONE; /** * The last valid operation. We need to remember the last good operation * in the case where the current operation temporarily is not valid (drag over * someplace you can't drop). */ private int lastValidOperation; /** * This is used because we allow the operation * to be temporarily overridden (for example a move to a copy) for a drop that * happens immediately after the operation is overridden. */ private int overrideOperation = -1; /** * The current DropTargetEvent, used only during validateDrop() */ private DropTargetEvent currentEvent; /** * The data item currently under the mouse. */ private Object currentTarget; /** * Information about the position of the mouse relative to the * target (before, on, or after the target. Location is one of * the LOCATION_* constants defined in this type. */ private int currentLocation; /** * A flag that allows adapter users to turn the insertion * feedback on or off. Default is true. */ private boolean feedbackEnabled = true; /** * A flag that allows adapter users to turn auto scrolling * on or off. Default is true. */ private boolean scrollEnabled = true; /** * A flag that allows adapter users to turn auto * expanding on or off. Default is true. */ private boolean expandEnabled = true; /** * A flag that allows adapter users to turn selection feedback * on or off. Default is true. */ private boolean selectFeedbackEnabled = true; /** * Creates a new drop adapter for the given viewer. * * @param viewer the viewer */ protected ViewerDropAdapter(Viewer viewer) { this.viewer = viewer; } /** * Clears internal state of this drop adapter. This method can be called * when no DnD operation is underway, to clear internal state from previous * drop operations. * * @since 3.5 */ protected void clearState() { this.currentTarget = null; this.lastValidOperation = DND.DROP_NONE; this.overrideOperation = -1; } /** * Returns the position of the given event's coordinates relative to its target. * The position is determined to be before, after, or on the item, based on * some threshold value. * * @param event the event * @return one of the LOCATION_* constants defined in this class */ protected int determineLocation(DropTargetEvent event) { if (!(event.item instanceof Item)) { return LOCATION_NONE; } Item item = (Item) event.item; Point coordinates = new Point(event.x, event.y); coordinates = viewer.getControl().toControl(coordinates); Rectangle bounds = getBounds(item); if (bounds == null) { return LOCATION_NONE; } if ((coordinates.y - bounds.y) < getThreshold()) { return LOCATION_BEFORE; } if ((bounds.y + bounds.height - coordinates.y) < getThreshold()) { return LOCATION_AFTER; } return LOCATION_ON; } /** * Get the threshold to determine whether to have before/after feedback or * select feedback. Threshold shall not be bigger than itemHeight/2. * * @return amount of pixels from top/bottom of element that trigger before/after * behavior. * @since 3.16 */ protected int getThreshold() { // fixed default threshold provided up to v3.16 return 5; } /** * Returns the target item of the given drop event. * * @param event the event * @return The target of the drop, may be null. */ protected Object determineTarget(DropTargetEvent event) { return event.item == null ? null : event.item.getData(); } private void doDropValidation(DropTargetEvent event) { //always remember what was previously requested, but not if it //was overridden if (event.detail != DND.DROP_NONE && overrideOperation == -1) lastValidOperation = event.detail; currentOperation = lastValidOperation; currentEvent = event; overrideOperation = -1; if (!validateDrop(currentTarget, currentOperation, event.currentDataType)) { currentOperation = DND.DROP_NONE; } //give the right feedback for the override if (overrideOperation != -1) event.detail = overrideOperation; else event.detail = currentOperation; currentEvent = null; } @Override public void dragEnter(DropTargetEvent event) { clearState(); // should this be removed and better be done in client code? currentTarget = determineTarget(event); doDropValidation(event); } @Override public void dragOperationChanged(DropTargetEvent event) { currentTarget = determineTarget(event); doDropValidation(event); } @Override public void dragOver(DropTargetEvent event) { //use newly revealed item as target if scrolling occurs Object target = determineTarget(event); //set the location feedback int oldLocation = currentLocation; currentLocation = determineLocation(event); setFeedback(event, currentLocation); //see if anything has really changed before doing validation. if (target != currentTarget || currentLocation != oldLocation) { currentTarget = target; doDropValidation(event); } } @Override public void drop(DropTargetEvent event) { currentLocation = determineLocation(event); currentEvent = event; if (overrideOperation != -1) currentOperation = overrideOperation; //perform the drop behavior if (!performDrop(event.data)) { event.detail = DND.DROP_NONE; } //reset for next time currentOperation = DND.DROP_NONE; currentEvent = null; } @Override public void dropAccept(DropTargetEvent event) { currentEvent = event; if (!validateDrop(currentTarget, event.detail, event.currentDataType)) { currentOperation = event.detail = DND.DROP_NONE; } currentEvent = null; } /** * Returns the bounds of the given SWT tree or table item. * * @param item the SWT Item * @return the bounds, or null if it is not a known type of item */ protected Rectangle getBounds(Item item) { if (item instanceof TreeItem) { return ((TreeItem) item).getBounds(); } if (item instanceof TableItem) { return ((TableItem) item).getBounds(0); } return null; } /** * Returns a constant describing the position of the mouse relative to the * target (before, on, or after the target. * * @return one of the LOCATION_* constants defined in this type */ protected int getCurrentLocation() { return currentLocation; } /** * Returns the current operation. * * @return a DROP_* constant from class DND * * @see DND#DROP_COPY * @see DND#DROP_MOVE * @see DND#DROP_LINK * @see DND#DROP_NONE */ protected int getCurrentOperation() { return currentOperation; } /** * Returns the target object currently under the mouse. * * @return the current target object */ protected Object getCurrentTarget() { return currentTarget; } /** * Returns the current {@link DropTargetEvent}. * * This may be called only inside of the {@link #validateDrop(Object, int, TransferData)} * or {@link #performDrop(Object)} methods. * @return the DropTargetEvent * @since 3.5 */ protected DropTargetEvent getCurrentEvent() { Assert.isTrue(currentEvent != null); return currentEvent; } /** * Returns whether visible insertion feedback should be presented to the user. *

* Typical insertion feedback is the horizontal insertion bars that appear * between adjacent items while dragging. *

* * @return true if visual feedback is desired, and false if not */ public boolean getFeedbackEnabled() { return feedbackEnabled; } /** * Returns the object currently selected by the viewer. * * @return the selected object or the first element in current selection, * and null if no objects are selected */ protected Object getSelectedObject() { ISelection selection = viewer.getSelection(); if (selection instanceof IStructuredSelection && !selection.isEmpty()) { IStructuredSelection structured = (IStructuredSelection) selection; return structured.getFirstElement(); } return null; } /** * @return the viewer to which this drop support has been added. */ protected Viewer getViewer() { return viewer; } /** * @deprecated this method should not be used. Exception handling has been * removed from DropTargetAdapter methods overridden by this class. * Handles any exception that occurs during callback, including * rethrowing behavior. *

* [Issue: Implementation prints stack trace and eats exception to avoid * crashing VA/J. * Consider conditionalizing the implementation to do one thing in VAJ * and something more reasonable in other operating environments. * ] *

* * @param exception the exception * @param event the event */ @Deprecated protected void handleException(Throwable exception, DropTargetEvent event) { // Currently we never rethrow because VA/Java crashes if an SWT // callback throws anything. Generally catching Throwable is bad, but in // this cases it's better than hanging the image. exception.printStackTrace(); event.detail = DND.DROP_NONE; } /** * Performs any work associated with the drop. *

* Subclasses must implement this method to provide drop behavior. *

* * @param data the drop data * @return true if the drop was successful, and * false otherwise */ public abstract boolean performDrop(Object data); /** * Overrides the current operation for a drop that happens immediately * after the current validateDrop. * * This maybe called only from within a * {@link #validateDrop(Object, int, TransferData)} method * * * @param operation * the operation to be used for the drop. * * @see DND#DROP_COPY * @see DND#DROP_MOVE * @see DND#DROP_LINK * @see DND#DROP_NONE * * @since 3.5 */ protected void overrideOperation(int operation) { overrideOperation = operation; } private void setFeedback(DropTargetEvent event, int location) { if (feedbackEnabled) { switch (location) { case LOCATION_BEFORE: event.feedback = DND.FEEDBACK_INSERT_BEFORE; break; case LOCATION_AFTER: event.feedback = DND.FEEDBACK_INSERT_AFTER; break; case LOCATION_ON: default: event.feedback = DND.FEEDBACK_SELECT; break; } } // Explicitly inhibit SELECT feedback if desired if (!selectFeedbackEnabled) { event.feedback &= ~DND.FEEDBACK_SELECT; } if (expandEnabled) { event.feedback |= DND.FEEDBACK_EXPAND; } if (scrollEnabled) { event.feedback |= DND.FEEDBACK_SCROLL; } } /** * Sets whether visible insertion feedback should be presented to the user. *

* Typical insertion feedback is the horizontal insertion bars that appear * between adjacent items while dragging. *

* * @param value * true if visual feedback is desired, and * false if not */ public void setFeedbackEnabled(boolean value) { feedbackEnabled = value; } /** * Sets whether selection feedback should be provided during dragging. * * @param value true if selection feedback is desired, and * false if not * * @since 3.2 */ public void setSelectionFeedbackEnabled(boolean value) { selectFeedbackEnabled = value; } /** * Sets whether auto scrolling and expanding should be provided during dragging. * * @param value true if scrolling and expanding is desired, and * false if not * @since 2.0 */ public void setScrollExpandEnabled(boolean value) { expandEnabled = value; scrollEnabled = value; } /** * Sets whether auto expanding should be provided during dragging. * * @param value true if expanding is desired, and * false if not * @since 3.4 */ public void setExpandEnabled(boolean value) { expandEnabled = value; } /** * Sets whether auto scrolling should be provided during dragging. * * @param value true if scrolling is desired, and * false if not * @since 3.4 */ public void setScrollEnabled(boolean value) { scrollEnabled = value; } /** * Validates dropping on the given object. This method is called whenever some * aspect of the drop operation changes. *

* Subclasses must implement this method to define which drops make sense. *

* * @param target the object that the mouse is currently hovering over, or * null if the mouse is hovering over empty space * @param operation the current drag operation (copy, move, etc.) * @param transferType the current transfer type * @return true if the drop is valid, and false * otherwise */ public abstract boolean validateDrop(Object target, int operation, TransferData transferType); }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy