Blog

The marriage of GWT with Eclipse-Technologies

I'm currently on the track to explore GWT and started just this morning with it. The first thing I found missing is something like the Viewers-Concept from JFace.

I don't want to learn new things if the one I'm familiar with would make my life much easier. JFace-Viewers is one of my main working areas in Eclipse-land. So I sat down and took a closer look and after 1 hour of work my GWT-code looks like this:

package at.bestsolution.eclipse.jface.example.client;

import java.util.ArrayList;

import org.gwtwidgets.client.util.SimpleDateParser;

import at.bestsolution.eclipse.jface.client.viewers.TreeViewer;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;
import at.bestsolution.eclipse.jface.example.client.ui.MyContentProvider;
import at.bestsolution.eclipse.jface.example.client.ui.MyLabelProvider;

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

/**
  * Entry point classes define <code>onModuleLoad()</code>.
  */
public class JFaceExampleApp implements EntryPoint {
  /**
    * This is the entry point method.
    */
  public void onModuleLoad() {
    Tree tree = new Tree();
    TreeViewer viewer = new TreeViewer(tree);
    viewer.setLabelProvider(new MyLabelProvider());
    viewer.setContentProvider(new MyContentProvider());
    viewer.setInput(createInput());

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

  private ArrayList createInput() {
    SimpleDateParser parser = new SimpleDateParser("yyyy-MM-dd");
    ArrayList list = new ArrayList();
    Family fam = new Family("Schindl");
    Person p = new Person("Tom",parser.parse("1979-05-01"),fam);
    p = new Person("Tina",parser.parse("1980-10-14"),fam);
    p = new Person("Laura",parser.parse("1991-08-07"),fam);
    list.add(fam);

    fam = new Family("Hoppichler");
    p = new Person("Andreas",parser.parse("1977-11-06"),fam);
    p = new Person("Franzi",parser.parse("1978-11-02"),fam);

    list.add(fam);
    return list;
  }
}

And the respective Viewer-classes like this:

package at.bestsolution.eclipse.jface.example.client.ui;

import java.util.ArrayList;

import at.bestsolution.eclipse.jface.client.viewers.ITreeContentProvider;
import at.bestsolution.eclipse.jface.client.viewers.Viewer;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;

public class MyContentProvider implements ITreeContentProvider {
  public Object[] getChildren(Object parentElement) {
    if( parentElement instanceof Family ) {
      return ((Family)parentElement).getList().toArray();
    }
    return new Object[0];
  }

  public Object getParent(Object element) {
    if( element instanceof Person ) {
      return ((Person)element).getFamily();
    }

    return null;
  }

  public boolean hasChildren(Object element) {
    return getChildren(element).length > 0;
  }

  public Object[] getElements(Object inputElement) {
    return ((ArrayList)inputElement).toArray();
  }

  public void dispose() {}

  public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {}
}
package at.bestsolution.eclipse.jface.example.client.ui;

import org.gwtwidgets.client.util.SimpleDateFormat;

import at.bestsolution.eclipse.jface.client.viewers.ILabelProvider;
import at.bestsolution.eclipse.jface.example.client.model.Family;
import at.bestsolution.eclipse.jface.example.client.model.Person;

public class MyLabelProvider implements ILabelProvider {
  private SimpleDateFormat format = new SimpleDateFormat("dd.MM.yyyy");

  public String getText(Object element) {
    if( element instanceof Family ) {
      return ((Family)element).getName();
    } else if( element instanceof Person ) {
      return ((Person)element).getName() + " ("+format.format(((Person)element).getBirthday())+")";
    }

    return "";
  }
}

Now you think this is cool? Because this was to trivial I thought I'll have to go further and after ~ 6h I had ported the the core-parts from the JFace-Databinding-Framework to GWT! So my UI-Binding-Code looks like this now:

// ....
TextBox box = new TextBox();

TextBoxObservableValue targetValue = new TextBoxObservableValue(box,TextBoxObservableValue.Change);
IObservableValue modelValue = PEMFObservablesFactory.observeDetailValue(Realm.getDefault(), value, "id", String.class);

DataBindingContext ctx = new DataBindingContext();
UpdateValueStrategy targetToModel = new UpdateValueStrategy();
targetToModel.setConverter(new IConverter() {
  public Object convert(Object fromObject) {
    return fromObject.toString();
  }

  public Object getFromType() {
    return null;
  }

  public Object getToType() {
    return null;
  }
});

UpdateValueStrategy modelToTarget = new UpdateValueStrategy();
modelToTarget.setConverter(new IConverter() {
  public Object convert(Object fromObject) {
    return fromObject.toString();
  }

  public Object getFromType() {
    return null;
  }

  public Object getToType() {
    return null;
  }
});
ctx.bindValue(targetValue, modelValue, targetToModel, modelToTarget);

The GWT-Compiler translates all into JS-Code and because there's no Reflection-API available in this space I had to invent my own concept which I lend from EMF hence the name PEMF (for PoorEMF). Without question much of the Databinding-Framework is not working but at this stage I don't mind. The good thing is that all those low-level modules use fairly only classes already available from GWT so porting the whole framework is only a matter of time.

published on
Previous
Doing RCP-Like programming with GWT