/******************************************************************************* * Copyright (c) 2003, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * ken.ryall@nokia.com - 157506 drop from external sources does not work on Linux/Mac *******************************************************************************/ package org.eclipse.ui.navigator; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.SafeRunner; import org.eclipse.jface.util.LocalSelectionTransfer; import org.eclipse.jface.viewers.StructuredViewer; import org.eclipse.swt.dnd.DND; import org.eclipse.swt.dnd.DropTargetEvent; import org.eclipse.swt.dnd.FileTransfer; import org.eclipse.swt.dnd.Transfer; import org.eclipse.swt.dnd.TransferData; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.widgets.Item; import org.eclipse.ui.internal.navigator.NavigatorSafeRunnable; import org.eclipse.ui.internal.navigator.Policy; import org.eclipse.ui.internal.navigator.dnd.NavigatorPluginDropAction; import org.eclipse.ui.part.PluginDropAdapter; import org.eclipse.ui.part.PluginTransfer; /** * Provides an implementation of {@link PluginDropAdapter} which uses the * extensions provided by the associated {@link INavigatorContentService}. * * <p> * Clients should not need to create an instance of this class unless they are * creating their own custom viewer. Otherwise, {@link CommonViewer} configures * its drop adapter automatically. * </p> * * * @see INavigatorDnDService * @see CommonDragAdapter * @see CommonDragAdapterAssistant * @see CommonDropAdapterAssistant * @see CommonViewer * @since 3.2 */ public final class CommonDropAdapter extends PluginDropAdapter { private static final Transfer[] SUPPORTED_DROP_TRANSFERS = new Transfer[] { LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance(), PluginTransfer.getInstance() }; private final INavigatorContentService contentService; private final INavigatorDnDService dndService; /** * Create a DropAdapter that handles a drop based on the given content * service and selection provider. * * @param aContentService * The content service this Drop Adapter is associated with * @param aStructuredViewer * The viewer this DropAdapter is associated with. */ public CommonDropAdapter(INavigatorContentService aContentService, StructuredViewer aStructuredViewer) { super(aStructuredViewer); contentService = aContentService; dndService = contentService.getDnDService(); setFeedbackEnabled(false); } /** * * @return An array of Transfers allowed by the CommonDropAdapter. Includes * {@link LocalSelectionTransfer#getTransfer()}, * {@link FileTransfer#getInstance()}, * {@link PluginTransfer#getInstance()}. * @see LocalSelectionTransfer * @see FileTransfer * @see PluginTransfer */ public Transfer[] getSupportedDropTransfers() { return SUPPORTED_DROP_TRANSFERS; } @Override public void dragEnter(DropTargetEvent event) { if (event.detail == DND.DROP_NONE) return; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.dragEnter: " + event); //$NON-NLS-1$ } for (TransferData dataType : event.dataTypes) { if (LocalSelectionTransfer.getTransfer().isSupportedType(dataType)) { event.currentDataType = dataType; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.dragEnter: local selection: " + event.currentDataType); //$NON-NLS-1$ } super.dragEnter(event); return; } } for (TransferData dataType : event.dataTypes) { if (FileTransfer.getInstance().isSupportedType(dataType)) { event.currentDataType = dataType; event.detail = DND.DROP_COPY; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.dragEnter: file: " + event.currentDataType); //$NON-NLS-1$ } super.dragEnter(event); return; } } for (TransferData dataType : event.dataTypes) { if (PluginTransfer.getInstance().isSupportedType(dataType)) { event.currentDataType = dataType; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.dragEnter: plugin: " + event.currentDataType); //$NON-NLS-1$ } super.dragEnter(event); return; } } event.detail = DND.DROP_NONE; } @Override public void dragLeave(DropTargetEvent event) { super.dragLeave(event); if (LocalSelectionTransfer.getTransfer().isSupportedType( event.currentDataType)) { event.data = NavigatorPluginDropAction .createTransferData(contentService); } } @Override public boolean performDrop(Object data) { final DropTargetEvent event = getCurrentEvent(); if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.drop (begin): " + event); //$NON-NLS-1$ } final Object target = getCurrentTarget() != null ? getCurrentTarget() : getViewer().getInput(); // Must validate the drop here because on some platforms (Linux, Mac) the event // is not populated with the correct currentDataType until the drop actually // happens, and validateDrop sets the currentTransfer based on that. The // call to validateDrop in dragAccept is too early. validateDrop(target, getCurrentOperation(), event.currentDataType); if (PluginTransfer.getInstance().isSupportedType(event.currentDataType)) { super.drop(event); return true; } if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.drop target: " + target + " op: " + getCurrentOperation()); //$NON-NLS-1$ //$NON-NLS-2$ } final CommonDropAdapterAssistant[] assistants = dndService.findCommonDropAdapterAssistants(target, getCurrentTransfer()); final boolean[] retValue = new boolean[1]; for (final CommonDropAdapterAssistant localAssistant : assistants) { SafeRunner.run(new NavigatorSafeRunnable() { @Override public void run() throws Exception { localAssistant.setCurrentEvent(event); IStatus valid = localAssistant.validateDrop(target, getCurrentOperation(), getCurrentTransfer()); if (valid != null && valid.isOK()) { if (Policy.DEBUG_DND) { System.out .println("CommonDropAdapter.drop assistant selected: " + localAssistant + " op: " + event.detail); //$NON-NLS-1$ //$NON-NLS-2$ } localAssistant.handleDrop(CommonDropAdapter.this, event, target); retValue[0] = true; } } }); if (retValue[0]) return true; } return false; } @Override public boolean validateDrop(final Object aDropTarget, final int theDropOperation, final TransferData theTransferData) { if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.validateDrop (begin) operation: " + theDropOperation + " target: " + aDropTarget /*+ " transferType: " + theTransferData.type*/); //$NON-NLS-1$ //$NON-NLS-2$ //new Exception().printStackTrace(System.out); } boolean result = false; final IStatus[] valid = new IStatus[1]; if (super.validateDrop(aDropTarget, theDropOperation, theTransferData)) { result = true; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.validateDrop valid for plugin transfer"); //$NON-NLS-1$ } } else { final Object target = aDropTarget != null ? aDropTarget : getViewer().getInput(); if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.validateDrop target: " + target); //$NON-NLS-1$ System.out.println("CommonDropAdapter.validateDrop local selection: " + //$NON-NLS-1$ LocalSelectionTransfer.getTransfer().getSelection()); } CommonDropAdapterAssistant[] assistants = dndService.findCommonDropAdapterAssistants( target, theTransferData); for (final CommonDropAdapterAssistant assistantLocal : assistants) { if (Policy.DEBUG_DND) { System.out .println("CommonDropAdapter.validateDrop checking assistant: \"" + assistantLocal); //$NON-NLS-1$ } SafeRunner.run(new NavigatorSafeRunnable() { @Override public void run() throws Exception { assistantLocal.setCurrentEvent(getCurrentEvent()); valid[0] = assistantLocal.validateDrop(target, theDropOperation, theTransferData); } }); if (valid[0] != null && valid[0].isOK()) { result = true; if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.validateDrop VALID"); //$NON-NLS-1$ } break; } if (Policy.DEBUG_DND) { System.out .println("CommonDropAdapter.validateDrop NOT valid: " + (valid[0] != null ? (valid[0].getSeverity() + ": " + valid[0].getMessage()) : "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ } } } if (Policy.DEBUG_DND) { System.out .println("CommonDropAdapter.validateDrop (returning " + (valid[0] != null ? valid[0].getSeverity() + ": " + valid[0].getMessage() : "" + result) + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ } setScrollExpandEnabled(true); return result; } /* * The visibility of the following methods is raised for downstream clients * (assistants). */ @Override public Rectangle getBounds(Item item) { return super.getBounds(item); } @Override public int getCurrentLocation() { return super.getCurrentLocation(); } @Override public int getCurrentOperation() { return super.getCurrentOperation(); } /** * @see org.eclipse.jface.viewers.ViewerDropAdapter#overrideOperation(int) * @since 3.4 */ @Override public void overrideOperation(int operation) { if (Policy.DEBUG_DND) { System.out.println("CommonDropAdapter.overrideOperation: " + operation); //$NON-NLS-1$ } super.overrideOperation(operation); } @Override public Object getCurrentTarget() { return super.getCurrentTarget(); } @Override public TransferData getCurrentTransfer() { return super.getCurrentTransfer(); } }