Implement Drag and Drop in Your Web Apps - Part 2/Page 3 | WebReference

Implement Drag and Drop in Your Web Apps - Part 2/Page 3

[previous] [next]

Implement Drag and Drop in Your Web Apps - Part 2 [con't]

Mouse Listeners

The final pieces of the dnd puzzle are the mouse listeners, where most of the complexity lies. Listing 6.13 lists the AbstractMouseDragger class, which blithely drags widgets around on an absolute panel.

Listing 6.13 com.gwtsolutions.components.client.ui.dnd.AbstractMouseDragger

This class knows nothing about drag sources or drop targets; all it does is drag widgets. Most of the logic consists of basic math that calculates the next position of a widget and checks boundaries to make sure the widget does not escape its enclosing absolute panel.

The interesting parts of the class are the calls to DOM.setCapture() and DOM.releaseCapture(), in onMouseDown() and onMouseUp(), respectively. DOM.setCapture() captures all mouse events and makes them available only to the widget that it is passed until DOM.releaseCapture() is invoked, returning event handling to normal. That provides a significant boost to performance while a widget is being dragged, which gives us time to make sophisticated calculations, like those in the DragSourceListener class, listed in Listing 6.15.

One other interesting thing about the AbstractMouseDragger class: It's abstract because it defines two abstract methods that can be implemented by subclasses to plug in a different dragging algorithm. Those methods—getNextLeft() and getNextTop()—are passed proposed locations that follow the mouse and return final locations for the current mouse movement. Those methods can be implemented by subclasses for specialized dragging, such as dragging widgets only in the horizontal or vertical directions. One of those subclasses is the FollowsMouseDragger class, listed in Listing 6.14, which follows the mouse but restricts the widget being dragged to the bounds of its enclosing absolute panel by invoking the inherited methods checkLeftBounds() and checkTopBounds().

Listing 6.14 com.gwtsolutions.components.client.ui.dnd.FollowsMouseDragger

package com.gwtsolutions.components.client.ui.dnd;

The DragSourceListener class, which makes callbacks to drag sources and drop targets as a widget is dragged, is listed in Listing 6.15.

Listing 6.15 com.gwtsolutions.components.client.ui.dnd.DragSourceListener

This is where most of the heavy lifting in the dnd module occurs. On a mouse down event, onMouseDown() finds all the drop targets in the drag source's enclosing absolute panel and stores them in an instance of WidgetCollection for further reference. That method also stores the drag source's location and invokes its startDragging method.

When the drag source is dragged, onMouseMove() checks to see if the drag source intersects one of the drop targets discovered in onMouseDown(); if so, it sets the drag source's enclosingDropTarget property and informs the drop target that a drag source has entered. If the drag source does not intersect a drop target but currently has an enclosing drop target, the listener informs the drop target that the drag source has exited and sets the drag source's enclosingDropTarget property to null.

When a drag source is dropped, either inside or outside a drop target, onMouseUp() informs both the drag source and drop target of the event.

Finally, notice that in onMouseEnter(), we call GWT's DOM.addEventPreview method to add an event preview to the top of the JavaScript event stack to prevent the browser from reacting to mouse drags. If we don't do that, then when a user drags an image, the browser will drag around an outline of the image as the user drags the mouse. It will not drag the image itself. Without that event preview, our drag and drop turns into mush (you might want to try removing the event preview and see the results for yourself). Subsequently, onMouseLeave() removes the event preview so that event handling returns to normal. See "Overriding a Pop-Up Panel's Default Event Handling Behavior" (page 211) for a more in-depth discussion of DOM.addEventPreview() and DOM.eventPreventDefault().

Returns the widget's parent widget. This method returns null for the root panel and for widgets whose DOM elements have not yet been added to the DOM tree.

One final detail of our drag-and-drop module: The DragSourceListener class uses instances of the Component module's Point class, which is listed in Listing 6.16.

Listing 6.16 com.gwtsolutions.components.client.ui.Point

Stuff We Covered in This Solution

GWT gives us all the tools we need to achieve drag and drop, and now that you have the code discussed in this solution, you don't have to do it yourself. With that code in hand, it's easy to use drag and drop in your own applications by developing the appropriate drag sources and drop targets, which can enclose any GWT widget, and then adding them to an absolute panel.

Apart from drag and drop itself, we've also explored some interesting corners of GWT, such as creating a GWT module to encapsulate reusable code, changing a widget's cursor, capturing and releasing events for a specific widget, and using event previews to inhibit the browser's reactions to events. That knowledge will come in handy as you create your own components, whether or not they are related to drag and drop.

Implement Drag and Drop in Your Web Apps

Printed with permission from from the book Google Web Toolkit Solutions: More Cool & Useful Stuff written by David Geary and Rob Gordon. ISBN 0132344815 • Copyright © 2007 Prentice Hall.

Digg This Add to