Project: Bio-PEPA
package uk.ac.ed.inf.biopepa.ui.wizards.timeseries;
 
import java.util.LinkedList; 
 
import org.eclipse.jface.wizard.WizardPage; 
import org.eclipse.swt.SWT; 
import org.eclipse.swt.custom.ScrolledComposite; 
import org.eclipse.swt.events.ModifyEvent; 
import org.eclipse.swt.events.ModifyListener; 
import org.eclipse.swt.layout.GridData; 
import org.eclipse.swt.layout.GridLayout; 
import org.eclipse.swt.widgets.Button; 
import org.eclipse.swt.widgets.Composite; 
import org.eclipse.swt.widgets.Event; 
import org.eclipse.swt.widgets.Label; 
import org.eclipse.swt.widgets.Listener; 
import org.eclipse.swt.widgets.Text; 
 
import uk.ac.ed.inf.biopepa.core.sba.ExperimentSet; 
 
public abstract class AbstractExperimentPage extends WizardPage { 
 protected AbstractExperimentPage(String pageName) { 
  super(pageName); 
 
  
 private String headerHelp = ""
 public void setHeader(String s){ 
  headerHelp = s; 
 
 
 /* These protected fields should be set during the constructor */ 
 protected NameHintPair[] experimentObjectNameHints; 
 
 /*
  * private BioPEPAModel model; 
  *  
  * public Constructor (BioPEPAModel model) { super(wizardPageName); 
  * this.model = model; 
  * setTitle("Rate Variables Setup and Experimentation Page"); 
  * setDescription("Set up the rate variables"); experimentObjectNames = ... 
  * ; } 
  */
 
 
 protected LinkedList<ArrayInput> arrayInputs = new LinkedList<ArrayInput>(); 
 public LinkedList<ArrayInput> getArrayInputs () { 
  return arrayInputs; 
 
  
 /*
  * public void addExperimentArrays (ExperimentSet experimentation){ for 
  * (ArrayInput arrayInput : arrayInputs){ 
  * arrayInput.addArrayInput(experimentation); } } 
  */
 
 public abstract void addExperimentArrays(ExperimentSet experiment); 
  
  
 
 public void createControl(Composite parent) { 
  ScrolledComposite composite = new ScrolledComposite(parent, 
    SWT.V_SCROLL | SWT.H_SCROLL); 
  setControl(composite); 
  // Layout 
 
  Composite linesParent = new Composite(composite, SWT.FILL); 
  GridLayout linesLayout = new GridLayout(); 
  linesLayout.numColumns = 7
  linesLayout.makeColumnsEqualWidth = false
 
  GridData linesGridData = new GridData(); 
  linesGridData.grabExcessHorizontalSpace = true
  linesGridData.horizontalAlignment = GridData.FILL; 
  linesParent.setLayoutData(linesGridData); 
 
  linesParent.setLayout(linesLayout); 
 
  // Create the labelled help row which spans all seven columns: 
  Label labelledHelp = new Label(linesParent, SWT.BORDER); 
  labelledHelp.setText(headerHelp); 
  GridData labelledHelpGridData = new GridData(); 
  labelledHelpGridData.grabExcessHorizontalSpace = true
  // Make it span all the columns of the lines parent. 
  labelledHelpGridData.horizontalSpan = linesLayout.numColumns; 
  labelledHelp.setLayoutData(labelledHelpGridData); 
   
   
  // Create the first row with labels tell people what to do 
  int labelStyle = SWT.SINGLE | SWT.CENTER; 
 
  Label nameLabel = new Label(linesParent, labelStyle); 
  nameLabel.setText("Name"); 
  Label checkBoxDummy1 = new Label(linesParent, labelStyle); 
  checkBoxDummy1.setText(""); 
  Label commaSep = new Label(linesParent, labelStyle); 
  commaSep.setText("comma separated values"); 
  Label checkBoxDummy2 = new Label(linesParent, labelStyle); 
  checkBoxDummy2.setText(""); 
  Label startValue = new Label(linesParent, labelStyle); 
  startValue.setText("start value"); 
  Label stopValue = new Label(linesParent, labelStyle); 
  stopValue.setText("stop value"); 
  Label stepValue = new Label(linesParent, labelStyle); 
  stepValue.setText("step"); 
 
  for (NameHintPair nameHint : experimentObjectNameHints) { 
   ArrayInput arrayInput = new ArrayInput(linesParent, nameHint); 
   arrayInputs.add(arrayInput); 
  
  linesParent.pack(true); 
  composite.setContent(linesParent); 
 
 
 /*
  * A simple method to create a grid data object for text object, since I 
  * think it is better to create a new one for each text object such that any 
  * changes are not then global. 
  */
 
 private GridData newTextGridData() { 
  GridData textGridData = new GridData(); 
  // textGridData.widthHint = 80; 
  textGridData.horizontalAlignment = GridData.FILL; 
  textGridData.grabExcessHorizontalSpace = true
  return textGridData; 
 
 
 private ModifyListener modifyListener = new ModifyListener() { 
 
  public void modifyText(ModifyEvent event) { 
   validatePage(); 
  
 }; 
 
 public void validatePage() { 
  for (ArrayInput arrayInput : arrayInputs) { 
   String message = arrayInput.validString(); 
   if (!message.equals("")) { 
    this.setErrorMessage("array input for: " + arrayInput.getName() 
      " is invalid: " + message); 
    this.setPageComplete(false); 
    return
   
  
  this.setErrorMessage(null); 
  this.setPageComplete(true); 
 
 
 protected class NameHintPair { 
  public String name; 
  public String hint; 
   
  public NameHintPair (String name, String hint){ 
   this.name = name; 
   this.hint = hint; 
  
 
  
 public class ArrayInput { 
  Label nameLabel; 
  Composite parent; 
   
  String name; 
  String hint; 
 
  Button listCheckBox; 
  Text listText; 
  Button rangeCheckBox; 
  Text startText; 
  Text stopText; 
  Text stepText; 
 
  public ArrayInput(Composite parent, NameHintPair nameHint) { 
   int labelStyle = SWT.SINGLE | SWT.LEFT; 
   int textStyle = SWT.RIGHT | SWT.BORDER; 
 
   this.parent = parent; 
   this.name   = nameHint.name; 
   this.hint   = nameHint.hint; 
 
   nameLabel = new Label(parent, labelStyle); 
   nameLabel.setText(name + " (" + hint + ")"); 
   nameLabel.setLayoutData(new GridData()); 
 
   listCheckBox = new Button(parent, SWT.CHECK); 
   listCheckBox.setEnabled(true); 
   listCheckBox.setSelection(false); 
   listCheckBox.addListener(SWT.Selection, listCheckBoxListener); 
 
   listText = new Text(parent, textStyle); 
   listText.setLayoutData(newTextGridData()); 
   listText.setText(""); 
   listText.addModifyListener(modifyListener); 
 
   rangeCheckBox = new Button(parent, SWT.CHECK); 
   rangeCheckBox.setEnabled(true); 
   rangeCheckBox.setSelection(false); 
   rangeCheckBox.addListener(SWT.Selection, rangeCheckBoxListener); 
   startText = new Text(parent, textStyle); 
   startText.addModifyListener(modifyListener); 
   stopText = new Text(parent, textStyle); 
   stopText.addModifyListener(modifyListener); 
   stepText = new Text(parent, textStyle); 
   stepText.addModifyListener(modifyListener); 
   enableWidgets(); 
  
 
  private Listener listCheckBoxListener = new Listener() { 
   public void handleEvent(Event event) { 
    if (listCheckBox.getSelection()) { 
     listText.forceFocus(); 
     rangeCheckBox.setSelection(false); 
    
    enableWidgets(); 
    validatePage(); 
   
  }; 
 
  private Listener rangeCheckBoxListener = new Listener() { 
   public void handleEvent(Event event) { 
    if (rangeCheckBox.getSelection()) { 
     startText.forceFocus(); 
     listCheckBox.setSelection(false); 
    
    enableWidgets(); 
    validatePage(); 
   
  }; 
 
  private void enableWidgets() { 
   boolean listEnabled = listCheckBox.getSelection(); 
   listText.setEnabled(listEnabled); 
 
   boolean rangeEnabled = rangeCheckBox.getSelection(); 
   startText.setEnabled(rangeEnabled); 
   stopText.setEnabled(rangeEnabled); 
   stepText.setEnabled(rangeEnabled); 
  
 
  public String getName() { 
   return name; 
  
 
  private Number[] getCommaSeparatedDoubleValues(String text) 
    throws Exception { 
   String[] values = text.split("(\\s)*,(\\s)*"); 
   if (values.length == 0) { 
    throw (new Exception("No comma separated values")); 
   
   Number[] list = new Number[values.length]; 
   for (int i = 0; i < values.length; i++) { 
    double current = Double.parseDouble(values[i]); 
    if (current < 0) { 
     throw new Exception("zero number"); 
    
    list[i] = current; 
   
   return list; 
  
 
  /*
   * Allows the callers to obtain the double values without worrying about 
   * any errors. All errors should be caught before the user presses 
   * finish and not allow the user to press finish when there exists some 
   * errors. 
   */
 
  public Number[] getDoubleValues() { 
   try { 
    return obtainDoubleValues(); 
   catch (Exception e) { 
    System.out.println(e.getMessage()); 
    return new Number[0]; 
   
  
 
  private Number[] obtainDoubleValues() throws Exception { 
   if (listCheckBox.getSelection()) { 
    String text = listText.getText().trim(); 
    Number[] list = getCommaSeparatedDoubleValues(text); 
    // Could check here if list has zero length but that 
    // should already be checked by getCommaSep..  
    return list; 
   
   if (rangeCheckBox.getSelection()) { 
    String startS = startText.getText().trim(); 
    String stopS = stopText.getText().trim(); 
    String stepS = stepText.getText().trim(); 
    double start = Double.parseDouble(startS); 
    double stop = Double.parseDouble(stopS); 
    double step = Double.parseDouble(stepS); 
 
    if (start > stop) { 
     throw new Exception("start value higher than stop value"); 
    
    if (step > (stop - start)) { 
     throw new Exception( 
       "step value too high (step > (stop - start)"); 
    
    if (step == 0){ 
     throw new Exception ("step value zero"); 
    
    if (step < 0){ 
     throw new Exception ("step value negative"); 
    
 
    LinkedList<Number> numbers = new LinkedList<Number>(); 
    for (; start <= stop; start += step) { 
     numbers.add(start); 
    
     
    // I guess this should never really happen since 
    // it would only do so if either of the above to 
    // error conditions were met, in which case we wouldn't 
    // get here. 
    if (numbers.size() == 0){ 
     throw new Exception ("No values specified"); 
    
     
    Number[] list = new Number[numbers.size()]; 
    for (int i = 0; i < numbers.size(); i++) { 
     list[i] = numbers.get(i); 
    
    return list; 
   
   // If neither checkbox is checked then we shouldn't 
   // really be here but we should return something 
   // which is just the empty result. 
   return new Number[0]; 
  
 
  /*
   * Returns the empty string in the case that the array input is valid 
   * and some error message otherwise 
   */
 
  public String validString() { 
   try { 
    obtainDoubleValues(); 
   catch (Exception e) { 
    return e.getMessage(); 
   
   // If we haven't returned by now then we must 
   // have a valid array input. 
   return ""
  
 
 
 
}