gwt

GWT Drag and Drop Example

In this example we will learn about GWT Drag and Drop. The Google Web Toolkit is a development framework for creating Ajax-enabled web applications in Java. Drag and Drop is supported in most browsers but currently it’s not supported in Opera. Tools and technologies used in this example are Java 1.8, Eclipse Luna 4.4.2, Eclipse GWT Plugin 2.6

1. Introduction

The ultimate in user interactivity, drag and drop is taken for granted in desktop applications but is a litmus test of sorts for web applications. Until now, drag and drop for web applications has, for the most part, been limited to specialized JavaScript frameworks such as Script.aculo.us and Rico. With the advent of GWT, we have drag-and-drop capabilities in a Java-based web application framework. Although GWT does not explicitly support drag and drop (drag and drop is an anticipated feature in the future), it provides us with all the necessary ingredients to make our own drag-and-drop module.

Whatever we are dragging we can make that appear beneath the cursor and it’s easy to do that. So the key elements are draggable things, drop targets and tons of events in between.

2. Configuration

Below is the GWT configuration file. The most important part is the entry point class which is defined in this configuration file.

GWTDradAndDrop.gwt.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.6.0//EN"
"http://google-web-toolkit.googlecode.com/svn/tags/2.6.0/distro-source/core/src/gwt-module.dtd">
<module rename-to='gwtdradanddrop'>
  <!-- Inherit the core Web Toolkit stuff. -->
  <inherits name='com.google.gwt.user.User'/>
  <inherits name='com.google.gwt.user.theme.clean.Clean'/>

  <!-- Specify the app entry point class. -->
  <entry-point class='com.javacodegeeks.client.GWTDradAndDrop'/>

  <!-- Specify the paths for translatable code -->
  <source path='client'/>
  <source path='shared'/>
</module>

3. Java files

To make a widget draggable, you must set the draggable property and add a drag handler. getElement().setDraggable(Element.DRAGGABLE_TRUE); The allowed values are DRAGGABLE_AUTO (auto), DRAGGABLE_FALSE (false), DRAGGABLE_TRUE (true).

Some widgets support the draggable property directly and some don’t. Label doesn’t. In the Drag Start Handler, you must set the event data, or some browsers will not allow you to drag it.

To make a widget droppable, you must add a DragOver handler and a drop handler. Make sure to call event.preventDefault() in the onDrop, or else the browser might navigate away from the current page!

private void initDrag() {
  getElement().setDraggable(Element.DRAGGABLE_TRUE);
  addDragStartHandler(new DragStartHandler() {
    @Override
    public void onDragStart(DragStartEvent event) {
      // Remember what's being dragged
      dragging = DragDropLabel.this;
      event.setData("ID", "UniqueIdentifier");
      event.getDataTransfer().setDragImage(getElement(), 10, 10);
    }
  });
}

We need to call the setData() for some of the browsers like Firefox. It sets the data in the DataTransfer object for the specified format. event.getDataTransfer().setDragImage(getElement(), 10, 10); copies the label image for the drag icon. The 10, 10 indicate the ‘x’ and ‘y’ offset of the cursor.

We don’t need to use the DragOverHandler but we need to add it. Here we are just changing the style.

addDomHandler(new DragOverHandler() {
  @Override
  public void onDragOver(DragOverEvent event) {
  addStyleName("dropping");
  }
}, DragOverEvent.getType());

To prevent the native text drop do event.preventDefault();

DragDropLabel.java

package com.javacodegeeks.client;

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

import com.google.gwt.event.dom.client.DragLeaveEvent;
import com.google.gwt.event.dom.client.DragLeaveHandler;
import com.google.gwt.event.dom.client.DragOverEvent;
import com.google.gwt.event.dom.client.DragOverHandler;
import com.google.gwt.event.dom.client.DragStartEvent;
import com.google.gwt.event.dom.client.DragStartHandler;
import com.google.gwt.event.dom.client.DropEvent;
import com.google.gwt.event.dom.client.DropHandler;
import com.google.gwt.dom.client.Element;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;
import com.google.gwt.user.client.ui.Widget;

