One month of UFacekit-Development


A month ago James Strachan and I started hacking on a project we named UFacekit.

We both faced the need to write datacentric applications for different deployment environments (Desktop (Swing/SWT), GWT (MyGWT/GWT-Ext), …) and we thought there must be an easy and fast way to come up with something that makes our day job easier. At this very moment UFacekit was born.

There are different things we are targeting with the project.

  1. Provide a uniform Facade above widget implementations (SWT,Swing,GWT,…)
  2. Promote the use of Eclipse-Databinding (and other related technologies e.g. EMF) outside Eclipse-World (Swing,GWT, …) and provide a highlevel API above the low-level databinding API
  3. Provide reuseable Bundles which can be used independently
    • you are only interested in Swing-Databinding but still want to use the native Swing-API? – UFacekit provides an indepented Swing-Observable bundle for you
    • you want to use an alternative Bean-like implementation not relying on reflection and EMF is too heavy for you? – UFacekit provides an independent implementation for you named UBean

Instead of writing an SWT-Port for GWT/Swing (I know for Swing there’s already an SWT port) we decided to go the Facade/Factory way and started hacking and the progress we made in this very short period of time (we are only working on it in the evening) is more than amazing.

Take a look at the following Screenshots they show what’s already possible with the current sources.

They look fairly identical (the only reason they not look completely the same is that I haven’t ported the GridLayout from SWT to Swing but relying on Mig-Layout).

They are full of features you need many lines code without a framework doing the nifity bits for you (e.g. MasterDetail + Field-Dependencies):

  • Master-Detail support
  • Model-UI-Binding
  • Field-Dependencies (Country/Federalstate)

Setting up this UI needs:

  • ~ 80 Lines of Widget-Toolkit-Independent code
  • ~ 20 Lines of Widget-Dependent code (= the start of the application which is currently not abstracted)

The amazing thing is that both UIs are made up by the same source code:

public void createFormUI(UIComposite root) {
  UIFactory ui = root.getFactory();

  UBeanForm listForm = new UBeanForm();
  final UBeanForm detailForm_1 = new UBeanForm();

  UIComposite containerComposite = ui.newComposite(root, null, ui.newGridLayout(2));

  TableColumn[] columns = { new TableColumn("People", new NameLabelProvider()) };

  UITable table = ui.newTable(
    listForm, 
    containerComposite, 
    new GridLayoutData(200, GridLayoutData.DEFAULT, GridLayoutData.ALIGN_BEGINNING, GridLayoutData.ALIGN_FILL, false, true),  
    listForm.detailList(AddressBook.PEOPLE, Collection.class), 
    columns);

  // ---------------------
  UIComposite detailComposite = ui.newComposite(
    containerComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, true), 
    ui.newGridLayout(2));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "ID");
  ui.newTextField(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.ID, int.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Name");
  ui.newTextField(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.NAME, String.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Location");
  ui.newTextArea(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.LOCATION, String.class));

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "Country");
  UICombo combo = ui.newCombo(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.COUNTRY, Country.class), 
    ModelHelper.createWritableList(getModel().getCountries(), Country.class), 
    new CountryLabelProvider());

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_BEGINNING), "Federalstate");
  ui.newDependentListBox(
    detailForm_1, 
    detailComposite, 
    new GridLayoutData(GridLayoutData.DEFAULT,120,GridLayoutData.ALIGN_FILL, GridLayoutData.ALIGN_FILL, true, false), 
    detailForm_1.detailValue(Person.FEDERAL_STATE, FederalState.class), 
    (IObservableList) detailForm_1.detailList(Country.FEDERAL_STATES, Collection.class).createObservable(combo.getSelectionObservable()),
    new FederalStateLabelProvider());

  WritableValue value = ModelHelper.createWritableValue(getModel());
  listForm.bind(value);

  IObservableValue detailObservable = table.getSelectionObservable();
  detailForm_1.bind(detailObservable);

  UBeanForm detailForm_2 = new UBeanForm();
  columns = new TableColumn[] {
    new TableColumn("ID", new IDLabelProvider()),
    new TableColumn("Name", new NameLabelProvider()),
    new TableColumn("Location", new LocationLabelProvider())
  };

  ui.newLabel(detailComposite, new GridLayoutData(GridLayoutData.ALIGN_END, GridLayoutData.ALIGN_CENTER), "");
  ui.newTable(
    detailForm_2, 
    detailComposite, new GridLayoutData(GridLayoutData.ALIGN_FILL,GridLayoutData.ALIGN_FILL,true,true), 
    detailForm_2.detailList(Person.FRIENDS, Collection.class), columns);
  detailForm_2.bind(detailObservable);
}

public void run(final String uiMethod) {
  Display display = new Display();
  Realm.runWithDefault(SWTObservables.getRealm(display), new Runnable() {
    public void run() {
      Shell shell = createUI(uiMethod);
      shell.setSize(650, 500);
      shell.setText("UFacekit - JFace-Demo ");

      Display display = Display.getCurrent();
      while (!shell.isDisposed()) {
        if (!display.readAndDispatch()) {
          display.sleep();
        }
      }
    }
  });
}

private Shell createUI(String uiMethod) {
  final Shell shell = new Shell();
  SWTComposite composite = new SWTComposite(shell,new JFaceFactory().newFillLayout());
  // generic code as shown above

You can even more reduce the size and complexity of the source by using FormBuilder-classes we are going to provide to make creating standard-forms like this as simple as possible.

Before we are publishing a first cut we need to finish the GWT-implementation (GWT/MyGWT/GWT-Ext) but we (in this case James) are on a good way and we should have a release fairly soon. Naturally there are some gaps (e.g. missing widgets, API inconsistencies) but hey the project just got 1 month so I hope you don’t mind.

Did this spot your interest? Come and join our google group and share your ideas with us.

About these ads

One Response to “One month of UFacekit-Development”

  1. i applaud your initiative–nice work, great progress, thus far!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 665 other followers

%d bloggers like this: