001: /*******************************************************************************
002: * Copyright (c) 2006, 2007 IBM Corporation and others.
003: * All rights reserved. This program and the accompanying materials
004: * are made available under the terms of the Eclipse Public License v1.0
005: * which accompanies this distribution, and is available at
006: * http://www.eclipse.org/legal/epl-v10.html
007: *
008: * Contributors:
009: * IBM Corporation - initial API and implementation
010: *******************************************************************************/package org.eclipse.ui.internal;
011:
012: import java.util.ArrayList;
013: import java.util.Iterator;
014: import java.util.List;
015:
016: import org.eclipse.swt.dnd.DND;
017: import org.eclipse.swt.dnd.DropTarget;
018: import org.eclipse.swt.dnd.DropTargetEvent;
019: import org.eclipse.swt.dnd.DropTargetListener;
020: import org.eclipse.swt.dnd.Transfer;
021: import org.eclipse.swt.dnd.TransferData;
022: import org.eclipse.swt.widgets.Control;
023: import org.eclipse.ui.PlatformUI;
024: import org.eclipse.ui.dnd.IDragAndDropService;
025: import org.eclipse.ui.services.IDisposable;
026:
027: /**
028: * Implementation for the <code>IDragAndDropService</code> to be used from
029: * <code>EditorSite</code>'s.
030: * </p><p>
031: * Adds a drop target to the given control that merges the site's
032: * drop behaviour with that specified by the <code>addMergedDropTarget</code> call.
033: * </p><p>
034: * The current implementation is only defined for EditorSite's and merges the
035: * given drop handling with the existing EditorSashContainer's behaviour.
036: * </p><p>
037: * NOTE: There is no cleanup (i.e. 'dispose') handling necessary for merged
038: * Drop Targets but the hooks are put into place to maintain the consistency
039: * of the implementation pattern.
040: * </p>
041: * @since 3.3
042: *
043: */
044: public class EditorSiteDragAndDropServiceImpl implements
045: IDragAndDropService, IDisposable {
046: /**
047: * Implementation of a DropTarget wrapper that will either delegate to the
048: * <code>primaryListener</code> if the event's <code>currentDataType</code>
049: * can be handled by it; otherwise the event is forwarded on to the
050: * listener specified by <code>secondaryListener</code>.
051: * </p><p>
052: * NOTE: we should perhaps refactor this out into an external class
053: * </p>
054: * @since 3.3
055: *
056: */
057: private static class MergedDropTarget {
058: private DropTarget realDropTarget;
059:
060: private Transfer[] secondaryTransfers;
061: private DropTargetListener secondaryListener;
062:
063: private Transfer[] primaryTransfers;
064: private DropTargetListener primaryListener;
065:
066: public MergedDropTarget(Control control, int priOps,
067: Transfer[] priTransfers,
068: DropTargetListener priListener, int secOps,
069: Transfer[] secTransfers, DropTargetListener secListener) {
070: realDropTarget = new DropTarget(control, priOps | secOps);
071:
072: // Cache the editor's transfers and listener
073: primaryTransfers = priTransfers;
074: primaryListener = priListener;
075:
076: // Capture the editor area's current transfers & listener
077: WorkbenchWindow ww = (WorkbenchWindow) PlatformUI
078: .getWorkbench().getActiveWorkbenchWindow();
079: WorkbenchWindowConfigurer winConfigurer = ww
080: .getWindowConfigurer();
081: secondaryTransfers = winConfigurer.getTransfers();
082: secondaryListener = winConfigurer.getDropTargetListener();
083:
084: // Combine the two sets of transfers into one array
085: Transfer[] allTransfers = new Transfer[secondaryTransfers.length
086: + primaryTransfers.length];
087: int curTransfer = 0;
088: for (int i = 0; i < primaryTransfers.length; i++) {
089: allTransfers[curTransfer++] = primaryTransfers[i];
090: }
091: for (int i = 0; i < secondaryTransfers.length; i++) {
092: allTransfers[curTransfer++] = secondaryTransfers[i];
093: }
094: realDropTarget.setTransfer(allTransfers);
095:
096: // Create a listener that will delegate to the appropriate listener
097: // NOTE: the -editor- wins (i.e. it can over-ride WB behaviour if it wants
098: realDropTarget.addDropListener(new DropTargetListener() {
099: public void dragEnter(DropTargetEvent event) {
100: getAppropriateListener(event).dragEnter(event);
101: }
102:
103: public void dragLeave(DropTargetEvent event) {
104: getAppropriateListener(event).dragLeave(event);
105: }
106:
107: public void dragOperationChanged(DropTargetEvent event) {
108: getAppropriateListener(event).dragOperationChanged(
109: event);
110: }
111:
112: public void dragOver(DropTargetEvent event) {
113: getAppropriateListener(event).dragOver(event);
114: }
115:
116: public void drop(DropTargetEvent event) {
117: getAppropriateListener(event).drop(event);
118: }
119:
120: public void dropAccept(DropTargetEvent event) {
121: getAppropriateListener(event).dropAccept(event);
122: }
123: });
124: }
125:
126: private DropTargetListener getAppropriateListener(
127: DropTargetEvent event) {
128: if (isSupportedType(primaryTransfers, event.currentDataType))
129: return primaryListener;
130:
131: return secondaryListener;
132: }
133:
134: private boolean isSupportedType(Transfer[] transfers,
135: TransferData transferType) {
136: for (int i = 0; i < transfers.length; i++) {
137: if (transfers[i].isSupportedType(transferType))
138: return true;
139: }
140: return false;
141: }
142:
143: /**
144: * Clean up...
145: */
146: public void dispose() {
147: }
148: }
149:
150: // Cache any listeners for cleanup
151: List addedListeners = new ArrayList();
152:
153: /* (non-Javadoc)
154: * @see org.eclipse.ui.dnd.IEditorDropTargetService#addDropTarget(org.eclipse.swt.widgets.Control, int, org.eclipse.swt.dnd.Transfer[], org.eclipse.swt.dnd.DropTargetListener)
155: */
156: public void addMergedDropTarget(Control control, int ops,
157: Transfer[] transfers, DropTargetListener listener) {
158: // First we have to remove any existing drop target from the control
159: removeMergedDropTarget(control);
160:
161: // Capture the editor area's current ops, transfers & listener
162: int editorSiteOps = DND.DROP_DEFAULT | DND.DROP_COPY
163: | DND.DROP_LINK;
164:
165: WorkbenchWindow ww = (WorkbenchWindow) PlatformUI
166: .getWorkbench().getActiveWorkbenchWindow();
167: WorkbenchWindowConfigurer winConfigurer = ww
168: .getWindowConfigurer();
169: Transfer[] editorSiteTransfers = winConfigurer.getTransfers();
170: DropTargetListener editorSiteListener = winConfigurer
171: .getDropTargetListener();
172:
173: // Create a new 'merged' drop Listener using combination of the desired
174: // transfers and the ones used by the EditorArea
175: MergedDropTarget newTarget = new MergedDropTarget(control, ops,
176: transfers, listener, editorSiteOps,
177: editorSiteTransfers, editorSiteListener);
178: addedListeners.add(newTarget);
179: }
180:
181: /**
182: * This method will return the current drop target for the control
183: * (whether or not it was created using this service.
184: * <p>
185: * <b>WARNING:</b> This code uses an SWT internal string to gain
186: * access to the drop target. I've been assured that neither the
187: * value of the string nor the fact that the target is stored in
188: * a property will change for 3.3 and that post-3.3 we will come
189: * up with a more viable DnD SWT story...
190: * </p>
191: * @param control The control to get the drop target for
192: * @return The DropTarget for that control (could be null
193: */
194: private DropTarget getCurrentDropTarget(Control control) {
195: if (control == null)
196: return null;
197:
198: Object curDT = control.getData("DropTarget"); //$NON-NLS-1$
199: return (DropTarget) curDT;
200: }
201:
202: /* (non-Javadoc)
203: * @see org.eclipse.ui.dnd.IDragAndDropService#removeMergedDropTarget(org.eclipse.swt.widgets.Control)
204: */
205: public void removeMergedDropTarget(Control control) {
206: DropTarget targetForControl = getCurrentDropTarget(control);
207: if (targetForControl != null) {
208: targetForControl.dispose();
209: addedListeners.remove(targetForControl);
210: }
211: }
212:
213: /* (non-Javadoc)
214: * @see org.eclipse.ui.services.IDisposable#dispose()
215: */
216: public void dispose() {
217: // Clean up the listeners
218: for (Iterator iterator = addedListeners.iterator(); iterator
219: .hasNext();) {
220: MergedDropTarget target = (MergedDropTarget) iterator
221: .next();
222: target.dispose();
223: }
224: addedListeners.clear();
225: }
226:
227: }
|