public class DragDropLabel extends Label {
 
 private static DragDropLabel dragging = null;
 final boolean droppable;

 public DragDropLabel(String text, boolean draggable, boolean droppable) {
   super(text);
   if (draggable) {
     initDrag();
   }
   if (droppable) {
     initDrop();
   }
   this.droppable = droppable;

   if (droppable) {
     addStyleName("droppable");
   } else if (draggable) {
     addStyleName("draggable");
   }
 }

   private void initDrag() {
     getElement().setDraggable(Element.DRAGGABLE_TRUE);

     addDragStartHandler(new DragStartHandler() {
     @Override
     public void onDragStart(DragStartEvent event) {     
       dragging = DragDropLabel.this;
       event.setData("ID", "UniqueIdentifier");
       event.getDataTransfer().setDragImage(getElement(), 10, 10);
     }
   });
 }

 private void initDrop() {
   addDomHandler(new DragOverHandler() {
   @Override
   public void onDragOver(DragOverEvent event) {
     addStyleName("dropping");
   }
 }, DragOverEvent.getType());

 addDomHandler(new DragLeaveHandler() {
   @Override
   public void onDragLeave(DragLeaveEvent event) {
     removeStyleName("dropping");
   }
 }, DragLeaveEvent.getType());

 addDomHandler(new DropHandler() {
   @Override
   public void onDrop(DropEvent event) {
     event.preventDefault();
     if (dragging != null) {
     TreeItem target = null;
     TreeItem source = null;
     Tree tree = (Tree) DragDropLabel.this.getParent();
     List<TreeItem> treeItems = new ArrayList<TreeItem>();
     treeItems.add(tree.getItem(0));
     while (!treeItems.isEmpty()) {
       TreeItem item = treeItems.remove(0);
       for (int i = 0; i < item.getChildCount(); i++) {
       treeItems.add(item.getChild(i));
     }

     Widget widget = item.getWidget();
     if (widget != null) {
       if (widget == dragging) {
         source = item;
         if (target != null) {
           break;
         }
       }
       if (widget == DragDropLabel.this) {
         target = item;
         widget.removeStyleName("dropping");
         if (source != null) {
           break;
         }
       }
     }
   }

     if (source != null && target != null) {
       TreeItem testTarget = target;
       while (testTarget != null) {
         if (testTarget == source) {
           return;
         }
         testTarget = testTarget.getParentItem();
       }
       target.addItem(source);
       target.setState(true);
     }
     dragging = null;
   }
 }
 }, DropEvent.getType());
 }
}

GWTDradAndDrop.java

package com.javacodegeeks.client;

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

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.user.client.Random;
import com.google.gwt.user.client.ui.RootPanel;
import com.google.gwt.user.client.ui.Tree;
import com.google.gwt.user.client.ui.TreeItem;

/**
* Entry point classes define <code>onModuleLoad()</code>.
*/
public class GWTDradAndDrop implements EntryPoint {

/**
* This is the entry point method.
*/
  public void onModuleLoad() {
    Tree tree = new Tree();
    TreeItem root = new TreeItem(new DragDropLabel("Grand Parent", false, true));
    tree.addItem(root);
    root.addItem(new DragDropLabel("Parent 1", true, true));
    root.addItem(new DragDropLabel("Parent 2", true, true));

    TreeItem parent3 = root.addItem(new DragDropLabel("Parent 3", true, true));
    parent3.addItem(new DragDropLabel("Parent 3.1", true, true));
    parent3.addItem(new DragDropLabel("Parent 3.2", true, true));

    List<TreeItem> treeItems = new ArrayList<TreeItem>();
    treeItems.add(tree.getItem(0));

    int number = 1;
    while (!treeItems.isEmpty()) {
      TreeItem item = treeItems.remove(0);
      for (int i = 0; i < item.getChildCount(); i++) {
        treeItems.add(item.getChild(i));
      }

      int files = Random.nextInt(4) + 1;
      for (int j = 0; j < files; j++) {
        item.addItem(new TreeItem(new DragDropLabel("Child " + number, true, false)));
        number++;
      }
      item.setState(true);
    }

    RootPanel.get().add(tree);
  }
}

