e4 – Workbench (Model) Tooling

10 03 2010

I’ve started to work on some tooling to make e4 consumable for the average developer. The first thing I’m concentrating on is tooling for the workbench model.

The key points are:

  • Run in 3.x
  • Run native in e4-Workbench (without the need of a compat layer)
  • Run native in e4-Running-Workbench for Live-Editing
  • Extensible by Workbench-Extenders to register their editors

The current editor state looks like this:

The screen shots show a running Standalone ModelEditor implemented as an e4-application. Until EclipseCon I expect to have a first alpha version for 3.x and the e4-M4-SDK.

Because we are at it: Together with Lars, Kai I’m delivering a tutorial (e4 – Anatomy of an e4-Application) at EclipseCon on writing e4-Applications so if you are interested in e4 make sure to show up at the tutorial.

If you are interested in the code and follow my progress you can checkout the code from CVS and/or subscribe to the following bug.





It’s release time – QxWT 1.0.1.0 and GRaphael 1.3.1.0

28 02 2010

QxWT 1.0.1.0

At the start of the year I promised to release Version 1.0.1.0 of QxWT at the end of Febuary and doing releases on time is one of the most important things so that people can start to trust into your project. You can download the released code from the project release website or directly through this link.

This release comes with the following major features:

  • Full support for Qooxdoo-Databinding
  • Advanced GWT-Features to e.g. Subclass JSNI-Wrappers and overload JavaScript methods in Java
  • Integration into the qooxdoo-Toolchain to create optimized JavaScript
  • Many bugfixes and not wrapped methods in 1.0.0.1
  • Integration of GRaphael to create advanced graphics, animations and charts ontop of SVG and VML using Raphael

The following features beside bugfixes are planned for the next release due in the end of April:

  • Wrapper:
    • Integrate into GWT-UI-Binder by allowing to adapt QxWT-Widgets
    • Integrate into GWT-RPC-Services
  • Eclipse-Tooling
    • Add Project Creation Support to easy setup a QxWT-Project
    • Add Support to control qooxdoo-Toolchain and create a deployable Application

GRaphael 1.3.1.0

To get support for advanced grapics and animation support I started writing a JSNI-Wrapper for Raphael. QxWT comes with an addon module which provides direct integration of GRaphael into QxWT-Applications. The wrapper is in it’s early stage and the API in the flow.

The current usage in QxWT looks like this:

QxRaphaelWidget widget = new QxRaphaelWidget(200, 200) {
  @Override
  protected void init(RPaper paper) {
    RElement el = paper.image("/image.png", 50, 50, 100, 100);
    el.attr( new RAttribute("opacity", "0"));
    el.animate(1000, new RAttribute("opacity", "1.0"));
  }
};

Which creates an image whose opacity attribute is animated from 0 – 1.0 in 1 second, advanced transitions, gradients and much more are possible as well. You can download the released code from the project release website or or directly through this link.

A real world example

To show the potential of all this technologies I’m working on a real world example which simply allows a user to manage Photos, create Online-Presentations and in future also create printable PDF-Files (e.g. a calender, photo-album, …).





QxWT 1.0.1.0 – Realworld Demo

28 02 2010

Tomorrow I’ll release QxWT 1.0.1.0 as I promised at the start of the year. To show people the power of QxWT and what can be achieved by using it, in conjunction with Eclipse-Tools like EMF and Teneo, I wrote an example application on the last 2 weekends.

First of all using all those OpenSource-Technologies together to create an application is simply fun. It’s been a long time since i worked with Hibernate but with Teneo, I really only needed know EMF and learn to use 2 or 3 JPA-APIs to query for stuff. This shows something I told many people already. EMF is not only useable in RCP-Application, it doesn’t even depend on OSGi. I used it at the backend for the Hibernate integration in an ordinary Jetty-Servlet-Container.

The application looks like this:

  • Open a Image-Album
  • Overview of images in the album
  • Editing meta data to images
  • Creating a custom Online-Presentation
  • Running Presentation

