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 ""; } } }