<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>weltermann17</title>
	<atom:link href="http://weltermann17.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://weltermann17.wordpress.com</link>
	<description>it&#039;s just a blog.</description>
	<lastBuildDate>Fri, 31 Jul 2009 08:05:03 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='weltermann17.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>weltermann17</title>
		<link>http://weltermann17.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://weltermann17.wordpress.com/osd.xml" title="weltermann17" />
	<atom:link rel='hub' href='http://weltermann17.wordpress.com/?pushpress=hub'/>
		<item>
		<title>jit + gwt: MouseOverLabelEvent/MouseOutLabelEvent</title>
		<link>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-mouseoverlabeleventmouseoutlabelevent/</link>
		<comments>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-mouseoverlabeleventmouseoutlabelevent/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 20:12:57 +0000</pubDate>
		<dc:creator>weltermann17</dc:creator>
				<category><![CDATA[jit with gwt]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[jit]]></category>

		<guid isPermaLink="false">http://weltermann17.wordpress.com/?p=71</guid>
		<description><![CDATA[These event types were added to enable easy &#8220;tooltip&#8221; or &#8220;show details when hovering over jit labels&#8221; implementation. Their usage was described in the previous post. Before you complain, I&#8217;ll add a link to download the entire package plus samples in the next couple of days. import com.google.gwt.event.shared.HandlerRegistration; import com.google.gwt.event.shared.HasHandlers; public interface HasMouseOutLabelHandlers extends HasHandlers [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=71&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>These event types were added to enable easy &#8220;tooltip&#8221; or &#8220;show details when hovering over jit labels&#8221; implementation. Their usage was described in the <a href="http://weltermann17.wordpress.com/2009/07/07/jit-gwt-event-handling-update/">previous post</a>.</p>
<p>Before you complain, I&#8217;ll add a link to download the entire package plus samples in the next couple of days.</p>
<pre>import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;

public interface HasMouseOutLabelHandlers extends HasHandlers {

    HandlerRegistration addMouseOutLabelHandler(MouseOutLabelHandler handler);

}

import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;

public interface HasMouseOverLabelHandlers extends HasHandlers {

    HandlerRegistration addMouseOverLabelHandler(MouseOverLabelHandler handler);

}

import com.google.gwt.event.shared.EventHandler;

public interface MouseOutLabelHandler extends EventHandler {

    void onMouseOutLabel(MouseOutLabelEvent event);

}

import com.google.gwt.event.shared.EventHandler;

public interface MouseOverLabelHandler extends EventHandler {

    void onMouseOverLabel(MouseOverLabelEvent event);

}

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.HasNativeEvent;
import com.google.gwt.event.shared.GwtEvent;

public class MouseOutLabelEvent extends GwtEvent&lt;MouseOutLabelHandler&gt; implements HasNativeEvent {

    protected MouseOutLabelEvent(NativeEvent nativeevent) {
	this.nativeevent = nativeevent;
    }

    public static Type getType() {
	return TYPE;
    }

    public static void fire(HasMouseOutLabelHandlers source, NativeEvent nativeevent) {
	source.fireEvent(new MouseOutLabelEvent(nativeevent));
    }

    @Override
    protected void dispatch(MouseOutLabelHandler handler) {
	handler.onMouseOutLabel(this);
    }

    @Override
    public final Type getAssociatedType() {
	return TYPE;
    }

    @Override
    public NativeEvent getNativeEvent() {
	return nativeevent;
    }

    private static Type&lt;MouseOutLabelHandler&gt; TYPE = new Type&lt;MouseOutLabelHandler&gt;();
    private final NativeEvent nativeevent;

}

import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.dom.client.HasNativeEvent;
import com.google.gwt.event.shared.GwtEvent;

public class MouseOverLabelEvent extends GwtEvent&lt;MouseOverLabelHandler&gt; implements HasNativeEvent {

    protected MouseOverLabelEvent(NativeEvent nativeevent) {
	this.nativeevent = nativeevent;
    }

    public static Type getType() {
	return TYPE;
    }

    public static void fire(HasMouseOverLabelHandlers source, NativeEvent nativeevent) {
	source.fireEvent(new MouseOverLabelEvent(nativeevent));
    }

    @Override
    protected void dispatch(MouseOverLabelHandler handler) {
	handler.onMouseOverLabel(this);
    }

    @Override
    public final Type getAssociatedType() {
	return TYPE;
    }

    @Override
    public NativeEvent getNativeEvent() {
	return nativeevent;
    }

    private static Type&lt;MouseOverLabelHandler&gt; TYPE = new Type&lt;MouseOverLabelHandler&gt;();
    private final NativeEvent nativeevent;

}</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/weltermann17.wordpress.com/71/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/weltermann17.wordpress.com/71/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/weltermann17.wordpress.com/71/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=71&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-mouseoverlabeleventmouseoutlabelevent/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/761f7115ab875b233a05530f95977330?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">weltermann17</media:title>
		</media:content>
	</item>
		<item>
		<title>jit + gwt: event handling update</title>
		<link>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-event-handling-update/</link>
		<comments>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-event-handling-update/#comments</comments>
		<pubDate>Tue, 07 Jul 2009 19:52:17 +0000</pubDate>
		<dc:creator>weltermann17</dc:creator>
				<category><![CDATA[jit with gwt]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[jit]]></category>

		<guid isPermaLink="false">http://weltermann17.wordpress.com/?p=64</guid>
		<description><![CDATA[I said in my recent post jit + gwt: a low-cost solution that the new event system of gwt 1.6 is &#8220;neat&#8221;. Well, I wasn&#8217;t neat enough for it. The way I implemented the event ClickLabelEvent resulted in all clicks on any type of Widget with gwt would now fire a ClickLabelEvent instead of the [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=64&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>I said in my recent post <a href="http://weltermann17.wordpress.com/2009/07/02/jit-gwt-a-low-cost-solution-2/">jit + gwt: a low-cost solution</a> that the new event system of gwt 1.6 is &#8220;neat&#8221;. Well, I wasn&#8217;t neat enough for it. The way I implemented the event ClickLabelEvent resulted in all clicks on any type of Widget with gwt would now fire a ClickLabelEvent instead of the original ClickEvent.</p>
<p>The problem was that ClickLabelEvent extended DomEvent and its Type was <code>new Type("click", new ClickLabelEvent())</code>. This line overshadows the original &#8220;click&#8221; event implementation and fires a ClickLabelEvent from now on. I list the wrong implementation below followed by the corrected code. I updated the original post to show the corrected code. The correct implementation is to extend GwtEvent, thus, ClickLabelEvent is not a native event anymore. In order to instantiate this event type it it&#8217;s necessary to add a <code>static void fire(HasClickLabelHandlers source, boolean rightclick)</code> method to the class. This method is used in the &#8220;glue code&#8221; that converts native events into gwt + jit events (JitWidget.forwardEvent, see below).</p>
<h5>Wrong implementation:</h5>
<pre>import com.google.gwt.event.dom.client.DomEvent;

public class ClickLabelEvent extends DomEvent {

    protected ClickLabelEvent() {
    }

    public static Type getType() {
	return TYPE;
    }

    @Override
    protected void dispatch(ClickLabelHandler handler) {
	int x = this.getNativeEvent().getScreenX();
	int y = this.getNativeEvent().getScreenY();
	if (1000000 == x &amp;&amp; 0 == y) {
	    handler.onClickLabel(this);
	} else if (0 == x &amp;&amp; 1000000 == y) {
	    handler.onRightClickLabel(this);
	}
    }

    @Override
    public final Type getAssociatedType() {
	return TYPE;
    }

    private static Type TYPE = new Type("click", new ClickLabelEvent());

}</pre>
<h5>Corrected implementation:import com.google.gwt.event.shared.GwtEvent;</h5>
<pre>public class ClickLabelEvent extends GwtEvent&lt;ClickLabelHandler&gt; {

    protected ClickLabelEvent(boolean rightclick) {
	this.rightclick = rightclick;
    }

    public static Type getType() {
	return TYPE;
    }

    public static void fire(HasClickLabelHandlers source, boolean rightclick) {
	ClickLabelEvent event = new ClickLabelEvent(rightclick);
	source.fireEvent(event);
    }

    @Override
    protected void dispatch(ClickLabelHandler handler) {
	if (rightclick) {
	    handler.onRightClickLabel(this);
	} else {
	    handler.onClickLabel(this);
	}
    }

    @Override
    public final Type getAssociatedType() {
	return TYPE;
    }

    private final boolean rightclick;
    private static Type TYPE&lt;ClickLabelHandler&gt; = new Type&lt;ClickLabelHandler&gt;();
}</pre>
<h5>Glue code:</h5>
<pre>public abstract class JitWidget extends Widget implements ResizeHandler, HasClickLabelHandlers,
	HasMouseOverLabelHandlers, HasMouseOutLabelHandlers {
  ...
   @SuppressWarnings("unused")
    private final static void forwardEvent(String name, JavaScriptObject event, JavaScriptObject label,
            JavaScriptObject node) {
	NativeEvent received = (NativeEvent) (null == event ? null : event.cast());
	Document document = Document.get();
	JitWidget jit = jitgwtwrappers.get(name);
	jit.setClickedLabel(label);
	jit.setClickedNode(node);
	String type = null == received ? "click" : received.getType();
	if ("click".equals(type)) {
	    JSONObject nodeobject = new JSONObject(node);
	    String nodeid = nodeobject.get("id").toString();
	    nodeid = nodeid.substring(1, nodeid.length() - 1);
	    History.newItem(name + ";" + nodeid);
	    ClickLabelEvent.fire(jit, false);
	} else if ("contextmenu".equals(type)) {
	    ClickLabelEvent.fire(jit, true);
	} else if ("mouseover".equals(type)) {
	    MouseOverLabelEvent.fire(jit, received);
	} else if ("mouseout".equals(type)) {
	    MouseOutLabelEvent.fire(jit, received);
	} else {
	    GWT.log("not handled: " + type, null);
	}
    }</pre>
<p>The glue code shows that I also added handling of two more event types to the class JitWidget: MouseOverLabelEvent and MouseOutLabelEvent.</p>
<p>Similar to ClickLabelEvent they are fired when the mouse is moved over or out of a label in a jit visualization. With these events it&#8217;s very easy to add a &#8220;ToolTip&#8221; hint to a label when you hover the mouse over it. Unlike some other implementations this only adds a tooltip for the &#8220;current&#8221; label which should show better performance.</p>
<h5>Sample for &#8220;ToolTip&#8221;:</h5>
<pre>   public void onModuleLoad() {
   ...
	spacetree.addMouseOverLabelHandler(this);
	spacetree.addMouseOutLabelHandler(this);
   ...
   @Override
    public void onMouseOverLabel(MouseOverLabelEvent event) {
	JitWidget jit = (JitWidget) event.getSource();
	JSONObject json = new JSONObject(jit.getClickedNode());
	PopupPanel popup= new DecoratedPopupPanel();
	StringBuilder b = new StringBuilder();
	for (String k : json.keySet()) {
	    b.append(k);
	    b.append(" : ");
	    b.append(json.get(k).isString());
	    b.append("");
	}
	popup.setWidth("200px");
	popup.setWidget(new HTML(b.toString()));
	int x = event.getNativeEvent().getClientX();
	int y = event.getNativeEvent().getClientY();
	tooltip = new ToolTip(2000, popup, x, y); // show popup after 2000ms, if not cancelled
    }

    @Override
    public void onMouseOutLabel(MouseOutLabelEvent event) {
	tooltip.cancel();
    }</pre>
<p>This code uses a small helper class called &#8220;ToolTip&#8221;:</p>
<pre>import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.RootPanel;

public class ToolTip extends Timer {

    public ToolTip(int delay, PopupPanel popup, int x, int y) {
	this.popup = popup;
	this.x = x + 32;
	this.y = y + 32;
	schedule(delay);
	scheduled = true;
    }

    @Override
    public void run() {
	popup.setPopupPosition(x, y);
	popup.show();
	int w = popup.getOffsetWidth();
	int h = popup.getOffsetHeight();
	x = x + Math.min(0, RootPanel.get().getOffsetWidth() - 32 - (x + w));
	y = y + Math.min(0, RootPanel.get().getOffsetHeight() - 32 - (y + h));
	popup.setPopupPosition(x, y);
    }

    @Override
    public void cancel() {
	if (scheduled) {
	    scheduled = false;
	    super.cancel();
	    popup.hide();
	}
    }

    private final PopupPanel popup;
    private boolean scheduled = false;
    private int x;
    private int y;

}</pre>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/weltermann17.wordpress.com/64/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/weltermann17.wordpress.com/64/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/weltermann17.wordpress.com/64/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=64&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://weltermann17.wordpress.com/2009/07/07/jit-gwt-event-handling-update/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/761f7115ab875b233a05530f95977330?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">weltermann17</media:title>
		</media:content>
	</item>
		<item>
		<title>jit + gwt: Screenshot of a sample with 2 SpaceTrees</title>
		<link>http://weltermann17.wordpress.com/2009/07/03/jit-gwt-screenshot-of-a-sample-with-2-spacetrees/</link>
		<comments>http://weltermann17.wordpress.com/2009/07/03/jit-gwt-screenshot-of-a-sample-with-2-spacetrees/#comments</comments>
		<pubDate>Fri, 03 Jul 2009 11:35:29 +0000</pubDate>
		<dc:creator>weltermann17</dc:creator>
				<category><![CDATA[jit with gwt]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[jit]]></category>

		<guid isPermaLink="false">http://weltermann17.wordpress.com/?p=51</guid>
		<description><![CDATA[Here&#8217;s a screenshot of a gwt ui using JitWidget with two SpaceTrees.<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=51&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>Here&#8217;s a screenshot of a gwt ui using JitWidget with two SpaceTrees.</p>
<p><a href="http://weltermann17.files.wordpress.com/2009/07/jit_gwt_sample_12.png"><img class="alignnone size-thumbnail wp-image-53" title="jit_gwt_sample_1" src="http://weltermann17.files.wordpress.com/2009/07/jit_gwt_sample_12.png?w=150&#038;h=93" alt="jit_gwt_sample_1" width="150" height="93" /></a></p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/weltermann17.wordpress.com/51/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/weltermann17.wordpress.com/51/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/weltermann17.wordpress.com/51/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=51&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://weltermann17.wordpress.com/2009/07/03/jit-gwt-screenshot-of-a-sample-with-2-spacetrees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/761f7115ab875b233a05530f95977330?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">weltermann17</media:title>
		</media:content>

		<media:content url="http://weltermann17.files.wordpress.com/2009/07/jit_gwt_sample_12.png?w=150" medium="image">
			<media:title type="html">jit_gwt_sample_1</media:title>
		</media:content>
	</item>
		<item>
		<title>jit + gwt: a low-cost solution</title>
		<link>http://weltermann17.wordpress.com/2009/07/02/jit-gwt-a-low-cost-solution-2/</link>
		<comments>http://weltermann17.wordpress.com/2009/07/02/jit-gwt-a-low-cost-solution-2/#comments</comments>
		<pubDate>Thu, 02 Jul 2009 21:37:00 +0000</pubDate>
		<dc:creator>weltermann17</dc:creator>
				<category><![CDATA[jit with gwt]]></category>
		<category><![CDATA[gwt]]></category>
		<category><![CDATA[jit]]></category>

		<guid isPermaLink="false">http://weltermann17.wordpress.com/?p=23</guid>
		<description><![CDATA[jit (JavaScript InfoVis Toolkit) and gwt (Google Web Toolkit) are both powerful and elegant libraries to create browser based user interfaces. jit offers a number of really cool graph visualizations that can be easily customized with Javascript and CSS. gwt is a dream for Java and J2EE developers facing the RIA challange come true. So [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=23&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<p>jit <a href="http://thejit.org/">(JavaScript InfoVis Toolkit)</a> and gwt <a href="http://code.google.com/webtoolkit/">(Google Web Toolkit)</a> are both powerful and elegant libraries to create browser based user interfaces. jit offers a number of really cool graph visualizations that can be easily customized with Javascript and CSS. gwt is a dream for Java and J2EE developers facing the RIA challange come true. So why not combine both?</p>
<p>According to the <a href="http://groups.google.com/group/javascript-information-visualization-toolkit/browse_thread/thread/7788da3fd7c1dc42">jit discussion group</a> there is not yet a plug-and-play solution for this. A development of a gwt extension <a href="http://code.google.com/p/gwt-graph/">gwt-graph</a> has just started. This looks very promising as it aims at fully wrapping the functionality of jit in gwt.</p>
<p>Because I needed to find a way to embed one or more Spacetrees into a gwt ui quickly in the last couple of days I came up with a very low-cost solution for jit + gwt that I would like to outline here.</p>
<p>Main goals for my solution were:</p>
<ul>
<li>write as little code as possbile</li>
<li>only wrap the jit objects where necessary to treat them like gwt objects where possible</li>
<li>make the jit objects act like gwt widgets so they can be dropped anywhere in a gwt ui</li>
<li>make it possible to drop more than one jit visualization into a gwt ui</li>
<li>let the jit objects react on resize automatically</li>
<li>let the jit objects easily interact with the gwt event system</li>
<li>concentrate on the jit Spacetree, but make it easy to implement the others as well</li>
</ul>
<p>These few classes implement the solution:</p>
<ul>
<li>interface ClickLabelHandler extends EventHandler (onClickLabel/onRightClickLabel)</li>
<li>class ClickLabelEvent extends DomEvent&lt;ClickLabelHandler&gt;</li>
<li>interface HasClickLabelHandlers extends HasHandlers</li>
<li>abstract class JitWidget extends Widget implements ResizeHandler, HasClickLabelHandlers</li>
<li>class SpaceTree extends JitWidget</li>
</ul>
<p>You find the code for the classes further down, but let&#8217;s first look at how to use them:</p>
<pre>    public void onModuleLoad() {
	Window.addResizeHandler(this);
	Window.enableScrolling(false);
	Window.setMargin("0px");
	History.addValueChangeHandler(this);
        // ... layout your gwt ui

        scrollPanel = new ScrollPanel();
	scrollPanel.setSize("100%", "100%");
	int w = scrollPanel.getOffsetWidth();
	int h = scrollPanel.getOffsetHeight();
	simplePanel = new SimplePanel();
	simplePanel.setPixelSize((int) (w * 1.33), (int) (h * 1.33));
	scrollPanel.add(simplePanel);
	scrollPanel.setPixelSize(w, h);

        // simplePanel will be the container for our SpaceTree, it will fill it up 100%
	spacetree = new SpaceTree("myspacetree", config("myspacetree"));
	spacetree.addClickLabelHandler(this);
	spacetree.addMouseOverLabelHandler(this);
	spacetree.addMouseOutLabelHandler(this);
	simplePanel.add(spacetree);
	DeferredCommand.addCommand(new Command() {
	    public void execute() {
		loadAndDisplay("myspacetree", dataset());
	    }
	});
    }

    private native JavaScriptObject config(String name) /*-{
        return {
        orientation: 'left',
        duration: 333,
        fps: 25,
        levelDistance: 32,
        levelsToShow: 5,
        Node: {
            width: 160,
            height: 20,
            type: 'rectangle',
            color: '#7aa',
            overridable: true },
        Edge: {
            type: 'bezier',
            overridable: true },
        onCreateLabel: function(label, node) {
            label.id = node.id;
            if (0 &lt; node.data.childcount &amp;&amp; !node.selected) {
            	label.innerHTML = node.name + "  " + node.data.childcount;
            	node.data.$color = "#aa7";
            } else {
            	label.innerHTML = node.name;
            	delete node.data.$color;
            }
            var forwardEvent = function(event) {
                jitWrapperForwardEvent(name, event || $wnd.event, label, node); };
            label.onclick = function(event) {
                jitWrappedObject(name).onClick(node.id);
                forwardEvent(event); };
            label.oncontextmenu = forwardEvent;
            label.onmouseover = forwardEvent;
            label.onmouseout = forwardEvent;
            var style = label.style;
            style.display = 'block';
            style.width = '160px';
            style.height ='20px';
            style.cursor = 'pointer';
            style.color = '#222';
            style.fontSize = '0.7em';
            style.textAlign= 'left';
            style.paddingTop = '2px';
            style.paddingLeft = '2px';
        },
        onBeforePlotNode: function(node){
            if (node.selected) {
                node.data.$color = "#ff7";
            } else {
                delete node.data.$color;
            }
        },
        onBeforePlotLine: function(adj){
            if (adj.nodeFrom.selected &amp;&amp; adj.nodeTo.selected) {
                adj.data.$color = "#44d";
                adj.data.$lineWidth = 1.2;
            } else {
                delete adj.data.$color;
                delete adj.data.$lineWidth;
            }
        }
        }
    }-*/;

    private native void loadAndDisplay(String name, JavaScriptObject json)  /*-{
        var jit = jitWrappedObject(name);
        jit.loadJSON(json);
        jit.compute();
        jit.onClick(jit.root);
        jitWrapperOnClick(name, null, json);
    }-*/;

    @Override
    public void onClickLabel(ClickLabelEvent event) {
	JitWidget jit = (JitWidget) event.getSource();
	dump("node", jit.getClickedNode());
    }

    @Override
    public void onRightClickLabel(ClickLabelEvent event) {
	JitWidget jit = (JitWidget) event.getSource();
	dump("label", jit.getClickedLabel());
    }

    @Override
    public void onMouseOverLabel(MouseOverLabelEvent event) {
	JitWidget jit = (JitWidget) event.getSource();
	JSONObject json = new JSONObject(jit.getClickedNode());
	PopupPanel popup= new DecoratedPopupPanel();
	StringBuilder b = new StringBuilder();
	for (String k : json.keySet()) {
	    b.append(k);
	    b.append(" : ");
	    b.append(json.get(k).isString());
	    b.append("");
	}
	popup.setWidth("200px");
	popup.setWidget(new HTML(b.toString()));
	int x = event.getNativeEvent().getClientX();
	int y = event.getNativeEvent().getClientY();
	tooltip = new ToolTip(2000, popup, x, y);
    }

    @Override
    public void onMouseOutLabel(MouseOutLabelEvent event) {
	tooltip.cancel();
    }

    @Override
    public void onValueChange(ValueChangeEvent&lt;String&gt; event) {
	String token = event.getValue();
	String name = token.substring(0, token.indexOf(";"));
	String nodeid = token.substring(token.indexOf(";") + 1);
	clickNode(name, nodeid);
    };

    private native void clickNode(String name, String nodeid) /*-{
        var jit = jitWrappedObject(name);
        jit.onClick(nodeid);
        jit.controller.onAfterCompute();
    }-*/;</pre>
<p>Some comments:</p>
<ul>
<li>a SpaceTree is simply constructed with new SpaceTree(&lt;name&gt;, &lt;method returning the config as JavaScriptObject&gt;)</li>
<li>&lt;name&gt; is very important as it is the reference in JavaScript to retrieve either the jit object or the gwt wrapper of type JitWidget</li>
<li>&lt;config method&gt; will almost always be a native JSNI method that will look very familiar to jit users</li>
<li>&lt;onCreateLabel&gt; (as always) is the key controller function: label.onclick and label.oncontextmenu must be implemented in order to provide a link back from the interactive jit visualization into the gwt event system</li>
<li>jitWrappedObject(name) returns the jit visualization created with new SpaceTree() (in this case an ST); it can then be used to call onClick(), for instance</li>
<li>jitWrapperOnClick(name, label, node) and jitWrapperOnRightClick(&#8230;) propagate the event &#8220;label was clicked&#8221; back into gwt&#8217;s event system which calls all ClickLabelHandlers registered with this JitWidget. The new gwt event system (1.6) is really neat.</li>
<li>JitWiget provides the methods getClickedNode and getClickedLabel to get at their content in the event handlers. This makes it easy to update other ui objects according to the clicked node or create a very specific context menu based on the current node and/or label.</li>
<li>Almost everything else you do with a JitWiget you need to write in JavaScript (e. g. loadAndDisplay()). The trick is to retrieve the jit object first using jitWrappedObject(name) and then use it the way you want. This way it is not necessary to wrap the entire functionality of jit with gwt and Java. It should also make this solution robust against enhancements in either jit or gwt.</li>
</ul>
<h4>Here is the code for all classes:</h4>
<pre>// ----------------------------------------------------------------------

package yourpackage;

import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.event.shared.HasHandlers;

public interface HasClickLabelHandlers extends HasHandlers {

    HandlerRegistration addClickLabelHandler(ClickLabelHandler handler);

}

// ----------------------------------------------------------------------

import com.google.gwt.event.shared.GwtEvent;

public class ClickLabelEvent extends GwtEvent&lt;ClickLabelHandler&gt; {

    protected ClickLabelEvent(boolean rightclick) {
	this.rightclick = rightclick;
    }

    public static Type getType() {
	return TYPE;
    }

    public static void fire(HasClickLabelHandlers source, boolean rightclick) {
	ClickLabelEvent event = new ClickLabelEvent(rightclick);
	source.fireEvent(event);
    }

    @Override
    protected void dispatch(ClickLabelHandler handler) {
	if (rightclick) {
	    handler.onRightClickLabel(this);
	} else {
	    handler.onClickLabel(this);
	}
    }

    @Override
    public final Type getAssociatedType() {
	return TYPE;
    }

    private final boolean rightclick;
    private static Type&lt;ClickLabelHandler&gt; TYPE = new Type&lt;ClickLabelHandler&gt;();

}

// ----------------------------------------------------------------------

import java.util.LinkedHashMap;
import java.util.Map;

import com.google.gwt.core.client.GWT;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Document;
import com.google.gwt.dom.client.NativeEvent;
import com.google.gwt.event.logical.shared.ResizeEvent;
import com.google.gwt.event.logical.shared.ResizeHandler;
import com.google.gwt.event.shared.HandlerRegistration;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.History;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.Widget;

public abstract class JitWidget extends Widget implements ResizeHandler, HasClickLabelHandlers,
	HasMouseOverLabelHandlers, HasMouseOutLabelHandlers {

    public JitWidget(String name, JavaScriptObject config) {
	this.name = name;
	this.config = config;
	final Element domelement = DOM.createElement("div");
	DOM.setElementProperty(domelement, "id", name);
	setElement(domelement);
	backgroundColor = 0 &lt; DOM.getStyleAttribute(domelement, "backgroundColor").length() ? DOM
		.getStyleAttribute(getElement(), "backgroundColor") : defaultBackgroundColor;
	DOM.setStyleAttribute(domelement, "backgroundColor", backgroundColor);
	jitgwtwrappers.put(name, this);
    }

    public String getName() {
	return name;
    }

    public JavaScriptObject getClickedNode() {
	return node;
    }

    public JavaScriptObject getClickedLabel() {
	return label;
    }

    @Override
    protected void onAttach() {
	setSize("100%", "100%");
	JavaScriptObject canvas = initCanvas(name, getOffsetWidth(), getOffsetHeight(), backgroundColor);
	JavaScriptObject jit = init(canvas, config);
	jitwrappedobjects.put(name, jit);
	super.onAttach();
    }

    @Override
    public void onResize(ResizeEvent event) {
	double width = event.getWidth();
	double height = event.getHeight();
	double percentagex = width / oldWidth;
	double percentagey = height / oldHeight;
	double w = getOffsetWidth() * percentagex;
	double h = getOffsetHeight() * percentagey;
	setPixelSize((int) w, (int) h);
	resize(name, w, h);
    }

    protected abstract JavaScriptObject init(JavaScriptObject canvas, JavaScriptObject config);

    private final native JavaScriptObject initCanvas(String name, double w, double h, String bcolor) /*-{
        return new $wnd.Canvas(name + '_canvas', {
           'injectInto': name,
           'width': w,
           'height': h,
           'backgroundColor': bcolor});
    }-*/;

    private final native void resize(String name, double w, double h) /*-{
        var jit = jitWrappedObject(name);
        jit.canvas.resize(w, h);
        jit.refresh();
        jit.controller.onAfterCompute();
    }-*/;

    public final static void resizeAll(ResizeEvent event) {
	for (JitWidget jit : jitgwtwrappers.values()) {
	    jit.onResize(event);
	}
	oldWidth = event.getWidth();
	oldHeight = event.getHeight();
    }

    @Override
    public HandlerRegistration addClickLabelHandler(ClickLabelHandler handler) {
	return addHandler(handler, ClickLabelEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseOverLabelHandler(MouseOverLabelHandler handler) {
	return addHandler(handler, MouseOverLabelEvent.getType());
    }

    @Override
    public HandlerRegistration addMouseOutLabelHandler(MouseOutLabelHandler handler) {
	return addHandler(handler, MouseOutLabelEvent.getType());
    }

    private final void setClickedNode(JavaScriptObject node) {
	this.node = node;
    }

    private final void setClickedLabel(JavaScriptObject label) {
	this.label = label;
    }

    @SuppressWarnings("unused")
    private final static JavaScriptObject getWrappedObject(String name) {
	return jitwrappedobjects.get(name);
    }

    @SuppressWarnings("unused")
    private final static void forwardEvent(String name, JavaScriptObject event, JavaScriptObject label,
	    JavaScriptObject node) {
	NativeEvent received = (NativeEvent) (null == event ? null : event.cast());
	Document document = Document.get();
	JitWidget jit = jitgwtwrappers.get(name);
	jit.setClickedLabel(label);
	jit.setClickedNode(node);
	String type = null == received ? "click" : received.getType();
	if ("click".equals(type)) {
	    JSONObject nodeobject = new JSONObject(node);
	    String nodeid = nodeobject.get("id").toString();
	    nodeid = nodeid.substring(1, nodeid.length() - 1);
	    History.newItem(name + ";" + nodeid);
	    ClickLabelEvent.fire(jit, false);
	} else if ("contextmenu".equals(type)) {
	    ClickLabelEvent.fire(jit, true);
	} else if ("mouseover".equals(type)) {
	    MouseOverLabelEvent.fire(jit, received);
	} else if ("mouseout".equals(type)) {
	    MouseOutLabelEvent.fire(jit, received);
	} else {
	    GWT.log("not handled: " + type, null);
	}
    }

    private final static native void exportToJavaScript() /*-{
        jitWrappedObject = @yourpackage.JitWidget::getWrappedObject(Ljava/lang/String;);
        jitWrapperForwardEvent = @yourpackage.JitWidget::forwardEvent(Ljava/lang/String;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;Lcom/google/gwt/core/client/JavaScriptObject;);
    }-*/;

    static {
	exportToJavaScript();
	oldWidth = Window.getClientWidth();
	oldHeight = Window.getClientHeight();
    }

    private final String name;
    private final JavaScriptObject config;
    private final String backgroundColor;
    private JavaScriptObject node;
    private JavaScriptObject label;
    private static final String defaultBackgroundColor = "#fff";
    private static final Map jitwrappedobjects = new LinkedHashMap();
    private static final Map jitgwtwrappers = new LinkedHashMap();
    private static double oldWidth;
    private static double oldHeight;

}

// ----------------------------------------------------------------------

import com.google.gwt.core.client.JavaScriptObject;

public class SpaceTree extends JitWidget {

    public SpaceTree(String name, JavaScriptObject config) {
	super(name, config);
    }

    @Override
    protected native JavaScriptObject init(JavaScriptObject canvas, JavaScriptObject config) /*-{
        return new $wnd.ST(canvas, config);
    }-*/;

}</pre>
<p>In every ui library I know automatic resizing is a pain. With jit+gwt there is no exception. As this is not yet working 100% I will describe the resize mechanism in a follow-up post.</p>
<br />  <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/weltermann17.wordpress.com/23/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/weltermann17.wordpress.com/23/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/weltermann17.wordpress.com/23/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=weltermann17.wordpress.com&amp;blog=8416602&amp;post=23&amp;subd=weltermann17&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://weltermann17.wordpress.com/2009/07/02/jit-gwt-a-low-cost-solution-2/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/761f7115ab875b233a05530f95977330?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">weltermann17</media:title>
		</media:content>
	</item>
	</channel>
</rss>
