Wednesday, November 25, 2009

Eclipse BIRT plugin - Chart scaling issue

Background:

We are using Eclipse BIRT plugin 2.5.0 in our application. We encountered a strange issue with BIRT. As you would normally do, we set the scaling in our BIRT chart (in report design) to AUTO, so that BIRT can dynamically figure out the min/max and step size for the axis. It worked fine until we hit a corner case. I wanted to share my problem and the workaround I used to solve this problem so that it helps anyone having the same issue.

Problematic case:

In one of our cases, all the values for the axis were either 0 or less than 0. In this case, it was between 0 and -.02 and so when displayed in percent it was from 0 to -2%. In this case, BIRT chose the axis scale to be from 0 to -100% and so the chart got squeezed (since the entire range is only between 0 and -2%), making the chart unusable. This seems like a bug in BIRT. I've just filed a bug for this: https://bugs.eclipse.org/bugs/show_bug.cgi?id=296207

Workaround:

Aftering unsuccessfully googling for some time and searching for other alternatives, I tried setting the step number and that solved the problem. This made BIRT choose the proper min/max and enlarged my chart.

If you are in report designer, edit chart and go to Format chart tab (or right click on chart and select Format chart). Under Chart Area->Axis, select the axis and hit scale button. This will open "Axis Scale" window. Here instead of "Auto" select the "Step Number" radio button. Specify a number here (10, 15 etc.,) to indicate the number of steps in the axis. This should add the following to the xml source of chart in rptdesign.

<Scale>
<StepNumber>10</StepNumber>
</Scale>

This solved my problem. Note that this workaround maintains the dynamic nature and does not hard code the chart values. The min/max (and so the step size) values in the chart are still dynamic based on the values in the chart.

Sunday, November 22, 2009

What did I learn today - Using ArrayContentProvider (Eclipse RCP - JFace)

If your table view displays a collection of objects for example, collection of Person objects, Collection of Employee info etc., instead of writing your own content provider, consider using ArrayContentProvider. This takes the viewer input (collection) and converts it to an Array.

For example, say your code does something like this:

this.viewer.setContentProvider(new EmployeeInfoContentProvider());
this.viewer.setLabelProvider(new EmployeeInfoLabelProvider());
// Assume employeeInfoSet is a Set of EmployeeInfo objects
this.viewer.setInput(this.employeeInfoSet);

EmployeeInfoContentProvider code:

public class EmployeeInfoContentProvider implements IStructuredContentProvider {

@Override
public Object[] getElements(final Object inputElement) {
if (inputElement instanceof Set) {
return ((Set) inputElement).toArray();
}

return new Object[0];
}

@Override
public void dispose() {
//Nothing to do
}

@Override
public void inputChanged(final Viewer viewer, final Object oldInput, final Object newInput) {
//Nothing to do
}

}

In the above code, EmployeeContentProvider does nothing but translating the collection to array. In this case, you can remove EmployeeContentProvider and use ArrayContentProvider, which does the conversion for you. So, your view code would look like this:

// Replacing EmployeeInfoContentProvider with ArrayContentProvider
this.viewer.setContentProvider(new ArrayContentProvider());
this.viewer.setLabelProvider(new EmployeeInfoLabelProvider());
// Assume employeeInfoSet is a Set of EmployeeInfo objects
this.viewer.setInput(this.employeeInfoSet);

Less code is better right!

Sunday, November 8, 2009

What did I learn today - Adding key listeners to trees and tables (SWT/JFace)

I wanted my trees and tables to listen to DEL key so that when user presses it, the selected nodes in the tree or the selected cells in the table would get deleted. I was looking for the method to add key listener to the table/tree viewer, but found that I need to add it to the viewer control.

Below is the code to add listener to the delete key on your tree viewer.

this.treeViewer.getControl().addKeyListener(new KeyAdapter() {
@Override
public void keyReleased(final KeyEvent e) {
if (e.keyCode == SWT.DEL) {
IStructuredSelection selection = (IStructuredSelection) treeViewer.getSelection();
if (selection.isEmpty()) {
return;
}

// Business logic to handle deletion - remove from model, view etc.,
handleDelete(selections);
}
}
});

You can do it similarly for other viewers (table viewer etc.,) or to listen to other keys also.

If you are working directly with SWT, you will add listener directly to the tree/table (i.e the control itself) like tree.addKeyListener(), table.addKeyListener() etc., You can add this to any control in SWT.