Enhanced JavaScript Bridge, Eclipse Galileo Feature #9

Enhanced JavaScript Bridge, Eclipse Galileo Feature #9

With Eclipse 3.5 — Galileo — just around the corner, I am counting down the top 10 features I’m most excited about.  Number 9 on my list is the improved Java 2 Javascript bridge available in the SWT Browser widget.  The SWT Browser now supports both calling Javascript from Java and calling Java from Javascript.  Leveraging the growing number of “Web Widgets” (Google maps for example) in your rich client applications is now very easy.

where_am_i

By tightly integrating the contents of the browser with the application, you can properly respond to events and update the UI accordingly.  For example, if you resize the window, the map can be resized and Google Maps updates the controls automatically.  Also, when you click Where Am I, the location at the center of the map is recorded in an SWT List widget.

where_am_i_2

The code for this is quite simple and the SWT team has even provided snippet 307 and 308 to help you get started.

Kudos for this feature goes out to Grant Gayed.

The code for my example is below:

package org.eclipse.swt.snippets;

import java.io.File;
import java.io.IOException;

import org.eclipse.swt.SWT;
import org.eclipse.swt.SWTError;
import org.eclipse.swt.browser.Browser;
import org.eclipse.swt.browser.BrowserFunction;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.ControlEvent;
import org.eclipse.swt.events.ControlListener;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.List;
import org.eclipse.swt.widgets.Shell;

public class Snippet308 {

 static List list;
 static Browser browser;
 public static void main(String [] args) throws IOException {
    File f = new File("map.html");
    Display display = new Display();
    final Shell shell = new Shell(display);
    shell.setLayout(new FillLayout());
    SashForm sash = new SashForm(shell, SWT.HORIZONTAL);

    try {
        browser = new Browser(sash, SWT.MOZILLA);
        browser.addControlListener(new ControlListener() {

          public void controlResized(ControlEvent e) {
              browser.execute("document.getElementById('map_canvas').style.width= "+ (browser.getSize().x - 20) + ";");
              browser.execute("document.getElementById('map_canvas').style.height= "+ (browser.getSize().y - 20) + ";");
          }

          public void controlMoved(ControlEvent e) {
          }
	});
    } catch (SWTError e) {
        System.out.println("Could not instantiate Browser: " + e.getMessage());
        display.dispose();
        return;
    }

    new CustomFunction (browser, "theJavaFunction");

    Composite c = new Composite(sash, SWT.BORDER);
    c.setLayout(new GridLayout(1, true));
    Button b = new Button(c, SWT.PUSH);
    list = new List(c, SWT.BORDER | SWT.V_SCROLL | SWT.H_SCROLL);
    list.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true));
    b.setText("Where Am I ?");
    b.addSelectionListener(new SelectionAdapter() {
        public void widgetSelected(SelectionEvent e) {
            double lat = ((Double) browser.evaluate("return map.getCenter().lat();")).doubleValue();
            double lng = ((Double) browser.evaluate("return map.getCenter().lng();")).doubleValue();
            list.add(lat + " : " + lng);
        }
    });

    browser.setUrl(f.toURI().toString());
    sash.setWeights(new int[] {4,1});
    shell.open();

    while (!shell.isDisposed()) {
        if (!display.readAndDispatch())
            display.sleep();
    }
    display.dispose();
 }

 static class CustomFunction extends BrowserFunction {
    Browser browser = null;
    CustomFunction (Browser browser, String name) {
        super (browser, name);
        this.browser = browser;
    }
    public Object function (Object[] arguments) {
        double lat = ((Double) arguments[0]).doubleValue();
        double lng = ((Double) arguments[1]).doubleValue();
        list.add(lat + " : " + lng);
        browser.execute("document.getElementById('map_canvas').style.width= "+ (browser.getSize().x - 20) + ";");
        browser.execute("document.getElementById('map_canvas').style.height= "+ (browser.getSize().y - 20) + ";");
        return null;
    }
 }
}

The map.html file is here:


    
    
9 Comments
  • Peter Kirschner
    Reply
    Posted at 12:56 pm, June 17, 2009

    Great! I was waiting for this. For those of you who have a portable Firefox or none installed.
    Use “new Browser(sash, SWT.NONE);” instead of “new Browser(sash, SWT.MOZILLA);”

  • Posted at 9:24 pm, June 17, 2009

    I read about this feature but I did not grasp the reach of it. This is seriously cool! Great work Grant Gayed!

  • Mark
    Reply
    Posted at 2:36 am, June 21, 2009

    I like this feature too. Been using it with BIRT reports. 🙂

  • zzeric
    Reply
    Posted at 3:02 am, June 29, 2009

    I got several questions about this Javascript bridge:
    1. On windows platform, when the browser was created as SWT.NONE, it relies on IE core. But on linux, which engine will it rely on?

    2. It seems when the browser was created as SWT.MOZILLA, it doesn’t rely on FireFox but XULRunner, so how can I use the latest features of Firefox 3.5?

    3. Can I use SWT without X11?

  • shudong
    Reply
    Posted at 4:49 pm, September 3, 2009

    on windows platform…
    I tried to create browser as SWT.MOZILLA and tried this feature,
    however, it seems the program always crash…
    but if I use SWT.NONE, it works fine

    0SECTION THREADS subcomponent dump routine
    NULL =================================
    NULL
    1XMCURTHDINFO Current Thread Details
    NULL ———————-
    3XMTHREADINFO “main” TID:0x4009B300, j9thread_t:0x003A5D94, state:R, prio=5
    3XMTHREADINFO1 (native thread ID:0x12CC, native priority:0x5, native policy:UNKNOWN)
    4XESTACKTRACE at org/eclipse/swt/internal/mozilla/XPCOM._JS_EvaluateUCScriptForPrincipals(Native Method)
    4XESTACKTRACE at org/eclipse/swt/internal/mozilla/XPCOM.JS_EvaluateUCScriptForPrincipals(XPCOM.java:161)
    4XESTACKTRACE at org/eclipse/swt/browser/Mozilla.execute(Mozilla.java:1777)
    4XESTACKTRACE at org/eclipse/swt/browser/WebBrowser.createFunction(WebBrowser.java:327)
    4XESTACKTRACE at org/eclipse/swt/browser/BrowserFunction.(BrowserFunction.java:86)
    4XESTACKTRACE at org/eclipse/swt/browser/BrowserFunction.(BrowserFunction.java:75)
    4XESTACKTRACE at com/ibm/html/browser/Main$CustomFunction.(Main.java:71)

  • Ian Bull
    Reply
    Posted at 6:38 pm, September 3, 2009

    I don’t know much about how this is handled on Windows, but I know you need to have XPCom properly setup for SWT.MOZILLA to work. There is some information in the FAQ http://www.eclipse.org/swt/faq.php#howusejavaxpcom. If this fails, you should try the SWT newsgroup.

  • Posted at 10:44 pm, December 1, 2009

    @Ian Finally found the time to try this out. Cool example, thank you very much. Finally I have a tool to get the geocoordinates for any location. 🙂

    @shudong I believe SWT.MOZILLA required XULrunner to be installed.

  • Mat Booth
    Reply
    Posted at 5:19 pm, March 12, 2010

    Hi,

    Is it possible to do this sort of thing in a single-sourced RCP/RAP application?

  • mig
    Reply
    Posted at 11:58 pm, November 10, 2010

    Nice!
    A question, though. What does this line

    mean? Is it essential for the java code to communicate with the javascript in the html?

Post a Comment

Comment
Name
Email
Website