Thursday, January 18, 2007

The new faces of JFace (part2)

The last time I showed you the new programming model we introduced to JFace to make it feel like programming SWT.

But has this been the only reason that we decided to add this new API beside the existing one (ILabelProvider, ITableLabelProvider, IColorProvider, ITableColorProvider, IFontProvider, ITableFontProvider) .
Sure enough it was not the only reason. First of all many newcomers have been confused by all those NON MANDATORY interfaces to control different aspects of items and we faced the problem that whenever SWT-Provided a new feature e.g. Owner Draw Support in 3.2 we would have to add a new interface type and to support new features e.g. ToolTip support for table/tree cells we also had to provide a new interface. We decided that this is not the way to go for the future.

So we sat down and thought about a complete new structure below JFace tree and table support. We added the idea of rows (ViewerRow) and cells (ViewerCell) abstracting common things provided of TreeItem and TableItem and completely hiding the widget specific things into this class. The abstraction level this provided to us made it possible to provide a common class named ColumnViewer.

So what have we learned so far:
  1. We don't need all those interfaces any more
  2. We have a new abstraction level for column based viewers (ViewerRow, ViewerCell)
  3. We have a new base class named ColumnViewer
So you may ask what you should use if you can't use the old interfaces any more. Well the answer is ColumnLabelProvider or if you want to implement the whole cell behaviour your own it's abstract base class named CellLabelProvider. The new ColumnLabelProvider combines all currently know interfaces (ILabelProvider, IFontProvider, IColorProvider). There's no base class visible to you supporting ITable*-interfaces because those interface put limitations to tables I'll show you later let's now explore how to use the new ColumnLabelProvider interface and how it is used.

TableViewer viewer = new TableViewer(parent,SWT.FULL_SELECTION);

TableViewerColumn column = new TableViewerColumn(viewer,SWT.NONE);
column.setLabelProvider(new StockNameProvider());
column.getColumn().setText("Name");

TableViewerColumn column = new TableViewerColumn(viewer,SWT.NONE);
column.setLabelProvider(new StockValueProvider());
column.getColumn().setText("Modification");

public class StockNameProvider extends ColumnLableProvider {
@Override
public String getText(Object element) {
return ((Stock)element).name;
}
}

public class StockValueProvider extends ColumnLabelProvider {

@Override
public String getText(Object element) {
return ((Stock)element).modification.doubleValue() + "%";
}

@Override
public Color getForeground(Object element) {
if( ((Stock)element)modiciation.doubleValue() < 0 ) {
return getDisplay().getSystemColor(SWT.COLOR_RED);
} else {
return getDisplay().getSystemColor(SWT.COLOR_GREEN);
}
}
}

You may now argue that this was easier with the old ITable*-API and you are true but from the point of reusability this version is much more flexible and you can reuse your LabelProviders for many different TableViewers because they don't hold any index informations. Another thing is that you needed a bunch of custom code if you wanted the columns to be reordable with the old API this is not an issue any more with the new API because the LabelProvider is directly connected to the column and moves with it.

Next time I'll continue with some nice new LabelProvider features like ToolTip support and OwnerDraw.

6 comments:

Mark Levison said...

While your doing all of this work would you consider providing a version of the tree viewer where you store no state information?

In the product I'm building our engine keeps track of the open/close state, selection etc. In addition results are readonly - so open/close I need make a request of the engine. When its done the work it will hand back a new results set.

Currently when we use the treeviewer and the content provider we have about 150 lines of code just keep the tree state in sync with the results set.

Please give us a stateless version of the tree viewer.

Tom said...

Please file a bug report or CC to the bug report if there one already. If this does need an API-Change maybe I have time in M6 to work on it if we need new API I think its too late.

Mark Levison said...

I will file a bug report. Mostly I mentioned this as food for thought. I'm hoping to stimulate your thinking as you move forward. Sometimes it would easier for us if your provided less instead of more.

Mark Levison said...

Its been filed as bug: 171284
https://bugs.eclipse.org/bugs/show_bug.cgi?id=171284

Troy said...

Has the new API been finalized? I really like this new design and it would help me out quite a bit. I don't mind at all having to adjust for minor changes here and there as you near the final 3.3 release. I'd just like to avoid adopting it only to find out it's been abandoned for something else. :)

Tom said...

Well the parts demonstrated here are fairly ready and I don't expect things to change but to be sure you should wait for M5 which is API freeze. The only thing that is currently in dicussion and will add new API is https://bugs.eclipse.org/bugs/show_bug.cgi?id=151295 but I don't expect any of the demonstrated API go away. But I'm not the decision maker.