4. GWT Compile

To compile the application right click on the project and choose ‘Google’. Then choose ‘GWT Compile’.

Figure 1. GWT Compile
Figure 1. GWT Compile

After clicking on the ‘GWT Compile’ we will get the below screen.

Figure 2. GWT Compile 2
Figure 2. GWT Compile 2

Click on the compile button. GWT will start compiling the project. You will see the below logs in the ‘Console’ window.

Compiling module com.javacodegeeks.GWTDradAndDrop
  Compiling 5 permutations
    Compiling permutation 0...
    Compiling permutation 1...
    Compiling permutation 2...
    Compiling permutation 3...
    Compiling permutation 4...
  Compile of permutations succeeded
Linking into E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\gwtdradanddrop
  Link succeeded
  Compilation succeeded -- 74.734s

5. Running the application

To run the application right click on the project and choose ‘Run As’ -> ‘Web Application (GWT Classic Dev Mode)’. Below is the screenshot:

Figure 3. GWT Run
Figure 3. GWT Run

You will get below logs in the ‘Console’ window. If there is any exception, it will be displayed in the same window.

Initializing App Engine server
Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.config.AppEngineWebXmlReader readAppEngineWebXml
INFO: Successfully processed E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF/appengine-web.xml
Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.config.AbstractConfigXmlReader readConfigXml
INFO: Successfully processed E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF/web.xml
Sep 01, 2015 9:17:02 PM com.google.appengine.tools.development.SystemPropertiesManager setSystemProperties
INFO: Overwriting system property key 'java.util.logging.config.file', value 'E:\meraj\study\eclipse\plugins\com.google.appengine.eclipse.sdkbundle_1.9.19\appengine-java-sdk-1.9.19\config\sdk\logging.properties' with value 'WEB-INF/logging.properties' from 'E:\meraj\study\eclipse-workspace\GWTDradAndDrop\war\WEB-INF\appengine-web.xml'
Sep 01, 2015 9:17:02 PM com.google.apphosting.utils.jetty.JettyLogger info
INFO: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
Sep 01, 2015 9:17:03 PM com.google.appengine.tools.development.DevAppServerImpl setServerTimeZone
WARNING: Unable to set the TimeZone to UTC (this is expected if running on JDK 8)
Sep 01, 2015 9:17:03 PM com.google.apphosting.utils.jetty.JettyLogger info
INFO: jetty-6.1.x
Sep 01, 2015 9:17:07 PM com.google.apphosting.utils.jetty.JettyLogger info
INFO: Started SelectChannelConnector@0.0.0.0:8888
Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.AbstractModule startup
INFO: Module instance default is running at http://localhost:8888/
Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.AbstractModule startup
INFO: The admin console is running at http://localhost:8888/_ah/admin
Sep 01, 2015 9:17:07 PM com.google.appengine.tools.development.DevAppServerImpl doStart
INFO: Dev App Server is now running

Once the application is running the focus will shift to the ‘Development Mode’ window where a URL will be displayed – http://127.0.0.1:8888/GWTDradAndDrop.html?gwt.codesvr=127.0.0.1:9997. Copy this URL and paste it in the Internet Explorer or your favorite browser. Remove the part after ‘.html’ and click Enter. You will get the screen as below.

Figure 4. Output
Figure 4. Output

You can drag the Child and drop them into different Parent.

6. Download the source file

This was an example of GWT Drag and Drop.

Download
You can download the full source code of this example here: GWT Drad And Drop. Please note that to save the space the lib folder is not included in the zip.

Mohammad Meraj Zia

Senior Java Developer
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button