The whole application is not completely ready, I hoped to be further but you can try it out:

The application uses the following opensource libs:

  • Frontend
    • QxWT (EPL/LPGL)/qooxdoo (EPL/LPGL)
    • GRaphael (LGPL/EPL)/Rapael (MIT)
  • Backend:
    • EMF+Teneo (EPL)
    • Hibernate (LGPL)
    • PostgreSQL (MIT)

I have not tested this thoroughly (I only took a look on Firefox, Safari, Chrome and Opera on Mac OS X – Opera seems to have issues with images) so please don’t expect to run everything 100%. The code of the example-application is part of my SVN-Repository but NOT released under an OSS-License! Still you can take a look and learn how to use the QxWT-API.

Things I plan to add in the weeks to come:

  • Finish current features and fixing bugs
  • Adding more presentation features (Image-Transition, Drop-Shadows, Animation, …) using more Features of Raphael
  • Print support to create printable Versions for Calendars, Photo-Books, …

So stay tuned for the release announcement of QxWT 1.0.1.0 tomorrow where I’ll explain features coming with this release and features I plan to add in the next releases.





e4 – Dependency and Service Lookup Tooling

23 02 2010

Today I extended my current implementation a bit so that I now extract the currently injected fields in a class and display them in the dialog one can open from within the JavaEditor. The following videos present shows this in action.

EclipseSchnappschuss001

EclipseSchnappschuss001

This movie requires Adobe Flash for playback.


The next step is to add injected services through the Dialog. People asked in comments of the last post whether this support is isolated to e4 and it’s services and the answer is no. The current implementation simply registers a service in the OSGi-ServiceRegistry.

public interface IDIServiceRegistry {
  public void addServiceProvider(IDIServiceProvider descriptor);
  public void removeServiceProvider(IDIServiceProvider descriptor);
  public List<IDIServiceProvider> getProviders();
}

Potential Tool implementors can use and provide informations about available services who are probably available at runtime. As an example implementation I’ve implemented 2 example bundles who contribute providers for e4-core services using DS (you see in the screencast that no available services are there until the tooling bundles are started).

The contribution of the Logger-Service is done looks like this:

public class LoggerProvider extends DIServiceProvider implements IDIServiceProvider {
  public LoggerProvider() {
    System.err.println("Instance created");
  }

  public String getLabel() {
    return "Logger Service";
  }

  public String getDescription() {
    return "Logging warnings, errors, information, as well as capturing debug and trace information. Everything done through this interface is not meant for normal end users. Strings are not expected to be translated.";
  }

  public String getServiceClassName() {
    return "org.eclipse.e4.core.services.Logger";
  }

  public String getBundle() {
    return "org.eclipse.e4.core.services";
  }

  public String getProduct() {
    return "e4";
  }

  public String getCategory() {
    return "Core Services";
  }
}

and contributed like this using DS:

<?xml version="1.0" encoding="UTF-8"?>
<scr:component
  xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0"
  enabled="true"
  immediate="true"
  name="org.eclipse.e4.core.services.jdt">
   <implementation
     class="org.eclipse.e4.core.services.jdt.LoggerProvider"/>
   <service>
      <provide interface="org.eclipse.e4.ui.jdt.IDIServiceProvider"/>
   </service>
</scr:component>

After having implemented the Class-Modification. I think the next logic step would be to write some PDE-Addon which simply registers all available DS-Services found in the Target-Platform into the DI-Registry. I’m still in an experimental stage so probably this is all crap and one has to address the problem differently.

Anyways I’ve learned something about IJavaProject and the AST-Stuff coming with JDT and it’s been a lot of fun so far.





e4 – Dependency Injection Tooling

21 02 2010

In bug 302824 we started discussing how to make the use of DI easier and beside e.g. providing Helper-Classes the ideal thing would be to provide good tooling. Think about how hard OSGi-Development would be without PDE and I think the same is true for DI as well.

I had some free minutes (well in reality hours) today and thought about how such a tooling could look like. The first thing I’ve implemented today is a dialog showing core services and add them to your POJO (currently only the UI is working more or less).

