Support free tutorials:











vogella training Training Books



Eclipse Drag and Drop - Tutorial

Lars Vogel

Version 1.1

23.06.2011

Revision History
Revision 0.1 16.10.2009 Lars
Vogel
created
Revision 0.2 - 1.1 19.11.2009 - 23.06.2011 Lars
Vogel
bugfixes and enhancements

Eclipse Drag and Drop

This article demonstrates the usage of Drag and Drop in the Eclipse framework.

The article assumes that you are familiar with Eclipse RCP development. In this article Eclipse 3.7 (Indigo) is used.


Table of Contents

1. Eclipse Drag and Drop
2. Project
3. Model
4. Content and Label Provider
5. Drag Listener and Drop Listener
6. Views
7. Support free vogella tutorials
7.1. Thank you
7.2. Questions and Discussion
8. Links and Literature
8.1. Source Code
8.2. Eclipse Drag and Drop Resources
8.3. vogella Resources

1. Eclipse Drag and Drop

Eclipse supports Drag and Drop based on transfer types defined as a subclass "org.eclipse.swt.dnd.Transfer". Every UI element can define if it provides a certain transfer type as source and if it accepts a certain transfer type as destination.

Eclipse provides several pre-defined transfer types, to define your own transfer type it is recommended to subclass "org.eclipse.swt.dnd.ByteArrayTransfer".

The following will demonstrate the usage of drag and drop for your own domain object between two JFace viewers (table and tree). The example in this article will just transfer Text. For a comprehensive description of drag and drop please check the articles in the appendix.

2. Project

Create a new Eclipse RCP project "de.vogella.dnd.jface" with two views.

See Eclipes RCP for information on how to create Eclipse RCP applications and views.

3. Model

Create the following model class.

package de.vogella.dnd.jface.model;

public class Todo {
  private String shortDescription;
  private String longDescription;
  
  public Todo(String shortDescription, String longDescription) {
    this.shortDescription = shortDescription;
    this.longDescription = longDescription;
  }
  
  public String getShortDescription() {
    return shortDescription;
  }
  public void setShortDescription(String shortDescription) {
    this.shortDescription = shortDescription;
  }
  public String getLongDescription() {
    return longDescription;
  }
  public void setLongDescription(String longDescription) {
    this.longDescription = longDescription;
  }
  
  
} 

Create the following content providers (Singletons).

package de.vogella.dnd.jface.model;

import java.util.ArrayList;
import java.util.List;

public enum ContentProvider {
  INSTANCE;
  
  public List<Todo> getModel(){
    List<Todo> list = new ArrayList<Todo>();
    Todo todo = new Todo("Java", "Learn the Closure proposal");
    list.add(todo);
    todo = new Todo("Eclipse", "Learn more about the RCP platform");
    list.add(todo);
    return list;
  }
} 

package de.vogella.dnd.jface.model;

import java.util.ArrayList;
import java.util.List;

public enum ContentProviderTree {
  INSTANCE;
  List<String> list = new ArrayList<String>();
  
  private ContentProviderTree() {
    list.add("Branch1");
    list.add("Branch1");
  }
  
  public List<String> getModel(){
    return list;
  }
} 

4. Content and Label Provider

Create the following label and content provider for your JFace viewers.

package de.vogella.dnd.jface.viewers;

import java.util.List;

import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.Viewer;

import de.vogella.dnd.jface.model.Todo;

public class TableContentProvider implements IStructuredContentProvider {

  @Override
  public Object[] getElements(Object inputElement) {
    List<Todo> list = (List<Todo>) inputElement;
    return list.toArray();
  }

  @Override
  public void dispose() {
    
  }

  @Override
  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
  }

} 

package de.vogella.dnd.jface.viewers;

import java.util.List;

import org.eclipse.jface.viewers.ITreeContentProvider;
import org.eclipse.jface.viewers.Viewer;

