Wednesday, August 31, 2011

Notifier Design Pattern

Say you want to develop an application which will have many viewers/pages and all these have to be refreshed with the latest data as soon as the data changes in the engine.

A very simple example is - Weather Reports. When the data changes in the engine, the weather report page has to be refreshed to show the latest data.

Let's follow the below steps:
  1. Develop your report dialog - which will show the weather information.
  2. Implement the ChangeListener in the dialog report- This will act as a listener
  3. Implement your report data class, which contains the weather information. This will act a notifier and also as a registry.
  4. Register your listener with the data class so that the viewer will get a notification if the data changes.

Here is the sample code for it:

import java.util.List;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
 * Weather report dialog.
public class WeatherDetailsDialog implements ChangeListener {
 private TableViewer weatherViewer;
 protected WeatherDetailsDialog() {  
  //your specific data passed through constructor 
 protected void createReport(Composite topComposite) {
  Group dependantsViewerGroup = new Group(topComposite, SWT.NONE);
  dependantsViewerGroup.setLayout(new GridLayout());
  GridData gridData3 = new GridData(SWT.FILL, SWT.FILL, true, false);
  dependantsViewerGroup.setText("Weather Report"); //$NON-NLS-1$
  weatherViewer = new TableViewer(
    dependantsViewerGroup, SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.BORDER);
  final Table reportTable = weatherViewer.getTable();
  GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
  gridData.heightHint = 140;
  TableColumn cityName = new TableColumn(reportTable, SWT.LEFT);
  cityName.setText("City"); //$NON-NLS-1$
  TableColumn valueColumn = new TableColumn(reportTable, SWT.LEFT);
  valueColumn.setText("Value"); //$NON-NLS-1$
  TableColumn descriptionColumn = new TableColumn(reportTable, SWT.LEFT);
  descriptionColumn.setText("Description"); //$NON-NLS-1$
  weatherViewer.setContentProvider(new WeatherContentProvider()); 
  weatherViewer.setLabelProvider(new WeatherLabelProvider());
  //Register viewer with the weathe report data.
  List<IWeather> reportData = computingEngine.getReportData();
  for (IWeather data : reportData) {
     * Invoked when the target of the listener has changed its state.
     * @param e  a ChangeEvent object
 public void stateChanged(ChangeEvent arg0) {
  Display.getDefault().asyncExec(new Runnable() {
   public void run() {

This will notfiy as soon the data changes.

import java.util.ArrayList;
import java.util.List;
import javax.swing.event.ChangeListener;

public class Weather {

 private List<ChangeListener> registeredListners = new ArrayList<ChangeListener>();
 private ComputingEngine ComputingData;
 private Float newValue;
 private String description;
 public Weather(ComputingEngine ComputingData) {
  this.ComputingData = ComputingData;
  * Updating the status change. This will notify to all the registered listeners
  * Ex: It will notify to the viewer/UI about the weather change report
  *   */
 public void setValue(Float newValue) {
  this.newValue = newValue;
 public ComputingEngine getComputingData() {
  return ComputingData;
 public void setDescription(String description) {
  this.description = description;
 public String getDescription() {
  return description;
 public Float getNewValue() {
  return newValue;
 //Add your listener here
 public void addChangeListener(ChangeListener listener) {
  if (!registeredListners.contains(listener))
 //removing the listener
 public void removeChangeListener(ChangeListener listener) {
  if (registeredListners.contains(listener))
 //This will be triggered when the state changes
 public void notifyListeners() {
  for (ChangeListener listener : registeredListners) {

Tuesday, August 30, 2011

Progress bar in the Table Viewer

Use Case:
If you want to show a progress bar with in the Table viewer and it should represent what percentage of job has finished.

May be you want to show something like this:

We should implement the OwnerDrawLabelProvider on the particular column where you want to show the progress bar.

OwnerDrawLabelProvider: Is an abstract implementation of a label provider that handles custom draw. So this can be used to implement progress bar in the table viewer.

Let's take the example:

//Table viewer
tableViewer = new TableViewer(composite, SWT.FULL_SELECTION | SWT.V_SCROLL | SWT.H_SCROLL);
  reportTable = tableViewer.getTable();
  reportTable.setLayoutData(new GridData(GridData.FILL, GridData.FILL, true, true));

//Progress bar column
TableViewerColumn progressColumn = new TableViewerColumn(tableViewer, SWT.CENTER);
  progressColumn.getColumn().setText(""); //$NON-NLS-1$

//set progress bar lable provider on the progresbar column
progressColumn.setLabelProvider(new ProgressLabelProvider(tableViewer));

//Implemention of OwnerDrawLabelProvider

import java.util.List;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.jface.viewers.OwnerDrawLabelProvider;
import org.eclipse.jface.viewers.TableViewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;

public class ProgressLabelProvider extends OwnerDrawLabelProvider {
 private TableViewer tableViewer;
 public ProgressLabelProvider(TableViewer tableViewer) {
  this.tableViewer = tableViewer;
 protected void measure(Event event, Object element) {
 protected void paint(Event event, Object element) {
  //Total Units to be executed
   int totalUnits = getObjects().size();
    //Identify the completed units by reading specific information
   int completedUnits = getCompletedUnits();
  //Calculate Percentage
   int percentage = (completedUnits * 100/totalUnits);
   Table table = tableViewer.getTable();
   TableItem item = (TableItem) event.item;
         int index = table.indexOf(item);
         Color foreground = gc.getForeground();
         Color background = gc.getBackground();
         Rectangle bounds = ((TableItem) event.item).getBounds(event.index);

         int width = (bounds.width - 1) * percentage / 100;
         gc.fillGradientRectangle(event.x, event.y, width, event.height, true);
         Rectangle rect2 = new Rectangle(event.x, event.y, width - 1, event.height - 1);
         String text = percentage + "%";
         Point size = event.gc.textExtent(text);
         int offset = Math.max(0, (event.height - size.y) / 2);
         gc.drawText(text, event.x + 2, event.y + offset, true);
 public Image getColumnImage(Object element) {
  return null;