Things To Remember: GWT Drag and Drop Edition

So I wrote the following code and wired it into the mouse up, down and move listeners so I can do drag and drop:

		@Override
		public void onMouseUp(MouseUpEvent event)
		{
			isDragging = false;
			// Do something to indicate we're done dragging
			
			DOM.releaseCapture(fClickLayer.getElement());
		}
		
		@Override
		public void onMouseMove(MouseMoveEvent event)
		{
			if (isDragging) {
				// Do something with the event to drag
			}
		}

		@Override
		public void onMouseDown(MouseDownEvent event)
		{
			DOM.setCapture(fClickLayer.getElement());
			// Note the initial state to start dragging
		}

And of course after the first three move events I stopped receiving move events, but instead the widget would be selected.

After banging my head against a brick wall for a couple of hours I realized I needed to prevent the browser from taking the default behavior on the received click and move events. And that’s done with the preventDefault() method:

		@Override
		public void onMouseUp(MouseUpEvent event)
		{
			isDragging = false;
			// Do something to indicate we're done dragging
			
			DOM.releaseCapture(fClickLayer.getElement());
		}
		
		@Override
		public void onMouseMove(MouseMoveEvent event)
		{
			if (isDragging) {
				event.preventDefault();		// ADD ME HERE
				// Do something with the event to drag
			}
		}

		@Override
		public void onMouseDown(MouseDownEvent event)
		{
			DOM.setCapture(fClickLayer.getElement());
			event.preventDefault();		// ADD ME HERE
			// Note the initial state to start dragging
		}

Duh.

As an aside, here’s a snippet of code that you can use to prevent something from being selected in HTML. You can also do this in CSS, I suppose. I encountered this snippet of code here.

	private native static void disableSelectInternal(Element e, boolean disable) 
	/*-{
    	if (disable) {
        	e.ondrag = function () { return false; };
        	e.onselectstart = function () { return false; };
        	e.style.MozUserSelect="none"
    	} else {
        	e.ondrag = null;
        	e.onselectstart = null;
        	e.style.MozUserSelect="text"
    	}
	}-*/;

I first tried hooking this up to the class receiving the mouse events, but to no avail.

Snippets of GWT

Strategy for validating text input in a TextBox during input:

One way to validate that the string being entered into a text box is properly formatted is to reject key changes as the user types, if the resulting string would result in an invalid string. The strategy I’m employing is to add a key press handler and schedule a deferred command: the deferred command then reverts the contents of the text box if the contents are illegal.

Thus:

public class TestEditorBox extends TextBox
{
    public TestEditorBox()
    {
        super();
        
        /*
         * Hang handler off key press; process and revert text of it doesn't
         * look right
         */
        addKeyPressHandler(new KeyPressHandler() {
            @Override
            public void onKeyPress(KeyPressEvent event)
            {
                final String oldValue = getText();
                Scheduler.get().scheduleDeferred(new Scheduler.ScheduledCommand() {
                    @Override
                    public void execute()
                    {
                        String curVal = getText();
                        if (!validate(curVal)) setText(oldValue);
                    }
                });
            }
        });
    }

    private boolean validate(String value)
    {
         // return true if the string is valid, false if not.
    }
...
}

GWT Weirdness Of The Day.

On the project I’m working on, I noticed that, for whatever reason, it was now taking up to 3 minutes to start a web site running under GWT. That is, from hitting the “Debug” button and opening the web site in the browser, to seeing the web site actually up and running, was taking just shy of three minutes, with most of that time with the Spinning Beach Ball Of Death™.

I finally figured out what was happening. The first clue came from hitting ‘pause’ on the Daemon Thread labeled “Code server for myProject from Safari DMP…”, and noticing a lot of time being spent walking around inside the source kit for resources.

And noticing a lot of that time was spent in a bunch of .svn folders.

I think what was going on is that, for some reason or another, a lot of crud had accumulated in a number of random hidden folders associated with subversion. I don’t know if this is normal or abnormal behavior for Subversion; I just know there was a bunch of crap floating around there–and GWT was spending several minutes walking around the directory structure.

Blowing away the entire source kit and checking it all out fresh from Subversion reduced the startup time to less than 5 seconds. And it greatly improved the performance of the browser in the debugger as well: rollovers which were taking a while to get detected now are fast and responsive.

I suspect all the crud in my source directory was creating a lot of crap for the debugger to deal with, creating a substantial slowdown that got cleared right up.

GWT, ScrollPanel and the iPad.

GWT makes it easy to create a scrolling panel within an HTML driven web site, by using the ScrollPanel class. ScrollPanel itself expands into a div tag containing the overflow attribute; specifying which axes the scroll bars land on translate into overflow-x or overflow-y attributes in the generated HTML DOM object.

And the iPad (and iPhone and iPod Touch) do not allow you to scroll within the overflow tags; the touch-drag gesture only scrolls the entire page.

What this means is if you are putting together a GWT application that you want to work on the iPad, the natural instinct to create a root panel the full size of the screen and tossing in a ScrollPanel area in the lower right that resizes with the window is incorrect. Instead, you are better off generating your GWT code so that it generates the properly sized HTML, and scroll around the GWT application using the window’s scroll bars.

Fun with GWT

Upgrading to v2.0 of GWT under Eclipse, here’s some of the things I encountered:

(1) For some reason my old 1.7.1 GWT projects are hopelessly broken; I can’t seem to debug them. Creating a new v2.0 GWT project seems to work fine. And I haven’t a clue as to why my v1.7.1 GWT projects, when I upgrade them to v2.0, refuse to debug: I’ve tried just switching the current GWT SDK, I’ve tried turning off and on GWT, I’ve tried blowing away the debug configurations–I’ve even tried recreating a new GWT project with the same source kit (which did work under v2.0’s debugger environment), then searching for differences.

Nothing.

The only workaround I’ve found is to create a new GWT project, and copy the sources across from the old GWT project.

(2) IE7 support for the new panel layouts is completely broken unless you change the DOCTYPE declaration from:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">

to

<!DOCTYPE HTML>

Beats me why; I’m not into the finer points of HTML compatibility and doctype specifications. But once you make this switch, the new layout panels work as advertised.