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

org.eclipse.jface.util.DelegatingDropAdapter Maven / Gradle / Ivy

The newest version!
/*******************************************************************************
 * Copyright (c) 2000, 2015 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.util;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.DropTargetListener;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.dnd.TransferData;

/**
 * A DelegatingDropAdapter is a DropTargetListener
 * that maintains and delegates to a set of {@link TransferDropTargetListener}s.
 * Each TransferDropTargetListener can then be implemented as if it
 * were the DropTarget's only DropTargetListener.
 * 

* On dragEnter, dragOperationChanged, * dragOver and drop, a current listener is * obtained from the set of all TransferDropTargetListeners. The * current listener is the first listener to return true for * {@link TransferDropTargetListener#isEnabled(DropTargetEvent)}. The current * listener is forwarded all DropTargetEvents until some other * listener becomes the current listener, or the drop terminates. *

*

* After adding all TransferDropTargetListeners to the * DelegatingDropAdapter the combined set of Transfers * should be set in the SWT DropTarget. * #getTransfers() provides the set of Transfer types * of all TransferDropTargetListeners. *

*

* The following example snippet shows a DelegatingDropAdapter with * two TransferDropTargetListeners. One supports dropping resources * and demonstrates how a listener can be disabled in the isEnabled method. The * other listener supports text transfer. *

* *
 * 
 *		final TreeViewer viewer = new TreeViewer(shell, SWT.NONE);
 * 		DelegatingDropAdapter dropAdapter = new DelegatingDropAdapter();
 *		dropAdapter.addDropTargetListener(new TransferDropTargetListener() {
 *			public Transfer getTransfer() {
 *				return ResourceTransfer.getInstance();
 *			}
 *			public boolean isEnabled(DropTargetEvent event) {
 *				// disable drop listener if there is no viewer selection
 *				if (viewer.getSelection().isEmpty())
 *					return false;
 *				return true;
 *			}
 *			public void dragEnter(DropTargetEvent event) {}
 *			public void dragLeave(DropTargetEvent event) {}
 *			public void dragOperationChanged(DropTargetEvent event) {}
 *			public void dragOver(DropTargetEvent event) {}
 *			public void drop(DropTargetEvent event) {
 *				if (event.data == null)
 *					return;
 *				IResource[] resources = (IResource[]) event.data;
 *				if (event.detail == DND.DROP_COPY) {
 *					// copy resources
 *				} else {
 *					// move resources
 *				}
 *
 *			}
 *			public void dropAccept(DropTargetEvent event) {}
 *		});
 *		dropAdapter.addDropTargetListener(new TransferDropTargetListener() {
 *			public Transfer getTransfer() {
 *				return TextTransfer.getInstance();
 *			}
 *			public boolean isEnabled(DropTargetEvent event) {
 *				return true;
 *			}
 *			public void dragEnter(DropTargetEvent event) {}
 *			public void dragLeave(DropTargetEvent event) {}
 *			public void dragOperationChanged(DropTargetEvent event) {}
 *			public void dragOver(DropTargetEvent event) {}
 *			public void drop(DropTargetEvent event) {
 *				if (event.data == null)
 *					return;
 *				System.out.println(event.data);
 *			}
 *			public void dropAccept(DropTargetEvent event) {}
 *		});
 *		viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, dropAdapter.getTransfers(), dropAdapter);
 * 
 * 
* * @since 3.0 */ public class DelegatingDropAdapter implements DropTargetListener { private List listeners = new ArrayList<>(); private TransferDropTargetListener currentListener; private int originalDropType; /** * Adds the given TransferDropTargetListener. * * @param listener the new listener */ public void addDropTargetListener(TransferDropTargetListener listener) { listeners.add(listener); } /** * The cursor has entered the drop target boundaries. The current listener is * updated, and #dragEnter() is forwarded to the current listener. * * @param event the drop target event * @see DropTargetListener#dragEnter(DropTargetEvent) */ @Override public void dragEnter(DropTargetEvent event) { // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Drag Enter: " + toString()); //$NON-NLS-1$ originalDropType = event.detail; updateCurrentListener(event); } /** * The cursor has left the drop target boundaries. The event is forwarded to the * current listener. * * @param event the drop target event * @see DropTargetListener#dragLeave(DropTargetEvent) */ @Override public void dragLeave(final DropTargetEvent event) { // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Drag Leave: " + toString()); //$NON-NLS-1$ setCurrentListener(null, event); } /** * The operation being performed has changed (usually due to the user changing * a drag modifier key while dragging). Updates the current listener and forwards * this event to that listener. * * @param event the drop target event * @see DropTargetListener#dragOperationChanged(DropTargetEvent) */ @Override public void dragOperationChanged(final DropTargetEvent event) { // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Drag Operation Changed to: " + event.detail); //$NON-NLS-1$ originalDropType = event.detail; TransferDropTargetListener oldListener = getCurrentListener(); updateCurrentListener(event); final TransferDropTargetListener newListener = getCurrentListener(); // only notify the current listener if it hasn't changed based on the // operation change. otherwise the new listener would get a dragEnter // followed by a dragOperationChanged with the exact same event. if (newListener != null && newListener == oldListener) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { newListener.dragOperationChanged(event); } }); } } /** * The cursor is moving over the drop target. Updates the current listener and * forwards this event to that listener. If no listener can handle the drag * operation the event.detail field is set to DND.DROP_NONE * to indicate an invalid drop. * * @param event the drop target event * @see DropTargetListener#dragOver(DropTargetEvent) */ @Override public void dragOver(final DropTargetEvent event) { TransferDropTargetListener oldListener = getCurrentListener(); updateCurrentListener(event); final TransferDropTargetListener newListener = getCurrentListener(); // only notify the current listener if it hasn't changed based on the // drag over. otherwise the new listener would get a dragEnter // followed by a dragOver with the exact same event. if (newListener != null && newListener == oldListener) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { newListener.dragOver(event); } }); } } /** * Forwards this event to the current listener, if there is one. Sets the * current listener to null afterwards. * * @param event the drop target event * @see DropTargetListener#drop(DropTargetEvent) */ @Override public void drop(final DropTargetEvent event) { // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Drop: " + toString()); //$NON-NLS-1$ updateCurrentListener(event); if (getCurrentListener() != null) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { getCurrentListener().drop(event); } }); } setCurrentListener(null, event); } /** * Forwards this event to the current listener if there is one. * * @param event the drop target event * @see DropTargetListener#dropAccept(DropTargetEvent) */ @Override public void dropAccept(final DropTargetEvent event) { // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Drop Accept: " + toString()); //$NON-NLS-1$ if (getCurrentListener() != null) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { getCurrentListener().dropAccept(event); } }); } } /** * Returns the listener which currently handles drop events. * * @return the TransferDropTargetListener which currently * handles drop events. */ private TransferDropTargetListener getCurrentListener() { return currentListener; } /** * Returns the transfer data type supported by the given listener. * Returns null if the listener does not support any of the * specified data types. * * @param dataTypes available data types * @param listener TransferDropTargetListener to use for testing * supported data types. * @return the transfer data type supported by the given listener or * null. */ private TransferData getSupportedTransferType(TransferData[] dataTypes, TransferDropTargetListener listener) { for (TransferData dataType : dataTypes) { if (listener.getTransfer().isSupportedType(dataType)) { return dataType; } } return null; } /** * Returns the combined set of Transfer types of all * TransferDropTargetListeners. * * @return the combined set of Transfer types */ public Transfer[] getTransfers() { Transfer[] types = new Transfer[listeners.size()]; for (int i = 0; i < listeners.size(); i++) { TransferDropTargetListener listener = listeners .get(i); types[i] = listener.getTransfer(); } return types; } /** * Returns true if there are no listeners to delegate events to. * * @return true if there are no TransferDropTargetListeners * false otherwise */ public boolean isEmpty() { return listeners.isEmpty(); } /** * Removes the given TransferDropTargetListener. * Listeners should not be removed while a drag and drop operation is in progress. * * @param listener the listener to remove */ public void removeDropTargetListener(TransferDropTargetListener listener) { if (currentListener == listener) { currentListener = null; } listeners.remove(listener); } /** * Sets the current listener to listener. Sends the given * DropTargetEvent if the current listener changes. * * @return true if the new listener is different than the previous * false otherwise */ private boolean setCurrentListener(TransferDropTargetListener listener, final DropTargetEvent event) { if (currentListener == listener) { return false; } if (currentListener != null) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { currentListener.dragLeave(event); } }); } currentListener = listener; // if (Policy.DEBUG_DRAG_DROP) // System.out.println("Current drop listener: " + listener); //$NON-NLS-1$ if (currentListener != null) { SafeRunnable.run(new SafeRunnable() { @Override public void run() throws Exception { currentListener.dragEnter(event); } }); } return true; } /** * Updates the current listener to one that can handle the drop. There can be many * listeners and each listener may be able to handle many TransferData * types. The first listener found that can handle a drop of one of the given * TransferData types will be selected. * If no listener can handle the drag operation the event.detail field * is set to DND.DROP_NONE to indicate an invalid drop. * * @param event the drop target event */ private void updateCurrentListener(DropTargetEvent event) { int originalDetail = event.detail; // revert the detail to the "original" drop type that the User indicated. // this is necessary because the previous listener may have changed the detail // to something other than what the user indicated. event.detail = originalDropType; Iterator iter = listeners.iterator(); while (iter.hasNext()) { TransferDropTargetListener listener = iter .next(); TransferData dataType = getSupportedTransferType(event.dataTypes, listener); if (dataType != null) { TransferData originalDataType = event.currentDataType; // set the data type supported by the drop listener event.currentDataType = dataType; if (listener.isEnabled(event)) { // if the listener stays the same, set its previously determined // event detail if (!setCurrentListener(listener, event)) { event.detail = originalDetail; } return; } event.currentDataType = originalDataType; } } setCurrentListener(null, event); event.detail = DND.DROP_NONE; // -always- ensure that expand/scroll are on...otherwise // if a valid drop target is a child of an invalid one // you can't get there... event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy