Monday, September 22, 2008

JFace-Viewers for Swing, is this possible?

You might think "Now he's gone completely crazy" but hold on and read through the next few paragrpahs to hopefully find out that I'm not.

0. The background


Do you sometimes have to code against Swing and have also been disappointed that you could not remember how to deal with Tables, Trees and TreeTables (I find myself always opening this tedious Swing-Tutorial to find how to do it)?

In last few days I worked on UFacekit's Swing implementation for Tree and TreeTable. JFace-Databinding has added support for Trees and TreeTables in 3.4 and naturally they build upon the JFace-Viewer implementation but naturally JFace-Viewers are bound to SWT and so it is impossible to use this support (or a slighlty one modified) Swing, right?

Well the above is not completely right the main JFace-Viewer-API is fairly free from SWT (besides some Widget, Item stuff) the internals are naturally not. After having noticed this I:

1. Extracted an Widget-Toolkit-Neutral API from JFace


... moved it to a new plugin (org.ufacekit.ui.viewers). I didn't only move the classes and interfaces to a new home I also added support for generics so all this casting is gone and done by the compiler for us.

A content provider now looks like this:

IContentProvider<Person,Collection<Person>> cp =
new IContentProvider<Person,Collection<Person>> {
// ...
}

and a collection can get iterated with a foreach-loop

for( Person p: v.getSelection() ) {
// ...
}

I rearranged some other classes and made interfaces from most of them, ... . So now I have a widget-toolkit-clean Viewer-API.

2. Copied some SWT-Classes (Widget, Table, TableItem, Tree, ...)


... replaced the internals through Swing-counter parts (some of the code is highly ineffecient because e.g. for a Tree we now have 3 Objects (UserObject, TreeItem, DefaultMutableTreeNode) )

3. Commented some JFace-code not needed to provide the minimum JFace-API


... providing a selection, and firing events when the selection changed but I currently e.g. don't need inline Editing so I simply commented all parts of the viewers that deal with this, including Mouse-Handling, ... . The problems from 2. & 3. are hidden from the user because all these are internal classes so I can replace them step by step.

4. Blog how nicely now I can setup a TreeTableViewer for Swing


