Mercurial > projects > dwt2
comparison org.eclipse.jface/src/org/eclipse/jface/util/DelegatingDropAdapter.d @ 12:bc29606a740c
Added dwt-addons in original directory structure of eclipse.org
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sat, 14 Mar 2009 18:23:29 +0100 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
11:43904fec5dca | 12:bc29606a740c |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2007 IBM Corporation and others. | |
3 * All rights reserved. This program and the accompanying materials | |
4 * are made available under the terms of the Eclipse Public License v1.0 | |
5 * which accompanies this distribution, and is available at | |
6 * http://www.eclipse.org/legal/epl-v10.html | |
7 * | |
8 * Contributors: | |
9 * IBM Corporation - initial API and implementation | |
10 * Port to the D programming language: | |
11 * Frank Benoit <benoit@tionex.de> | |
12 *******************************************************************************/ | |
13 module org.eclipse.jface.util.DelegatingDropAdapter; | |
14 | |
15 import org.eclipse.jface.util.TransferDropTargetListener; | |
16 import org.eclipse.jface.util.SafeRunnable; | |
17 | |
18 | |
19 import org.eclipse.swt.dnd.DND; | |
20 import org.eclipse.swt.dnd.DropTargetEvent; | |
21 import org.eclipse.swt.dnd.DropTargetListener; | |
22 import org.eclipse.swt.dnd.Transfer; | |
23 import org.eclipse.swt.dnd.TransferData; | |
24 | |
25 import java.lang.all; | |
26 import java.util.List; | |
27 import java.util.ArrayList; | |
28 import java.util.Iterator; | |
29 import java.util.Set; | |
30 | |
31 /** | |
32 * A <code>DelegatingDropAdapter</code> is a <code>DropTargetListener</code> that | |
33 * maintains and delegates to a set of {@link TransferDropTargetListener}s. Each | |
34 * <code>TransferDropTargetListener</code> can then be implemented as if it were | |
35 * the DropTarget's only <code>DropTargetListener</code>. | |
36 * <p> | |
37 * On <code>dragEnter</code>, <code>dragOperationChanged</code>, <code>dragOver</code> | |
38 * and <code>drop</code>, a <i>current</i> listener is obtained from the set of all | |
39 * <code>TransferDropTargetListeners</code>. The current listener is the first listener | |
40 * to return <code>true</code> for | |
41 * {@link TransferDropTargetListener#isEnabled(DropTargetEvent)}. | |
42 * The current listener is forwarded all <code>DropTargetEvents</code> until some other | |
43 * listener becomes the current listener, or the drop terminates. | |
44 * </p> | |
45 * <p> | |
46 * After adding all <code>TransferDropTargetListeners</code> to the | |
47 * <code>DelegatingDropAdapter</code> the combined set of <code>Transfers</code> should | |
48 * be set in the SWT <code>DropTarget</code>. <code>#getTransfers()</code> provides the | |
49 * set of <code>Transfer</code> types of all <code>TransferDropTargetListeners</code>. | |
50 * </p> | |
51 * <p> | |
52 * The following example snippet shows a <code>DelegatingDropAdapter</code> with two | |
53 * <code>TransferDropTargetListeners</code>. One supports dropping resources and | |
54 * demonstrates how a listener can be disabled in the isEnabled method. | |
55 * The other listener supports text transfer. | |
56 * </p> | |
57 * <code><pre> | |
58 * final TreeViewer viewer = new TreeViewer(shell, SWT.NONE); | |
59 * DelegatingDropAdapter dropAdapter = new DelegatingDropAdapter(); | |
60 * dropAdapter.addDropTargetListener(new TransferDropTargetListener() { | |
61 * public Transfer getTransfer() { | |
62 * return ResourceTransfer.getInstance(); | |
63 * } | |
64 * public bool isEnabled(DropTargetEvent event) { | |
65 * // disable drop listener if there is no viewer selection | |
66 * if (viewer.getSelection().isEmpty()) | |
67 * return false; | |
68 * return true; | |
69 * } | |
70 * public void dragEnter(DropTargetEvent event) {} | |
71 * public void dragLeave(DropTargetEvent event) {} | |
72 * public void dragOperationChanged(DropTargetEvent event) {} | |
73 * public void dragOver(DropTargetEvent event) {} | |
74 * public void drop(DropTargetEvent event) { | |
75 * if (event.data is null) | |
76 * return; | |
77 * IResource[] resources = (IResource[]) event.data; | |
78 * if (event.detail is DND.DROP_COPY) { | |
79 * // copy resources | |
80 * } else { | |
81 * // move resources | |
82 * } | |
83 * | |
84 * } | |
85 * public void dropAccept(DropTargetEvent event) {} | |
86 * }); | |
87 * dropAdapter.addDropTargetListener(new TransferDropTargetListener() { | |
88 * public Transfer getTransfer() { | |
89 * return TextTransfer.getInstance(); | |
90 * } | |
91 * public bool isEnabled(DropTargetEvent event) { | |
92 * return true; | |
93 * } | |
94 * public void dragEnter(DropTargetEvent event) {} | |
95 * public void dragLeave(DropTargetEvent event) {} | |
96 * public void dragOperationChanged(DropTargetEvent event) {} | |
97 * public void dragOver(DropTargetEvent event) {} | |
98 * public void drop(DropTargetEvent event) { | |
99 * if (event.data is null) | |
100 * return; | |
101 * System.out.println(event.data); | |
102 * } | |
103 * public void dropAccept(DropTargetEvent event) {} | |
104 * }); | |
105 * viewer.addDropSupport(DND.DROP_COPY | DND.DROP_MOVE, dropAdapter.getTransfers(), dropAdapter); | |
106 * </pre></code> | |
107 * @since 3.0 | |
108 */ | |
109 public class DelegatingDropAdapter : DropTargetListener { | |
110 private List listeners; | |
111 | |
112 private TransferDropTargetListener currentListener; | |
113 | |
114 private int originalDropType; | |
115 | |
116 this(){ | |
117 listeners = new ArrayList(); | |
118 } | |
119 | |
120 /** | |
121 * Adds the given <code>TransferDropTargetListener</code>. | |
122 * | |
123 * @param listener the new listener | |
124 */ | |
125 public void addDropTargetListener(TransferDropTargetListener listener) { | |
126 listeners.add(cast(Object)listener); | |
127 } | |
128 | |
129 /** | |
130 * The cursor has entered the drop target boundaries. The current listener is | |
131 * updated, and <code>#dragEnter()</code> is forwarded to the current listener. | |
132 * | |
133 * @param event the drop target event | |
134 * @see DropTargetListener#dragEnter(DropTargetEvent) | |
135 */ | |
136 public void dragEnter(DropTargetEvent event) { | |
137 // if (Policy.DEBUG_DRAG_DROP) | |
138 // System.out.println("Drag Enter: " + toString()); //$NON-NLS-1$ | |
139 originalDropType = event.detail; | |
140 updateCurrentListener(event); | |
141 } | |
142 | |
143 /** | |
144 * The cursor has left the drop target boundaries. The event is forwarded to the | |
145 * current listener. | |
146 * | |
147 * @param event the drop target event | |
148 * @see DropTargetListener#dragLeave(DropTargetEvent) | |
149 */ | |
150 public void dragLeave(DropTargetEvent event) { | |
151 // if (Policy.DEBUG_DRAG_DROP) | |
152 // System.out.println("Drag Leave: " + toString()); //$NON-NLS-1$ | |
153 setCurrentListener(null, event); | |
154 } | |
155 | |
156 /** | |
157 * The operation being performed has changed (usually due to the user changing | |
158 * a drag modifier key while dragging). Updates the current listener and forwards | |
159 * this event to that listener. | |
160 * | |
161 * @param event the drop target event | |
162 * @see DropTargetListener#dragOperationChanged(DropTargetEvent) | |
163 */ | |
164 public void dragOperationChanged(DropTargetEvent event) { | |
165 // if (Policy.DEBUG_DRAG_DROP) | |
166 // System.out.println("Drag Operation Changed to: " + event.detail); //$NON-NLS-1$ | |
167 originalDropType = event.detail; | |
168 TransferDropTargetListener oldListener = getCurrentListener(); | |
169 updateCurrentListener(event); | |
170 TransferDropTargetListener newListener = getCurrentListener(); | |
171 // only notify the current listener if it hasn't changed based on the | |
172 // operation change. otherwise the new listener would get a dragEnter | |
173 // followed by a dragOperationChanged with the exact same event. | |
174 if (newListener !is null && newListener is oldListener) { | |
175 SafeRunnable.run(new class(event,newListener) SafeRunnable { | |
176 DropTargetEvent event_; | |
177 TransferDropTargetListener newListener_; | |
178 this(DropTargetEvent a,TransferDropTargetListener b){ | |
179 event_=a; | |
180 newListener_=b; | |
181 } | |
182 public void run() { | |
183 newListener_.dragOperationChanged(event_); | |
184 } | |
185 }); | |
186 } | |
187 } | |
188 | |
189 /** | |
190 * The cursor is moving over the drop target. Updates the current listener and | |
191 * forwards this event to that listener. If no listener can handle the drag | |
192 * operation the <code>event.detail</code> field is set to <code>DND.DROP_NONE</code> | |
193 * to indicate an invalid drop. | |
194 * | |
195 * @param event the drop target event | |
196 * @see DropTargetListener#dragOver(DropTargetEvent) | |
197 */ | |
198 public void dragOver(DropTargetEvent event) { | |
199 TransferDropTargetListener oldListener = getCurrentListener(); | |
200 updateCurrentListener(event); | |
201 TransferDropTargetListener newListener = getCurrentListener(); | |
202 | |
203 // only notify the current listener if it hasn't changed based on the | |
204 // drag over. otherwise the new listener would get a dragEnter | |
205 // followed by a dragOver with the exact same event. | |
206 if (newListener !is null && newListener is oldListener) { | |
207 SafeRunnable.run(new class(event,newListener) SafeRunnable { | |
208 DropTargetEvent event_; | |
209 TransferDropTargetListener newListener_; | |
210 this(DropTargetEvent a,TransferDropTargetListener b){ | |
211 event_=a; | |
212 newListener_=b; | |
213 } | |
214 public void run() { | |
215 newListener_.dragOver(event_); | |
216 } | |
217 }); | |
218 } | |
219 } | |
220 | |
221 /** | |
222 * Forwards this event to the current listener, if there is one. Sets the | |
223 * current listener to <code>null</code> afterwards. | |
224 * | |
225 * @param event the drop target event | |
226 * @see DropTargetListener#drop(DropTargetEvent) | |
227 */ | |
228 public void drop(DropTargetEvent event) { | |
229 // if (Policy.DEBUG_DRAG_DROP) | |
230 // System.out.println("Drop: " + toString()); //$NON-NLS-1$ | |
231 updateCurrentListener(event); | |
232 if (getCurrentListener() !is null) { | |
233 SafeRunnable.run(new class(event) SafeRunnable { | |
234 DropTargetEvent event_; | |
235 this(DropTargetEvent a){ event_=a;} | |
236 public void run() { | |
237 getCurrentListener().drop(event_); | |
238 } | |
239 }); | |
240 } | |
241 setCurrentListener(null, event); | |
242 } | |
243 | |
244 /** | |
245 * Forwards this event to the current listener if there is one. | |
246 * | |
247 * @param event the drop target event | |
248 * @see DropTargetListener#dropAccept(DropTargetEvent) | |
249 */ | |
250 public void dropAccept(DropTargetEvent event) { | |
251 // if (Policy.DEBUG_DRAG_DROP) | |
252 // System.out.println("Drop Accept: " + toString()); //$NON-NLS-1$ | |
253 if (getCurrentListener() !is null) { | |
254 SafeRunnable.run(new class(event) SafeRunnable { | |
255 DropTargetEvent event_; | |
256 this(DropTargetEvent a){ event_=a;} | |
257 public void run() { | |
258 getCurrentListener().dropAccept(event_); | |
259 } | |
260 }); | |
261 } | |
262 } | |
263 | |
264 /** | |
265 * Returns the listener which currently handles drop events. | |
266 * | |
267 * @return the <code>TransferDropTargetListener</code> which currently | |
268 * handles drop events. | |
269 */ | |
270 private TransferDropTargetListener getCurrentListener() { | |
271 return currentListener; | |
272 } | |
273 | |
274 /** | |
275 * Returns the transfer data type supported by the given listener. | |
276 * Returns <code>null</code> if the listener does not support any of the | |
277 * specified data types. | |
278 * | |
279 * @param dataTypes available data types | |
280 * @param listener <code>TransferDropTargetListener</code> to use for testing | |
281 * supported data types. | |
282 * @return the transfer data type supported by the given listener or | |
283 * <code>null</code>. | |
284 */ | |
285 private TransferData getSupportedTransferType(TransferData[] dataTypes, | |
286 TransferDropTargetListener listener) { | |
287 for (int i = 0; i < dataTypes.length; i++) { | |
288 if (listener.getTransfer().isSupportedType(dataTypes[i])) { | |
289 return dataTypes[i]; | |
290 } | |
291 } | |
292 return null; | |
293 } | |
294 | |
295 /** | |
296 * Returns the combined set of <code>Transfer</code> types of all | |
297 * <code>TransferDropTargetListeners</code>. | |
298 * | |
299 * @return the combined set of <code>Transfer</code> types | |
300 */ | |
301 public Transfer[] getTransfers() { | |
302 Transfer[] types = new Transfer[listeners.size()]; | |
303 for (int i = 0; i < listeners.size(); i++) { | |
304 TransferDropTargetListener listener = cast(TransferDropTargetListener) listeners | |
305 .get(i); | |
306 types[i] = listener.getTransfer(); | |
307 } | |
308 return types; | |
309 } | |
310 | |
311 /** | |
312 * Returns <code>true</code> if there are no listeners to delegate events to. | |
313 * | |
314 * @return <code>true</code> if there are no <code>TransferDropTargetListeners</code> | |
315 * <code>false</code> otherwise | |
316 */ | |
317 public bool isEmpty() { | |
318 return listeners.isEmpty(); | |
319 } | |
320 | |
321 /** | |
322 * Removes the given <code>TransferDropTargetListener</code>. | |
323 * Listeners should not be removed while a drag and drop operation is in progress. | |
324 * | |
325 * @param listener the listener to remove | |
326 */ | |
327 public void removeDropTargetListener(TransferDropTargetListener listener) { | |
328 if (currentListener is listener) { | |
329 currentListener = null; | |
330 } | |
331 listeners.remove(cast(Object)listener); | |
332 } | |
333 | |
334 /** | |
335 * Sets the current listener to <code>listener</code>. Sends the given | |
336 * <code>DropTargetEvent</code> if the current listener changes. | |
337 * | |
338 * @return <code>true</code> if the new listener is different than the previous | |
339 * <code>false</code> otherwise | |
340 */ | |
341 private bool setCurrentListener(TransferDropTargetListener listener, | |
342 DropTargetEvent event) { | |
343 if (currentListener is listener) { | |
344 return false; | |
345 } | |
346 if (currentListener !is null) { | |
347 SafeRunnable.run(new class(event) SafeRunnable { | |
348 DropTargetEvent event_; | |
349 this(DropTargetEvent a){ event_=a;} | |
350 public void run() { | |
351 currentListener.dragLeave(event_); | |
352 } | |
353 }); | |
354 } | |
355 currentListener = listener; | |
356 // if (Policy.DEBUG_DRAG_DROP) | |
357 // System.out.println("Current drop listener: " + listener); //$NON-NLS-1$ | |
358 if (currentListener !is null) { | |
359 SafeRunnable.run(new class(event) SafeRunnable { | |
360 DropTargetEvent event_; | |
361 this(DropTargetEvent a){ event_=a;} | |
362 public void run() { | |
363 currentListener.dragEnter(event_); | |
364 } | |
365 }); | |
366 } | |
367 return true; | |
368 } | |
369 | |
370 /** | |
371 * Updates the current listener to one that can handle the drop. There can be many | |
372 * listeners and each listener may be able to handle many <code>TransferData</code> | |
373 * types. The first listener found that can handle a drop of one of the given | |
374 * <code>TransferData</code> types will be selected. | |
375 * If no listener can handle the drag operation the <code>event.detail</code> field | |
376 * is set to <code>DND.DROP_NONE</code> to indicate an invalid drop. | |
377 * | |
378 * @param event the drop target event | |
379 */ | |
380 private void updateCurrentListener(DropTargetEvent event) { | |
381 int originalDetail = event.detail; | |
382 // revert the detail to the "original" drop type that the User indicated. | |
383 // this is necessary because the previous listener may have changed the detail | |
384 // to something other than what the user indicated. | |
385 event.detail = originalDropType; | |
386 | |
387 Iterator iter = listeners.iterator(); | |
388 while (iter.hasNext()) { | |
389 TransferDropTargetListener listener = cast(TransferDropTargetListener) iter | |
390 .next(); | |
391 TransferData dataType = getSupportedTransferType(event.dataTypes, | |
392 listener); | |
393 if (dataType !is null) { | |
394 TransferData originalDataType = event.currentDataType; | |
395 // set the data type supported by the drop listener | |
396 event.currentDataType = dataType; | |
397 if (listener.isEnabled(event)) { | |
398 // if the listener stays the same, set its previously determined | |
399 // event detail | |
400 if (!setCurrentListener(listener, event)) { | |
401 event.detail = originalDetail; | |
402 } | |
403 return; | |
404 } | |
405 event.currentDataType = originalDataType; | |
406 } | |
407 } | |
408 setCurrentListener(null, event); | |
409 event.detail = DND.DROP_NONE; | |
410 | |
411 // -always- ensure that expand/scroll are on...otherwise | |
412 // if a valid drop target is a child of an invalid one | |
413 // you can't get there... | |
414 event.feedback = DND.FEEDBACK_EXPAND | DND.FEEDBACK_SCROLL; | |
415 } | |
416 } |