1 /******************************************************************************* 2 * Copyright (c) 2003, 2015 IBM Corporation and others. 3 * 4 * This program and the accompanying materials 5 * are made available under the terms of the Eclipse Public License 2.0 6 * which accompanies this distribution, and is available at 7 * https://www.eclipse.org/legal/epl-2.0/ 8 * 9 * SPDX-License-Identifier: EPL-2.0 10 * 11 * Contributors: 12 * IBM Corporation - initial API and implementation 13 * ken.ryall@nokia.com - 157506 drop from external sources does not work on Linux/Mac 14 *******************************************************************************/ 15 package org.eclipse.ui.navigator; 16 17 import org.eclipse.core.runtime.IStatus; 18 import org.eclipse.core.runtime.SafeRunner; 19 import org.eclipse.jface.util.LocalSelectionTransfer; 20 import org.eclipse.jface.viewers.StructuredViewer; 21 import org.eclipse.swt.dnd.DND; 22 import org.eclipse.swt.dnd.DropTargetEvent; 23 import org.eclipse.swt.dnd.FileTransfer; 24 import org.eclipse.swt.dnd.Transfer; 25 import org.eclipse.swt.dnd.TransferData; 26 import org.eclipse.swt.graphics.Rectangle; 27 import org.eclipse.swt.widgets.Item; 28 import org.eclipse.ui.internal.navigator.NavigatorSafeRunnable; 29 import org.eclipse.ui.internal.navigator.Policy; 30 import org.eclipse.ui.internal.navigator.dnd.NavigatorPluginDropAction; 31 import org.eclipse.ui.part.PluginDropAdapter; 32 import org.eclipse.ui.part.PluginTransfer; 33 34 /** 35 * Provides an implementation of {@link PluginDropAdapter} which uses the 36 * extensions provided by the associated {@link INavigatorContentService}. 37 * 38 * <p> 39 * Clients should not need to create an instance of this class unless they are 40 * creating their own custom viewer. Otherwise, {@link CommonViewer} configures 41 * its drop adapter automatically. 42 * </p> 43 * 44 * 45 * @see INavigatorDnDService 46 * @see CommonDragAdapter 47 * @see CommonDragAdapterAssistant 48 * @see CommonDropAdapterAssistant 49 * @see CommonViewer 50 * @since 3.2 51 */ 52 public final class CommonDropAdapter extends PluginDropAdapter { 53 54 private static final Transfer[] SUPPORTED_DROP_TRANSFERS = new Transfer[] { 55 LocalSelectionTransfer.getTransfer(), FileTransfer.getInstance(), 56 PluginTransfer.getInstance() }; 57 58 private final INavigatorContentService contentService; 59 60 private final INavigatorDnDService dndService; 61 62 /** 63 * Create a DropAdapter that handles a drop based on the given content 64 * service and selection provider. 65 * 66 * @param aContentService 67 * The content service this Drop Adapter is associated with 68 * @param aStructuredViewer 69 * The viewer this DropAdapter is associated with. 70 */ CommonDropAdapter(INavigatorContentService aContentService, StructuredViewer aStructuredViewer)71 public CommonDropAdapter(INavigatorContentService aContentService, 72 StructuredViewer aStructuredViewer) { 73 super(aStructuredViewer); 74 contentService = aContentService; 75 dndService = contentService.getDnDService(); 76 setFeedbackEnabled(false); 77 } 78 79 /** 80 * 81 * @return An array of Transfers allowed by the CommonDropAdapter. Includes 82 * {@link LocalSelectionTransfer#getTransfer()}, 83 * {@link FileTransfer#getInstance()}, 84 * {@link PluginTransfer#getInstance()}. 85 * @see LocalSelectionTransfer 86 * @see FileTransfer 87 * @see PluginTransfer 88 */ getSupportedDropTransfers()89 public Transfer[] getSupportedDropTransfers() { 90 return SUPPORTED_DROP_TRANSFERS; 91 } 92 93 @Override dragEnter(DropTargetEvent event)94 public void dragEnter(DropTargetEvent event) { 95 96 if (event.detail == DND.DROP_NONE) 97 return; 98 99 if (Policy.DEBUG_DND) { 100 System.out.println("CommonDropAdapter.dragEnter: " + event); //$NON-NLS-1$ 101 } 102 for (TransferData dataType : event.dataTypes) { 103 if (LocalSelectionTransfer.getTransfer().isSupportedType(dataType)) { 104 event.currentDataType = dataType; 105 if (Policy.DEBUG_DND) { 106 System.out.println("CommonDropAdapter.dragEnter: local selection: " + event.currentDataType); //$NON-NLS-1$ 107 } 108 super.dragEnter(event); 109 return; 110 } 111 } 112 113 for (TransferData dataType : event.dataTypes) { 114 if (FileTransfer.getInstance().isSupportedType(dataType)) { 115 event.currentDataType = dataType; 116 event.detail = DND.DROP_COPY; 117 if (Policy.DEBUG_DND) { 118 System.out.println("CommonDropAdapter.dragEnter: file: " + event.currentDataType); //$NON-NLS-1$ 119 } 120 super.dragEnter(event); 121 return; 122 } 123 } 124 125 for (TransferData dataType : event.dataTypes) { 126 if (PluginTransfer.getInstance().isSupportedType(dataType)) { 127 event.currentDataType = dataType; 128 if (Policy.DEBUG_DND) { 129 System.out.println("CommonDropAdapter.dragEnter: plugin: " + event.currentDataType); //$NON-NLS-1$ 130 } 131 super.dragEnter(event); 132 return; 133 } 134 } 135 136 event.detail = DND.DROP_NONE; 137 138 } 139 140 @Override dragLeave(DropTargetEvent event)141 public void dragLeave(DropTargetEvent event) { 142 super.dragLeave(event); 143 if (LocalSelectionTransfer.getTransfer().isSupportedType( 144 event.currentDataType)) { 145 event.data = NavigatorPluginDropAction 146 .createTransferData(contentService); 147 } 148 } 149 150 @Override performDrop(Object data)151 public boolean performDrop(Object data) { 152 final DropTargetEvent event = getCurrentEvent(); 153 if (Policy.DEBUG_DND) { 154 System.out.println("CommonDropAdapter.drop (begin): " + event); //$NON-NLS-1$ 155 } 156 final Object target = getCurrentTarget() != null ? 157 getCurrentTarget() : getViewer().getInput(); 158 159 // Must validate the drop here because on some platforms (Linux, Mac) the event 160 // is not populated with the correct currentDataType until the drop actually 161 // happens, and validateDrop sets the currentTransfer based on that. The 162 // call to validateDrop in dragAccept is too early. 163 validateDrop(target, getCurrentOperation(), event.currentDataType); 164 if (PluginTransfer.getInstance().isSupportedType(event.currentDataType)) { 165 super.drop(event); 166 return true; 167 } 168 169 if (Policy.DEBUG_DND) { 170 System.out.println("CommonDropAdapter.drop target: " + target + " op: " + getCurrentOperation()); //$NON-NLS-1$ //$NON-NLS-2$ 171 } 172 final CommonDropAdapterAssistant[] assistants = dndService.findCommonDropAdapterAssistants(target, 173 getCurrentTransfer()); 174 175 final boolean[] retValue = new boolean[1]; 176 for (final CommonDropAdapterAssistant localAssistant : assistants) { 177 SafeRunner.run(new NavigatorSafeRunnable() { 178 @Override 179 public void run() throws Exception { 180 localAssistant.setCurrentEvent(event); 181 IStatus valid = localAssistant.validateDrop(target, getCurrentOperation(), 182 getCurrentTransfer()); 183 if (valid != null && valid.isOK()) { 184 if (Policy.DEBUG_DND) { 185 System.out 186 .println("CommonDropAdapter.drop assistant selected: " + localAssistant + " op: " + event.detail); //$NON-NLS-1$ //$NON-NLS-2$ 187 } 188 localAssistant.handleDrop(CommonDropAdapter.this, event, target); 189 retValue[0] = true; 190 } 191 } 192 }); 193 if (retValue[0]) 194 return true; 195 } 196 197 return false; 198 } 199 200 @Override validateDrop(final Object aDropTarget, final int theDropOperation, final TransferData theTransferData)201 public boolean validateDrop(final Object aDropTarget, final int theDropOperation, 202 final TransferData theTransferData) { 203 204 if (Policy.DEBUG_DND) { 205 System.out.println("CommonDropAdapter.validateDrop (begin) operation: " + theDropOperation + " target: " + aDropTarget /*+ " transferType: " + theTransferData.type*/); //$NON-NLS-1$ //$NON-NLS-2$ 206 //new Exception().printStackTrace(System.out); 207 } 208 209 boolean result = false; 210 final IStatus[] valid = new IStatus[1]; 211 212 if (super.validateDrop(aDropTarget, theDropOperation, theTransferData)) { 213 result = true; 214 if (Policy.DEBUG_DND) { 215 System.out.println("CommonDropAdapter.validateDrop valid for plugin transfer"); //$NON-NLS-1$ 216 } 217 } else { 218 final Object target = aDropTarget != null ? aDropTarget : getViewer().getInput(); 219 if (Policy.DEBUG_DND) { 220 System.out.println("CommonDropAdapter.validateDrop target: " + target); //$NON-NLS-1$ 221 System.out.println("CommonDropAdapter.validateDrop local selection: " + //$NON-NLS-1$ 222 LocalSelectionTransfer.getTransfer().getSelection()); 223 } 224 CommonDropAdapterAssistant[] assistants = dndService.findCommonDropAdapterAssistants( 225 target, theTransferData); 226 for (final CommonDropAdapterAssistant assistantLocal : assistants) { 227 if (Policy.DEBUG_DND) { 228 System.out 229 .println("CommonDropAdapter.validateDrop checking assistant: \"" + assistantLocal); //$NON-NLS-1$ 230 } 231 SafeRunner.run(new NavigatorSafeRunnable() { 232 @Override 233 public void run() throws Exception { 234 assistantLocal.setCurrentEvent(getCurrentEvent()); 235 valid[0] = assistantLocal.validateDrop(target, theDropOperation, 236 theTransferData); 237 } 238 }); 239 if (valid[0] != null && valid[0].isOK()) { 240 result = true; 241 if (Policy.DEBUG_DND) { 242 System.out.println("CommonDropAdapter.validateDrop VALID"); //$NON-NLS-1$ 243 } 244 break; 245 } 246 if (Policy.DEBUG_DND) { 247 System.out 248 .println("CommonDropAdapter.validateDrop NOT valid: " + (valid[0] != null ? (valid[0].getSeverity() + ": " + valid[0].getMessage()) : "")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ 249 } 250 } 251 } 252 253 if (Policy.DEBUG_DND) { 254 System.out 255 .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$ 256 } 257 258 setScrollExpandEnabled(true); 259 return result; 260 261 } 262 263 /* 264 * The visibility of the following methods is raised for downstream clients 265 * (assistants). 266 */ 267 268 @Override getBounds(Item item)269 public Rectangle getBounds(Item item) { 270 return super.getBounds(item); 271 } 272 273 @Override getCurrentLocation()274 public int getCurrentLocation() { 275 return super.getCurrentLocation(); 276 } 277 278 @Override getCurrentOperation()279 public int getCurrentOperation() { 280 return super.getCurrentOperation(); 281 } 282 283 /** 284 * @see org.eclipse.jface.viewers.ViewerDropAdapter#overrideOperation(int) 285 * @since 3.4 286 */ 287 @Override overrideOperation(int operation)288 public void overrideOperation(int operation) { 289 if (Policy.DEBUG_DND) { 290 System.out.println("CommonDropAdapter.overrideOperation: " + operation); //$NON-NLS-1$ 291 } 292 super.overrideOperation(operation); 293 } 294 295 @Override getCurrentTarget()296 public Object getCurrentTarget() { 297 return super.getCurrentTarget(); 298 } 299 300 @Override getCurrentTransfer()301 public TransferData getCurrentTransfer() { 302 return super.getCurrentTransfer(); 303 } 304 305 306 } 307