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 }