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