public class TreeContentProvider implements ITreeContentProvider {

  @Override
  public Object[] getChildren(Object parentElement) {
    return null;
  }

  @Override
  public Object getParent(Object element) {
    return null;
  }

  @Override
  public boolean hasChildren(Object element) {
    return false;
  }

  @Override
  public Object[] getElements(Object inputElement) {
    List<String> list = (List<String>) inputElement;
    return list.toArray();
  }

  @Override
  public void dispose() {
    
  }

  @Override
  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
  }

} 

package de.vogella.dnd.jface.viewers;

import org.eclipse.jface.viewers.BaseLabelProvider;
import org.eclipse.jface.viewers.ITableLabelProvider;
import org.eclipse.swt.graphics.Image;

import de.vogella.dnd.jface.model.Todo;

public class TableLabelProvider extends BaseLabelProvider implements
    ITableLabelProvider {

  @Override
  public Image getColumnImage(Object element, int columnIndex) {
    return null;
  }

  @Override
  public String getColumnText(Object element, int columnIndex) {
    Todo todo = (Todo) element;
    switch (columnIndex) {
    case 0:
      return todo.getShortDescription();
    case 1:
      return todo.getLongDescription();
    }
    return "Not supported";
  }

} 

package de.vogella.dnd.jface.viewers;

import org.eclipse.jface.viewers.LabelProvider;


public class TreeLabelProvider extends LabelProvider {
  @Override
  public String getText(Object element) {
    String s = (String) element; 
    return s;
  }

} 

5. Drag Listener and Drop Listener

Create the following Drop and Drag listener which will be later assigned to the views.

package de.vogella.dnd.jface.dnd;

import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.dnd.DragSourceEvent;
import org.eclipse.swt.dnd.DragSourceListener;
import org.eclipse.swt.dnd.TextTransfer;

import de.vogella.dnd.jface.model.Todo;
public class MyDragListener implements DragSourceListener {

  private final TableViewer viewer;

  public MyDragListener(TableViewer viewer) {
    this.viewer = viewer;
  }

  @Override
  public void dragFinished(DragSourceEvent event) {
    System.out.println("Finshed Drag");
  }

  @Override
  public void dragSetData(DragSourceEvent event) {
    // Here you do the convertion to the type which is expected.
    IStructuredSelection selection = (IStructuredSelection) viewer
    .getSelection();
    Todo firstElement = (Todo) selection.getFirstElement();
    
    if (TextTransfer.getInstance().isSupportedType(event.dataType)) {
      event.data = firstElement.getShortDescription() + " " + firstElement.getLongDescription(); 
    }

  }

  @Override
  public void dragStart(DragSourceEvent event) {
    System.out.println("Start Drag");
  }

} 

package de.vogella.dnd.jface.dnd;

import org.eclipse.jface.viewers.Viewer;
import org.eclipse.jface.viewers.ViewerDropAdapter;
import org.eclipse.swt.dnd.DropTargetEvent;
import org.eclipse.swt.dnd.TransferData;

import de.vogella.dnd.jface.model.ContentProviderTree;

public class MyDropListener extends ViewerDropAdapter {

  private final Viewer viewer;

  public MyDropListener(Viewer viewer) {
    super(viewer);
    this.viewer = viewer;
  }

  @Override
  public void drop(DropTargetEvent event) {
    int location = this.determineLocation(event);
    String target = (String) determineTarget(event);
    String translatedLocation ="";
    switch (location){
    case 1 :
      translatedLocation = "Dropped before the target ";
      break;
    case 2 :
      translatedLocation = "Dropped after the target ";
      break;
    case 3 :
      translatedLocation = "Dropped on the target ";
      break;
    case 4 :
      translatedLocation = "Dropped into nothing ";
      break;
    }
    System.out.println(translatedLocation);
    System.out.println("The drop was done on the element: " + target);
    super.drop(event);
  }

