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.setLayoutData(gridData3);
  dependantsViewerGroup.setText("Weather Report"); //$NON-NLS-1$
   
  weatherViewer = new TableViewer(
    dependantsViewerGroup, SWT.FULL_SELECTION | SWT.H_SCROLL | SWT.BORDER);
  final Table reportTable = weatherViewer.getTable();
  reportTable.setLinesVisible(false);
  reportTable.setHeaderVisible(true);
  reportTable.setLayoutData(gridData3);
  GridData gridData = new GridData(SWT.FILL, SWT.TOP, true, false);
  gridData.heightHint = 140;
  reportTable.setLayoutData(gridData);
  TableColumn cityName = new TableColumn(reportTable, SWT.LEFT);
  cityName.setText("City"); //$NON-NLS-1$
  cityName.pack();
  cityName.setWidth(100);
   
  TableColumn valueColumn = new TableColumn(reportTable, SWT.LEFT);
  valueColumn.setText("Value"); //$NON-NLS-1$
  valueColumn.pack();
  valueColumn.setWidth(100);
   
  TableColumn descriptionColumn = new TableColumn(reportTable, SWT.LEFT);
  descriptionColumn.setText("Description"); //$NON-NLS-1$
  descriptionColumn.pack();
  descriptionColumn.setWidth(120);
   
  weatherViewer.setContentProvider(new WeatherContentProvider()); 
  weatherViewer.setLabelProvider(new WeatherLabelProvider());
  //Register viewer with the weathe report data.
   
  List<IWeather> reportData = computingEngine.getReportData();
  for (IWeather data : reportData) {
   ((Weather)data).addChangeListener(this);
  }
  weatherViewer.setInput(reportData);
 }
/**
     * Invoked when the target of the listener has changed its state.
     *
     * @param e  a ChangeEvent object
     */
   
 @Override
 public void stateChanged(ChangeEvent arg0) {
  Display.getDefault().asyncExec(new Runnable() {
   @Override
   public void run() {
    weatherViewer.refresh();
   }
  });
 }
}


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;
  notifyListeners();
 }
  
 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))
   registeredListners.add(listener);
 }
 //removing the listener
 public void removeChangeListener(ChangeListener listener) {
  if (registeredListners.contains(listener))
   registeredListners.remove(listener);
 }
 //This will be triggered when the state changes
 public void notifyListeners() {
  for (ChangeListener listener : registeredListners) {
   listener.stateChanged(null);
  }
 }
}

No comments:

Post a Comment