(in fact SwingX because Swing doesn't has a TreeTable implementation by default - don't ask me why a Toolkit being around for such a long time doesn't has such a standard-control)

So now I don't have to remember how I have to create a TableTree in Swing which loads subnodes lazily because I can simple use the API I already know from JFace for SWT.

@Override
protected Component createUI(JFrame frame, List<Person> model) {
JXTreeTable tree = new JXTreeTable();

TableColumnExt c1 = new TableColumnExt(1);
c1.setHeaderValue("Givenname");
c1.setWidth(200);
tree.getColumnModel().addColumn(c1);

TableColumnExt c2 = new TableColumnExt(1);
c2.setHeaderValue("Surname");
c2.setWidth(200);
tree.getColumnModel().addColumn(c2);

JScrollPane scroll = new JScrollPane(tree);

TreeTableViewer<Person, Collection<Person>> viewer =
new TreeTableViewer<Person, Collection<Person>>(tree);
viewer.addSelectionChangedListener(
new ISelectionChangedListener<Person>() {
public void selectionChanged(SelectionChangedEvent<Person> event) {
for( Person p: event.getSelection() ) {
System.out.println(p);
}
}
});

TreeViewerColumn<Person> c = new TreeViewerColumn<Person>(viewer,c1);
c.setLabelProvider(new LabelConverter<Person>() {
@Override
public String getText(Person element) {
return element.getGivenname();
}
});
c = new TreeViewerColumn<Person>(viewer,c2);
c.setLabelProvider(new LabelConverter<Person>() {
@Override
public String getText(Person element) {
return element.getSurname();
}
});

viewer.setContentProvider(
new ITreeContentProvider<Person,Collection<Person>>() {
public Collection<Person> getChildren(Person parentElement) {
return parentElement.getChildren();
}

public Person getParent(Person element) {
return element.getParent();
}

public boolean hasChildren(Person element) {
return ((Person)element).getChildren().size() > 0;
}

public Collection<Person> getElements(Collection<Person> inputElement) {
return inputElement;
}

public void dispose() {
// TODO Auto-generated method stub
}

public void inputChanged(IViewer<Person, Collection<Person>> viewer,
Collection<Person> oldInput,
Collection<Person> newInput) {
// TODO Auto-generated method stub
}
});
viewer.setInput(model);
return scroll;
}

5. Summary


The internals are quite ugly there is a huge amount of bugs (I'm sure that not all is working smoothly already), missing functionality (e.g. Icon, Color and Font support) but I now have the foundation to add Tree and TreeTable support to the UFacekit-Library. Cleaning up and bugfixing can happen later. Like all other parts of the UFacekit-Project you can consume this swing-jface-bundle standalone because it has no dependency at all (besides the one on org.ufacekit.ui.viewers).

6. So am I now?


  • Completely Crazy

  • Fairly Crazy

  • A bit Crazy

  • Fairly normal if you know me and all the crazy ideas I already had

Tuesday, September 09, 2008

UFacekit - Proposed as a Component under Platform/Incubator

So the news is out [Mailinglist, Newsgroups]. UFacekit is proposed as a Component under Platform/Incubator project (proposal). I think this is the right move for UFacekit to gather momentum towards our first release. If you want to support this move:
  1. Comment on the following newsgroup post from Boris

  2. Add yourself/company as an interested party on the proposal page
I'm currently working on the JavaDoc and for SWT/JFace a build should be available right after we moved the sources to foundations repositories, swiched namespaces, ... .

Wednesday, September 03, 2008

Exploring new technologies part of Ganymede-Release Train

I took myself some time the last days exploring new technologies available with Ganymede 3.4:

  • Eclipse-Databinding and its new features

  • EMF-Databinding (Provisional but working very smoothly)

  • Teneo: Persist your model via hibernate in a SQL-Database

  • CDO: Share your model between different clients and persist it into an SQL-Database (with Revision support)

  • New Extension Points to enhance the Expression Framework

  • Spring & OSGi

  • P2 to install the Products using the P2-Agent

I did this to understand those technologies better because we at my company have to decide which technologies our next generation of products is built on (The current ones are based on selfwritten libs because at that time there was no Eclipse-Databinding, Teneo and CDO or we didn't knew about it).

As always when learning new technologies I created an example application but before I started I defined some goals I think are curcial to all Enterprise Datacentric Desktop Applications:

  • Nice L&F (as good as I can make an UI Look without a designer)

  • Plugable storage technology

  • Undo/Redo Support

Then I started hacking, creating an Ecore-Model, some plugins, extension points, browsing documentation and noticed that there are no examples around for most of the things I wanted use:

  • How to create an EditingDomain myself when not using the generated editor-classes from EMF?

  • How to use the new org.eclipse.ui.services-Extension point to enhance the expression framework?

  • Best strategy to use Extension Points when bundles are installed/uninstalled/updated while the application is running


All those things are not hard if you know how to do it but if you don't it's quite tricky to solve these problems. It even gets harder if the technologies you plan to use are quite new and/or are not used together and because of this bugs arise.

So the immediate output of my work was that 2 bugs [239015, 245183] in Eclipse-Databinding got fixed in 3.4.1.

The longterm output for me is:

  • I now have a good picture how our next technology stack looks like

  • I have an example application (I will add other things in the next weeks) to teach my co-workers the technologies

  • I had a lot of fun (besides struggeling with P2)

The longterm output for you is:

  • You have a small application showing you a lot of different concepts around RCP+EMF+Databinding applications

    • EMF-Ecore

    • Usage/Creation of your own Extension Points

    • Using EditingDomain outside the scope of EMF-Generated artefacts

    • Using Teneo

    • Using CDO

  • I started summerizing all the ideas, technologies and concepts combined in this example in a document, I'm working on from time to time. So maybe some time you'll get a "book" explaining you everything

  • Some nice reusable classes e.g. one to use EMF/Databinding-LabelProviders with cool features, a new drop down widget showing a Tree in the popup, ...


This is the application:


If you want to run it locally get a copy of the P2-Agent and point the metadata repository and artifacts repository to this location.

To use the CDO-Version you also need a server component which can be installed when pointing the agent to this location. After having installed the CDO-Server you also have to create a CDO-Configuration (cdo-server.xml) in the installations "configuration" directory which you can fetch from here.

The repository name in the above config "CDO-1" has to be the id of the CDO-Configuration you create in your application.

Finally if you are interested only in the sources then install a subversion plugin in your eclipse and use one of te Team-ProjectSet files from here to check out the necessary projects.

If you want to learn more about these cool technologies. I've proposed beside a talk about E4 - The new platform-ui concepts a talk about this example application on ESE.