  // This method performs the actual drop
  // We simply add the String we receive to the model and trigger a refresh of the 
  // viewer by calling its setInput method.
  @Override
  public boolean performDrop(Object data) {
    ContentProviderTree.INSTANCE.getModel().add(data.toString());
    viewer.setInput(ContentProviderTree.INSTANCE.getModel());
    return false;
  }

  @Override
  public boolean validateDrop(Object target, int operation,
      TransferData transferType) {
    return true;
    
  }

  

} 

6. Views

Adjust your views. The first view will show a table and will allow that elements will be dragged from it. The second view accepts drops.

package de.vogella.dnd.jface.view;

import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import de.vogella.dnd.jface.dnd.MyDragListener;
import de.vogella.dnd.jface.model.ContentProvider;
import de.vogella.dnd.jface.viewers.TableContentProvider;
import de.vogella.dnd.jface.viewers.TableLabelProvider;

public class TableView extends ViewPart {


  @Override
  public void createPartControl(Composite parent) {
    TableViewer viewer = new TableViewer(parent, SWT.MULTI | SWT.H_SCROLL
        | SWT.V_SCROLL);
    int operations = DND.DROP_COPY| DND.DROP_MOVE;
    Transfer[] transferTypes = new Transfer[]{TextTransfer.getInstance()};
    viewer.addDragSupport(operations, transferTypes , new MyDragListener(viewer));
    viewer.setContentProvider(new TableContentProvider());
    viewer.setLabelProvider(new TableLabelProvider());
    viewer.setInput(ContentProvider.INSTANCE.getModel());
  }

  @Override
  public void setFocus() {

  }

} 

package de.vogella.dnd.jface.view;

import org.eclipse.jface.viewers.TreeViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.dnd.DND;
import org.eclipse.swt.dnd.TextTransfer;
import org.eclipse.swt.dnd.Transfer;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.ui.part.ViewPart;

import de.vogella.dnd.jface.dnd.MyDropListener;
import de.vogella.dnd.jface.model.ContentProviderTree;
import de.vogella.dnd.jface.viewers.TreeContentProvider;
import de.vogella.dnd.jface.viewers.TreeLabelProvider;

public class TreeView extends ViewPart {

  @Override
  public void createPartControl(Composite parent) {
    TreeViewer viewer = new TreeViewer(parent, SWT.MULTI | SWT.H_SCROLL
        | SWT.V_SCROLL);
    int operations = DND.DROP_COPY | DND.DROP_MOVE;
    Transfer[] transferTypes = new Transfer[]{TextTransfer.getInstance()};
    viewer.addDropSupport(operations, transferTypes, new MyDropListener(viewer));
    viewer.setContentProvider(new TreeContentProvider());
    viewer.setLabelProvider(new TreeLabelProvider());
    viewer.setInput(ContentProviderTree.INSTANCE.getModel());
  }
  
  @Override
  public void setFocus() {
  }


} 

7. Support free vogella tutorials

Maintaining high quality free online tutorials is a lot of work. Please support free tutorials by donating or by reporting typos and factual errors.

7.1. Thank you

Please consider a contribution if this article helped you.

Flattr this

7.2. Questions and Discussion

If you find errors in this tutorial, please notify me (see the top of the page). Please note that due to the high volume of feedback I receive, I cannot answer questions to your implementation. Ensure you have read the vogella FAQ as I don't respond to questions already answered there.

8. Links and Literature

8.1. Source Code

Source Code of Examples

8.2. Eclipse Drag and Drop Resources

SWT Drag and Drop

JFace Drag and Drop

8.3. vogella Resources

vogella Training Android and Eclipse Training from the vogella team

Android Tutorial Introduction to Android Programming

GWT Tutorial Program in Java, compile to JavaScript and HTML

Eclipse RCP Tutorial Create native applications in Java

JUnit Tutorial Test your application

Git Tutorial Put all your files in a distributed version control system