A drop target in eclipse therefore cannot deal with unknown objects by default. Eg you cannot drop your plugin local objects on a Navigator view. This article describes how you can drop your own objects into existing eclipse views and how to enrich your local drop target with generic drop support.
Source code for this tutorial is available on github as a single zip archive, as a Team Project Set or you can browse the files online.
Step 1: Simple drag support
Lets start with default SWT drag support. Create a new Plug-in Project named com.codeandme.draganddrop. Add a new view with a Text element to it. Name the text element txtInput. I expect you are familiar with that procedure.
Now we add TextTransfer support:
int operations = DND.DROP_MOVE | DND.DROP_COPY; DragSource source = new DragSource(txtInput, operations); Transfer[] types = new Transfer[] { TextTransfer.getInstance() }; source.setTransfer(types); source.addDragListener(new DragSourceListener() { @Override public void dragStart(DragSourceEvent event) { if (txtInput.getText().length() == 0) event.doit = false; } @Override public void dragSetData(DragSourceEvent event) { // for text drag to editors if (TextTransfer.getInstance().isSupportedType(event.dataType)) event.data = txtInput.getSelectionText(); } @Override public void dragFinished(DragSourceEvent event) { } });This is default SWT dnd code, nothing special so far.
Step 1: Add drag support for generic objects
By default the action to be performed on a drop is implemented by the DropListener of the target. Fortunately eclipse provides a special transfer type that delegates the drop action to a dedicated class which we may provide in our plugin.
Switch to your plugin.xml and add a new Extension of type org.eclipse.ui.dropActions. Add an action element to it, set the id to com.codeandme.draganddrop.dropText and implement a class TextDropActionDelegate:
package com.codeandme.draganddrop; import java.io.ByteArrayInputStream; import org.eclipse.core.resources.IContainer; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.swt.widgets.Text; import org.eclipse.ui.part.IDropActionDelegate; public class TextDropActionDelegate implements IDropActionDelegate { public static final String ID = "com.codeandme.draganddrop.dropText"; @Override public boolean run(Object source, Object target) { if (source instanceof byte[]) { if (target instanceof IContainer) { IContainer parent = (IContainer) target; IFile file = parent.getFile(new Path("dropped text.txt")); if (!file.exists()) { try { file.create(new ByteArrayInputStream((byte[]) source), true, new NullProgressMonitor()); } catch (CoreException e) { e.printStackTrace(); } } return true; } else if (target instanceof Text) ((Text) target).setText(new String((byte[]) source)); } return false; } }The run() method gets called when the drop action is to be performed. The target is automatically set to the object under the mouse when we perform the drop, eg a folder in a Navigator view. The provided code is a bit simplified, eg we do not try to adapt the target in case it is not an IContainer.
Now we need to add our drop delegate to our source object. Switch back to your view and modify the code:
Transfer[] types = new Transfer[] { TextTransfer.getInstance(), PluginTransfer.getInstance() };add a new transfer type: PluginTransfer.
public void dragSetData(DragSourceEvent event) { // for text drag to editors if (TextTransfer.getInstance().isSupportedType(event.dataType)) event.data = txtInput.getSelectionText(); // for plugin transfer drags to navigator views if (PluginTransfer.getInstance().isSupportedType(event.dataType)) event.data = new PluginTransferData(TextDropActionDelegate.ID, txtInput.getSelectionText().getBytes()); }When a plugin transfer is accepted by the target we need to set a PluginTransferData object that links to our action delegate and provides the source data.
Everything is in place, so give it a try: type and select some text in your view and drop it on a folder in the Project Explorer view.
Step 3: Add generic drop support to your own views
Generic drop support does not come entirely for free. If you want to add it to a JFace tree or table it is dead simple as that:
int operations = DND.DROP_MOVE | DND.DROP_COPY; DropTarget target = new DropTarget(viewer.getControl(), operations); Transfer[] types = new Transfer[] { PluginTransfer.getInstance() }; target.setTransfer(types); target.addDropListener(new PluginDropAdapter(viewer));We may also reuse the PluginDropAdapter on simple Controls like text boxes. Therefore we need to overwrite some methods:
target.addDropListener(new PluginDropAdapter(null) { @Override protected int determineLocation(DropTargetEvent event) { return LOCATION_ON; } @Override protected Object getCurrentTarget() { return txtTarget; } });If you provide drop support in general it is advised to add the plugin transfer type to allow other plugins to use your drop support.