There are other JDT/PDE extension we could provide to make DI in general easier but I need to make myself familiar with PDE/JDT-extensions before I know what’s possible.





e4 – Extending an existing Product

14 02 2010

After some months of not having contributed substential stuff to e4 and in anticipation of the EclipseCon tutorial “e4 – Anatomy of an e4-Application”. I worked yesterday on some demo stuff which we’ll probably use show the audience:

  • The new development process when writing plugins using Mock-Objects
  • Extending an existing e4-Application

The idea of the extension is to add Flickr-Support (Searching and importing images and adding Images to flickr) to our e4-Photo-Demo using the Service-API provided by flickr.com.

One of the strengths of writing and extending e4-Applications is that you don’t need to bring up whole workbench but can develop all components standalone at first (you can even simply start with a none-OSGi-Application).

Here’s the process I followed

  • Writing the UI as an ordinary SWT-Application (No OSGi, No e4). The initial code looked something like this:
    public class Flickr {
      public Flickr(Composite comp) {
         // Create my UI
      }
    
      private void handleSearch(String apiKey, String tags) {
        // TODO implement search logic
      }
    
      public static void main(String[] args) {
        Display display = new Display();
        Shell shell = new Shell();
    
        Flickr flickr = new Flickr(shell);
        shell.open();
    
        while( ! shell.isDisposed() ) {
          if( ! display.readAndDispatch() ) {
            display.sleep();
          }
        }
    
        display.dispose();
      }
    }
    

    After some codeing (well I thought writing something like a PagedTableViewer might me a nice thing) the UI looked like something like this:
    . The code is in a Bundle-Project “org.eclipse.e4.demo.e4photo.flickr” which depends on SWT-only for now (I let PDE manage even my standard Java-Project because this frees me from all the ClassPath-Configuration).

  • The next thing was to look at the Flickr-API and what a JavaService to talk with it could look like. The Service-Interface I came up with looked like this:
    public interface IFlickrService {
      public FlickrSearch createTagSearch(String apiKey, String tags) throws RemoteException;
    
      public List<FlickrPhoto> getPhotos(FlickrSearch search, int page) throws RemoteException;
    
      public InputStream getPhoto(FlickrPhoto photo) throws RemoteException;
    }
    

    The service definition is also part of a separate bundle named ‘org.eclipse.e4.demo.e4photo.flickr.service’.

  • Next step was to create a bundle with a concrete implementation named ‘org.eclipse.e4.demo.e4photo.flickr.service.rest’. Which uses the REST-API provided. The service is self is also a simply POJO and so I was able to test it quite easily by simply adding a main-method.
    public class RestFlickrService implements IFlickrService {
      // Implementation of methods
    
      public static void main(String[] args) {
        try {
          RestFlickrService s = new RestFlickrService();
          FlickrSearch search = s.createTagSearch("46d3d5269fe6513602b3f0f06d9e2b2e", "eclipsecon");
    
          for( int page = 1; page <= search.getPages(); page++ ) {
            System.err.println("--------------------------------");
            System.err.println("Page " + page);
            System.err.println("--------------------------------");
            List<FlickrPhoto> photos = s.getPhotos(search, page);
            for( FlickrPhoto p : photos ) {
              System.err.println("	* " + p);
            }
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }
    

    Please don’t blame me that I haven’t written this by creating JUnit-Test but you should get the point that writeing application like this makes your whole application very easy to test in a real world application.

  • Now we need to wire the stuff together so until now we didn’t even used OSGi but now we can’t get away without it. First step is to use DS to register our service in the OSGi-Registry:
    <?xml version="1.0" encoding="UTF-8"?>
    <scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" immediate="true" name="org.eclipse.e4.demo.e4photo.flickr.service.rest">
       <implementation class="org.eclipse.e4.demo.e4photo.flickr.service.rest.RestFlickrService"/>
       <service>
          <provide interface="org.eclipse.e4.demo.e4photo.flickr.service.IFlickrService"/>
       </service>
    </scr:component>
    
  • And we need to make our UI-Bundle use the IFlickrService. To prepare the stuff for DI we need to add the javax.inject-Bundle which holds the annotation of JSR-330.
    public class Flickr {
      @Inject
      private IFlickrService flickrService;
    
      private void handleSearch(String apiKey, String tags) {
        try {
          FlickrSearch search = flickrService.createTagSearch(apiKey, tags);
          table.setInput(new SearchInput(search));
        } catch (RemoteException e1) {
          Status s = new Status(IStatus.ERROR, "org.eclipse.e4.demo.e4photo.flickr", e1.getMessage(), e1);
          ErrorDialog.openError(table.getShell(), "Searchfailure", "Failure while executing search", s);
        }
      }
    }
    
  • Now we make an mock-application bundle ‘org.eclipse.e4.demo.e4photo.flickr.mock’ which holds an Equinox-Application which bootstraps the Dependency Framework coming with e4 and creates an instance of our view.
    public class Application implements IApplication {
      public Object start(IApplicationContext context) throws Exception {
        Display display = new Display();
        Shell shell = new Shell();
    
        Bundle bundle = FrameworkUtil.getBundle(Application.class);
        BundleContext bundleContext = bundle.getBundleContext();
        IEclipseContext eclipseCtx = EclipseContextFactory.getServiceContext(bundleContext);
        eclipseCtx.set(Composite.class.getName(), shell);
    
        ContextInjectionFactory.make(Flickr.class, eclipseCtx);
        shell.open();
    
        while( ! shell.isDisposed() ) {
          if( ! display.readAndDispatch() ) {
            display.sleep();
          }
        }
        display.dispose();
        return IApplication.EXIT_OK;
      }
    
      public void stop() {
        // nothing to do
      }
    }
    
  • Running this Application with all the bundles we create above plus the core OSGi-Bundles needed like (equinox.ds) will bring up the same application we’ve had after the first step. With the difference that now executing the search will really do something. We now have a running OSGi-Application which allows us to query Flickr for Photos.

  • Last step is to integrate the “Flickr-Application” as a view in the existing Photo-Demo. This is done using an the ‘org.eclipse.e4.workbench.model’ extension point which allows us to contribute ModelElements to the e4 Workbench-Model.

    Pointing to an XMI-File like this.
  • Add the bundles beside the one of the mock-Application to the Launch-Config of the e4-Photo-Demo and you now have support for searching Fotos from Flickr like shown at the start of the post.

I think one of the strengths of e4 is that it makes it easy to develop code in a way that you can run it standalone while developing. You can do this also to some extend in 3.x but at the moment you reach out to workbench-services you’ll get into trouble.

Writing a general mock framework for 3.x is quite hard because you need to rebuild the complete Workbench-Structure because your component is reaching out to them. For e4 the only thing needed is to provide mock implementation of the 20 things (=core workbench-services) and you are ready to work without bringing up an eclipse-instance to test your contribution.





e4 – why you don’t need e5

9 02 2010

This was orginally a reply on Elias post on e5:

On “should take risks”:
We agreed that e4 would be compatible with 3.x. Is not 100% correct: We agreed on the fact that e4 will provide a compat layer so that people can run the 3.x plug-ins which is a completely different thing IMHO because the underpinning designs of e4 are not influenced by this fact.

So what you suggest is what we’ve done in e4 we started with a new set of ideas and code leaving the old one behind already which you notice if you look at the plain e4-bundles in CVS.

On “needs a driver”:
The driver for e4 in my way of thinking is RCP and though you probably don’t believe we are on a good way to make development of RCP much easier. Yet what is missing is tooling, wizards and documentation and people who mastered to learn programming e4-Applications and give you a lending hand.

There’s no need anymore for using plugin.xml for example. You can create an e4 application in a fully programmatic way only you don’t know it as a newcomer.

On “must be easy to learn & master”:
I agree but we should not forget what we are talking about. This are not HelloWorld-programs nor a simple webpages. We are talking about business applications. Still this is a valid point and we need to do our best to give people convenience tools and API to hide away the natural complexities of a multi purpose platform like e4 is one.

General sum up:
I really don’t think that you need an e5 any time soon if you look at how modular e4 is designed from scratch with

  • its extensible workbench-model at the bottom (it even allows you to add your own workbench concepts if you are unhappy with the one coming with e4)
  • its plugable rendering structure on the top
  • its abandoning of singletons making it useable in multi-user environments like RAP (by the use of DI)
  • its leveraging of OSGi (Direct support for OSGi-Services through DI, usage of the OSGi-EventSystem)
  • its even looser coupeling by the use of DI (e.g. I have code I run as plain SWT-Application and inside e4-Applications)

and this all with a really really small amount of size (as Boris already explained in his former reply your numbers are incorrect). The killer feature of e4 is that it comes with concepts and strategies to write UI applications but doesn’t force you the way to do it in certain way by allowing you to exchange (most) of them:

  • You don’t like plugin.xml to make up your UI – Great don’t use it and make up the workbench model from code, your own DSL (e.g. there’s an Xtext-Tutorial at EclipseCon where they show of how to define an Workbench-Model using a DSL), …
  • You don’t like the limitation of SWT or some of their controls – Great don’t use them and replace them with your own ones (and this even by not controling the Application-Startup like you had to do in your Ribbon-Examples for 3.x) by writing your own IPresentation engine which has about 5 methods you need to implement
  • You don’t even like SWT at all – Great don’t use it, use Swing, Qt, ncurses and write your own renderers
  • You don’t like DI but prefer to reach out to the OSGi-Service-Registry your own – Great do it. The argument that you don’t know which services are available is a tooling and documentation issue. The argument that you don’t know which services are available at a given time is something you need to get used to in dynamic environments like OSGi but at least e4 (when using DI) saves from writing code to handle this

I think e4 with the right documentation gives you (and many many people out there) exactly what you/they want so before starting to think about e5 I hope you dive deeper and exploit its possibilities.

To end this post what I like most about e4 is: It gives me back control of almost everything – if I want to – and I can’t live without this power (anymore).





UFaceKit – 2 (new) interesting features in latest nightly

4 02 2010

Like the title already says the latest nightly build comes with 2 amazing features one already part of the code base since a long time (XPath to traverse the UI-DOM) the second one just hit SVN (plugable model-item mapping). I’m going to discuss them in short in this blog posting.

Plugable Model-Item-Mapping

You probably ask yourself. What’s this and why should I care. To understand the problem you must know how the current JFace-Viewers are working internally and which problems this can cause.

JFace-Viewers store strong Java-References between the domain model and the SWT-Item using TableItem#setData(Object)/TreeItem#setData(Object) and additionally if you turn on hashlookup (to speed up setting of selections, …) in an internal HashTable.

The problem with this is that your domain model stays resident in memory as long as the TableItem exists even if no one really needs it until you e.g. want to update the table-item. This implementation detail of current JFace-Viewers makes the use of CDO in UI less ideal because CDO can’t apply it’s clever memory management because your UI code holds strong references into your domain-object graph.

One can overcome this problem in JFace-Viewer world as well by writing some clever Content- and LabelProviders (The implementation is also available from our repository but not part of a build yet) but in my opinion not ideal from a users point of view. Moreover I think a viewer framework should have the possibility to plug-in “your” mapping strategy (e.g. provided by the domain-technoloy project you are using) according to the use case.

That’s why I decided that this feature has to be part of the core UFaceKit-Viewer-Framework and the support of it has just hit the SVN-Repository and is part of my shining new nightly athena build.

/*******************************************************************************
 * Copyright (c) 2010, BestSolution.at and others
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     Tom Schindl <tom.schindl@bestsolution.at> - Initial API and implementation
 *******************************************************************************/
package org.eclipse.ufacekit.ui.jface.cdo.viewers;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

import org.eclipse.emf.cdo.CDOObject;
import org.eclipse.emf.cdo.common.id.CDOID;
import org.eclipse.emf.cdo.view.CDOView;
import org.eclipse.ufacekit.ui.jface.viewers.Viewer;
import org.eclipse.ufacekit.ui.jface.viewers.mapping.AbstractTableItemModelMapping;

public class CdoModelTableItemMapping<ModelElement extends CDOObject,Item extends org.eclipse.swt.widgets.Item> extends AbstractTableItemModelMapping<ModelElement, Item> {
  private CDOView view;
  private Map<CDOID, Item> map;

  public CdoModelTableItemMapping( CDOView view, Viewer<ModelElement, ?> viewer) {
    super(viewer);
    this.view = view;
    this.map = new HashMap<CDOID, Item>();
  }

  @Override
  public void associate(ModelElement model, Item item) {
    if (map.containsKey(model.cdoID())) {
      throw new IllegalStateException("This mapping only supports one instance of a model element");
    }
    item.setData(model.cdoID());
    map.put(model.cdoID(), item);
  }

  @Override
  public void disassociate(Item item) {
    map.remove(item.getData());
    item.setData(null);
  }

  @Override
  public void disassociateAll() {
    map.clear();
  }

  @SuppressWarnings("unchecked")
  @Override
  public ModelElement lookup(Item item) {
    return (ModelElement) view.getObject( (CDOID)item.getData() );
  }

  @Override
  public Collection<Item> lookup(ModelElement element) {
    Item item = (Item) map.get(element);
    if( item != null ) {
      return Collections.singleton(item);
    }

    return Collections.emptyList();
  }
}

This implementation is completely untested but I think you should get the point because we are not restoring the domain object but look it up from our local CDOView we can once more rely on CDOs clever memory management. Nice isn’t it?

XPath support to traverse your UI-DOM

This feature is part of UFaceKit sources since day one in the SVN-Repository but I added it not into the first nightly builds. I think the XPath support for UIs is a fairly unique feature of UFaceKit and the reflective API makes it extremly easy to implement it operations like e.g. applying changes to a many widgets.

package testproject;

import java.util.Iterator;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.ufacekit.core.xpath.common.XPathContext;
import org.eclipse.ufacekit.core.xpath.common.XPathContextFactory;
import org.eclipse.ufacekit.ui.core.UIDesktop;
import org.eclipse.ufacekit.ui.core.UIFactory;
import org.eclipse.ufacekit.ui.core.UIRunnable;
import org.eclipse.ufacekit.ui.core.UIWidget;
import org.eclipse.ufacekit.ui.core.controls.UIApplicationWindow;
import org.eclipse.ufacekit.ui.core.controls.UIButton;
import org.eclipse.ufacekit.ui.core.controls.UIComposite;
import org.eclipse.ufacekit.ui.core.controls.UIInputField;
import org.eclipse.ufacekit.ui.core.controls.UILabel;
import org.eclipse.ufacekit.ui.core.controls.UIApplicationWindow.ApplicationWindowUIInfo;
import org.eclipse.ufacekit.ui.core.controls.util.Rectangle;
import org.eclipse.ufacekit.ui.core.form.UIGridFormBuilder;
import org.eclipse.ufacekit.ui.core.layouts.GridLayoutData;
import org.eclipse.ufacekit.ui.core.layouts.UIFillLayout;
import org.eclipse.ufacekit.ui.core.layouts.GridLayoutData.Alignment;
import org.eclipse.ufacekit.ui.core.xpath.UFacekitXPathContextFactory;
import org.eclipse.ufacekit.ui.jface.core.JFaceFactory;
import org.eclipse.ufacekit.ui.uform.UBeanForm; 

public class Application implements IApplication {

  public Object start(IApplicationContext context) throws Exception {
    JFaceFactory factory = new JFaceFactory();

    final UIDesktop desktop = factory.newDesktop();
    desktop.runWithDefaultRealm(new UIRunnable<UIDesktop>() {
      @Override
      protected IStatus run(UIDesktop arg0) {
        createUI(arg0);
        return Status.OK_STATUS;
      }
    });
    desktop.run();

    return IApplication.EXIT_OK;
  }

  private void createUI(UIDesktop d) {
    UIFactory<?> f = d.getFactory();

    UIFillLayout l = f.newFillLayout();
    final UIApplicationWindow window = f.newApplicationWindow(d, new ApplicationWindowUIInfo(l));
    window.setText("UFaceKit - Hello World");

    UIComposite comp = f.newComposite(window, new UIComposite.CompositeUIInfo(null, f.newGridLayout(1)));
    UILabel label = f.newLabel(comp, new UILabel.LabelUIInfo(GridLayoutData.fillHorizontalData()));
    label.setText("Form Example");

    UBeanForm form = new UBeanForm(f);		

     UIGridFormBuilder builder = UIGridFormBuilder.newInstance(comp, GridLayoutData.fillHorizontalData(), form);
     builder.newLabel("Firstname");
     builder.newInputField(UIInputField.InputFieldBindingInfo.newTextFieldInfo(form.detailValue(Person.FIRSTNAME, String.class)) );

      builder.newLabel("Surname");
      builder.newInputField(UIInputField.InputFieldBindingInfo.newTextFieldInfo(form.detailValue(Person.SURNAME, String.class)) );

      UIButton button = f.newButton(comp, new UIButton.ButtonUIInfo(new GridLayoutData(Alignment.END, Alignment.DEFAULT)));
      button.setText("Save");
      button.setActionRunnable(new UIRunnable<UIButton>() {

      @Override
      protected IStatus run(UIButton b) {
        XPathContextFactory<UIWidget> factory = UFacekitXPathContextFactory.newInstance();
        XPathContext context = factory.newContext(b.getParent());

        Iterator<?> iterator = context.iterate("UIComposite/UIInputField");
        boolean flag = true;
        while( iterator.hasNext() ) {
          UIInputField field = (UIInputField) iterator.next();
          if( field.getText().equals("") ) {
            flag = false;
            field.getStyle().setBackground("#ff0000");
          } else {
            field.getStyle().setBackgroundColor(null);
          }
        }

        if( ! flag ) {
          b.getDesktop().showErrorDialog(
            b.getWindow(),
            "Validation Error",
            "Required fields are marked read",
            new Status(IStatus.ERROR, Activator.PLUGIN_ID, ""),
            null );
        }

        return Status.OK_STATUS;
      }
    });
    window.open();
    window.setBounds(new Rectangle(500, 400, 400, 250));
  }

  public void stop() {
    // nothing to do
  }
}

This creates an UI like this:





Consumeable UFaceKit-Builds for SWT

3 02 2010

This a remarkable day in the history of UFaceKit because since today we can provide consumeable nightly builds to install or create a target platform.

A big thank you to Chris Aniszczyk and Pascal Rapicault who helped me in getting my build in shape – I hope to meet you at EclipseCon and pay you some beers.

Let’s take a look how one get his/her hands dirty on UFaceKit for SWT:

  • Create a new target platform with the following steps
    • Open the target platform properties page
    • Select the RCP-With-Source-Template
    • Select Add… on the page to add additional plugins and select “Software Site” on the opened dialog
    • Click once more the Add…-Button
    • Insert as URL http://download.eclipse.org/ufacekit/updates-nightly/
    • Check the top most checkbox in the tree shown and VERY IMPORTANT UNCHECK “Include required software”
    • Enter a name for the target
    • Activate the new target

    Now we are ready to create our first UFaceKit-Application:

    • Select Plugin-Project
    • Give the Project a Name
    • Uncheck “This plug-in will make contributions to the UI”
    • Select the Headless template
    • Open the MANIFEST.MF and add the following Bundles:
      • org.eclipse.ufacekit.ui.jface.core
      • org.eclipse.ufacekit.ui.core
      • org.eclipse.ufacekit.core.util
      • org.eclipse.swt;bundle-version
      • org.eclipse.ufacekit.core.ubean

The project is now configured appropriately. Now let’s create an HelloWorld-Application. Open the Application.java-File and make it look like this:

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.equinox.app.IApplication;
import org.eclipse.equinox.app.IApplicationContext;
import org.eclipse.ufacekit.core.util.DataRunnable;
import org.eclipse.ufacekit.ui.core.UIDesktop;
import org.eclipse.ufacekit.ui.core.UIRunnable;
import org.eclipse.ufacekit.ui.core.controls.UIApplicationWindow;
import org.eclipse.ufacekit.ui.core.controls.UIButton;
import org.eclipse.ufacekit.ui.core.controls.UIButton.ButtonUIInfo;
import org.eclipse.ufacekit.ui.core.controls.UIApplicationWindow.ApplicationWindowUIInfo;
import org.eclipse.ufacekit.ui.core.controls.util.Rectangle;
import org.eclipse.ufacekit.ui.core.layouts.UIFillLayout;
import org.eclipse.ufacekit.ui.jface.core.JFaceFactory;

public class Application implements IApplication {

  public Object start(IApplicationContext context) throws Exception {
    JFaceFactory f = new JFaceFactory();

    final UIDesktop dk = factory.newDesktop();

    UIFillLayout layout = f.newFillLayout();
    ApplicationWindowUIInfo d = new ApplicationWindowUIInfo(layout);
    final UIApplicationWindow window = f.newApplicationWindow(dk, d);
    window.setText("UFaceKit - Hello World");

    ButtonUIInfo d1 = new UIButton.ButtonUIInfo(null)
    UIButton button = f.newButton(window, d1);
    button.setText("Click me");
    button.setActionRunnable(new UIRunnable<UIButton>() {
      @Override
      protected IStatus run(UIButton arg0) {
        DataRunnable<Boolean> run = new DataRunnable<Boolean>() {
          public void run(Boolean arg0) {
            if( arg0 ) {
              System.out.println("Good Boy/Girl");
            } else {
              System.out.println("Too bad.");
            }
          }
        }
        dk.showQuestionDialog(window, "Question", "Do you like UFaceKit?", run);
        return Status.OK_STATUS;
      }
    });
    window.open();
    window.setBounds(new Rectangle(500, 400, 400, 100));
    dk.run();

    return IApplication.EXIT_OK;
  }

  public void stop() {
    // nothing to do
  }
}

I think the code is quite self-explanatory but there are some remarkable things you should have noticed:

  1. No SWT-Imports
  2. Beside the factory creation all code is UI-Technology agnostic (and it’s quite easy to get rid of this by using Declarative Services because UFaceKit is designed with the idea of “UI as a service”)
  3. Blocking operations like showQuestionDialog() get passed a callback – this is needed because one of the target platforms is Web-Browsers who have no concept of an event loop

I’m going to transfer this content over to UFaceKit-Wiki in the following days and write other tutorials on how to exploit other features of UFaceKit like:

  • Declarative Styling
  • Applying XPaths to your UI-Dom
  • Built-in databinding

One more note: The UFaceKit-SWT port is feature complete and stable since about 6 months and there hardly any todos before releasing 1.0.0 of the SWT-Port so it’s really useable and I hope that some people give it a try and report back problems so that I can release a very stable build.

The only real blocker for a 1.0.0 release is that the test suite is not completed yet and I won’t release before having a complete test suite which helps me to avoid regressions in future versions and ensure compability of future platform ports to the API contract defined.





QxWT 1.0.1.0-rc1 and other cool stuff

31 01 2010

As the blog title suggest I’ve uploaded a first release candidate for the QxWT 1.0.1.0 which is going to be released on about a month.

The most important new features coming with this release:

  • Postprocessing to use qooxdoo toolchain
  • Support for Databinding

Beside this I am in need of a browser charting library and played around a bit with Raphael this weekend which also has a very tiny charting module which is released under MIT. Because of my QxWT-work I’m quite good now in writing JSNI-Wrappers and so I did that for Raphael. You can look at the result of this here.

The wrapper is released under EPL and LGPL and I guess QxWT will in cooperate this library in 1.0.1.0.