| // ProcessorControl.java |
| package org.eclipse.stem.util.analysis.views; |
| |
| /******************************************************************************* |
| * Copyright (c) 2007, 2008 IBM Corporation and others. |
| * All rights reserved. This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License v1.0 |
| * which accompanies this distribution, and is available at |
| * http://www.eclipse.org/legal/epl-v10.html |
| * |
| * Contributors: |
| * IBM Corporation - initial API and implementation |
| *******************************************************************************/ |
| |
| import java.io.BufferedReader; |
| import java.io.File; |
| import java.text.DateFormat; |
| import java.text.SimpleDateFormat; |
| import java.util.Calendar; |
| import java.util.Date; |
| import java.util.Map; |
| import java.util.StringTokenizer; |
| |
| import org.eclipse.stem.analysis.LogInitializationException; |
| import org.eclipse.stem.util.analysis.DataProcessor; |
| import org.eclipse.swt.SWT; |
| import org.eclipse.swt.events.ModifyEvent; |
| import org.eclipse.swt.events.ModifyListener; |
| import org.eclipse.swt.events.SelectionAdapter; |
| import org.eclipse.swt.events.SelectionEvent; |
| import org.eclipse.swt.layout.FormAttachment; |
| import org.eclipse.swt.layout.FormData; |
| import org.eclipse.swt.layout.FormLayout; |
| import org.eclipse.swt.layout.GridLayout; |
| import org.eclipse.swt.widgets.Button; |
| import org.eclipse.swt.widgets.Composite; |
| import org.eclipse.swt.widgets.Control; |
| import org.eclipse.swt.widgets.DirectoryDialog; |
| import org.eclipse.swt.widgets.Display; |
| import org.eclipse.swt.widgets.FileDialog; |
| import org.eclipse.swt.widgets.Label; |
| import org.eclipse.swt.widgets.Shell; |
| import org.eclipse.swt.widgets.Spinner; |
| import org.eclipse.swt.widgets.Text; |
| |
| /** |
| * GUI for processing data - reading incidence data from files (file names |
| * keyed by location) and creating the new format CSV files for STEM |
| */ |
| public class ProcessorControl extends AnalysisControl { |
| |
| /** |
| * The format of the time in the input files |
| */ |
| private static final String TIME_FORMAT = "yyyy-MM-dd"; |
| |
| /** |
| * Input text field for the source folder of the raw data |
| */ |
| protected static Text sourceFolder; |
| |
| /** |
| * Input text field for the target folder of the processed data |
| */ |
| protected static Text targetFolder; |
| |
| /** |
| * Input text field for the population data file |
| */ |
| protected static Text populationDataFile; |
| |
| /** |
| * Recovery rate |
| */ |
| protected static Spinner recoveryRate; |
| |
| /** |
| * Susceptible rate |
| */ |
| protected static Spinner susceptibleRate; |
| |
| /** |
| * Immunity loss rate |
| */ |
| protected static Spinner immunityLossRate; |
| |
| /** |
| * Population size in the start year |
| */ |
| protected static Spinner populationSizeStartYear; |
| |
| /** |
| * Population size in the end year |
| */ |
| protected static Spinner populationSizeEndYear; |
| |
| /** |
| * Button to trigger the data processing |
| */ |
| protected Button processButton; |
| |
| /** |
| * A label to report status |
| */ |
| protected static Label statusLabel; |
| |
| /** |
| * Start date of the data |
| */ |
| protected static Date startDate; |
| |
| /** |
| * End date of the data |
| */ |
| protected static Date endDate; |
| |
| /** |
| * @param parent |
| */ |
| public ProcessorControl(final Composite parent) { |
| |
| super(parent, SWT.None); |
| createContents(); |
| |
| } // ProcessorControl |
| |
| /** |
| * Create the contents of the plotter |
| */ |
| void createContents() { |
| |
| final Shell shell = this.getShell(); |
| |
| setLayout(new FormLayout()); |
| |
| identifiableTitle = new Label(this, SWT.NONE); |
| identifiableTitle.setText(Messages.getString("PROCESSOR.TITLE")); |
| Display display = this.getDisplay(); |
| identifiableTitle.setFont(this.getLargerFont(18, display)); |
| |
| // status label |
| statusLabel = new Label(this, SWT.BORDER); |
| statusLabel.setText(""); |
| |
| // source folder |
| Label sourceFolderLabel = new Label(this, SWT.BORDER); |
| sourceFolderLabel.setText(Messages.getString("PROCESSOR.SOURCEFOLDER")); |
| |
| sourceFolder = new Text(this, SWT.BORDER); |
| sourceFolder.setText(""); |
| sourceFolder.setEditable(false); // can only be selected through dialog |
| |
| Button selectSourceFolderButton = new Button(this, SWT.NONE); |
| selectSourceFolderButton.setText(Messages.getString("PROCESSOR.SELECTSOURCEFOLDER")); |
| selectSourceFolderButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(@SuppressWarnings("unused") final SelectionEvent e) { |
| final DirectoryDialog dd = new DirectoryDialog(shell, SWT.OPEN); |
| dd.setText(Messages.getString("PROCESSOR.SELECTSOURCEFOLDEDIALOGTITLE")); |
| |
| String dir = sourceFolder.getText(); |
| if((dir==null)||(dir.length()<1)) dir = ROOT_PATH; |
| |
| dd.setFilterPath(dir); |
| final String selected = dd.open(); |
| if(selected!=null) sourceFolder.setText(selected); |
| if(selected != null && selected.length() != 0) { |
| statusLabel.setText(Messages.getString("PROCESSOR.READINGDATA")); |
| populationSizeStartYear.setEnabled(false); |
| populationSizeEndYear.setEnabled(false); |
| initializeDates(); |
| if(startDate != null && endDate != null) { |
| DateFormat format = new SimpleDateFormat(TIME_FORMAT); |
| statusLabel.setText("Processing data from " + format.format(startDate) + " to " + format.format(endDate)); |
| |
| // initialize target folder to the source folder |
| if (targetFolder.getText() == null || targetFolder.getText().length() == 0) { |
| targetFolder.setText(selected); |
| } |
| |
| Calendar startCal = Calendar.getInstance(); |
| startCal.setTime(startDate); |
| Calendar endCal = Calendar.getInstance(); |
| endCal.setTime(endDate); |
| populationSizeStartYear.setEnabled(true); |
| if(startCal.get(Calendar.YEAR) < endCal.get(Calendar.YEAR)) { |
| populationSizeEndYear.setEnabled(true); |
| } |
| } else { |
| // failed to read data - invalid data |
| statusLabel.setText(Messages.getString("PROCESSOR.FAILEDREADDATA")); |
| sourceFolder.setText(""); |
| } |
| } |
| enableProcessButton(); |
| } |
| }); |
| |
| // target folder |
| Label targetFolderLabel = new Label(this, SWT.BORDER); |
| targetFolderLabel.setText(Messages.getString("PROCESSOR.TARGETFOLDER")); |
| |
| targetFolder = new Text(this, SWT.BORDER); |
| targetFolder.setBounds(10, 10, 100, 20); |
| targetFolder.setText(""); |
| targetFolder.setEditable(false); // can only be selected through dialog |
| |
| Button selectTargetFolderButton = new Button(this, SWT.NONE); |
| selectTargetFolderButton.setText(Messages.getString("PROCESSOR.SELECTTARGETFOLDER")); |
| selectTargetFolderButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(@SuppressWarnings("unused") final SelectionEvent e) { |
| final DirectoryDialog dd = new DirectoryDialog(shell, SWT.OPEN); |
| dd.setText(Messages.getString("PROCESSOR.SELECTTARGETFOLDEDIALOGTITLE")); |
| |
| String dir = targetFolder.getText(); |
| if((dir==null)||(dir.length()<1)) dir = ROOT_PATH; |
| |
| dd.setFilterPath(dir); |
| final String selected = dd.open(); |
| if(selected!=null) targetFolder.setText(selected); |
| enableProcessButton(); |
| } |
| }); |
| |
| // population data file |
| Label populationDataFileLabel = new Label(this, SWT.BORDER); |
| populationDataFileLabel.setText(Messages.getString("PROCESSOR.POPULATIONDATAFILE")); |
| |
| populationDataFile = new Text(this, SWT.BORDER); |
| populationDataFile.setBounds(10, 10, 100, 20); |
| populationDataFile.setText(""); |
| populationDataFile.setEditable(false); // can only be selected through dialog |
| |
| Button selectPopulationDataFileButton = new Button(this, SWT.NONE); |
| selectPopulationDataFileButton.setText(Messages.getString("PROCESSOR.SELECTPOPULATIONDATAFILE")); |
| selectPopulationDataFileButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(@SuppressWarnings("unused") final SelectionEvent e) { |
| final FileDialog fd = new FileDialog(shell, SWT.OPEN); |
| fd.setText(Messages.getString("PROCESSOR.SELECTPOPULATIONDATAFILEDIALOGTITLE")); |
| String beginSearch = populationDataFile.getText(); |
| if((beginSearch==null)||(beginSearch.length()<1)) beginSearch = ROOT_PATH; |
| |
| fd.setFilterPath(beginSearch); |
| final String selected = fd.open(); |
| if(selected!=null) populationDataFile.setText(selected); |
| enableProcessButton(); |
| } |
| }); |
| |
| // parameters |
| Label parametersLabel = new Label(this, SWT.BORDER); |
| parametersLabel.setText(Messages.getString("PROCESSOR.PARAMETERS")); |
| |
| Composite spinnerComposite = new Composite(this, SWT.BORDER); |
| GridLayout gridLayout = new GridLayout(); |
| gridLayout.numColumns = 6; |
| spinnerComposite.setLayout(gridLayout); |
| |
| // recovery rate |
| Label recoveryRateLabel = new Label(spinnerComposite, SWT.NONE); |
| recoveryRateLabel.setText(Messages.getString("PROCESSOR.RECOVERYRATE")); |
| |
| recoveryRate = new Spinner(spinnerComposite, SWT.NONE); |
| recoveryRate.setDigits(2); // allow 2 decimal places |
| recoveryRate.setMinimum(0); // set the minimum value to 0 |
| recoveryRate.setMaximum(100); // set the maximum value to 1.0 |
| recoveryRate.setIncrement(1); // set the increment value to 0.01 |
| recoveryRate.setSelection(20); // set the initial value 0.2 |
| recoveryRate.addModifyListener(new ModifyListener() { |
| public void modifyText(@SuppressWarnings("unused") final ModifyEvent e) { |
| enableProcessButton(); |
| } |
| }); |
| |
| // susceptible rate |
| Label susceptibleRateLabel = new Label(spinnerComposite, SWT.NONE); |
| susceptibleRateLabel.setText(Messages.getString("PROCESSOR.SUSCEPTIBLERATE")); |
| |
| susceptibleRate = new Spinner(spinnerComposite, SWT.NONE); |
| susceptibleRate.setDigits(3); // allow 3 decimal places |
| susceptibleRate.setMinimum(0); // set the minimum value to 0 |
| susceptibleRate.setMaximum(1000); // set the maximum value to 1.0 |
| susceptibleRate.setIncrement(1); // set the increment value to 0.001 |
| susceptibleRate.setSelection(333); // set the initial value 0.001 |
| susceptibleRate.addModifyListener(new ModifyListener() { |
| public void modifyText(@SuppressWarnings("unused") final ModifyEvent e) { |
| enableProcessButton(); |
| } |
| }); |
| |
| // immunity loss rate |
| Label immunityLossRateLabel = new Label(spinnerComposite, SWT.NONE); |
| immunityLossRateLabel.setText(Messages.getString("PROCESSOR.IMMUNITYLOSSRATE")); |
| |
| immunityLossRate = new Spinner(spinnerComposite, SWT.NONE); |
| immunityLossRate.setDigits(4); // allow 4 decimal places |
| immunityLossRate.setMinimum(0); // set the minimum value to 0 |
| immunityLossRate.setMaximum(10000); // set the maximum value to 1.0 |
| immunityLossRate.setIncrement(1); // set the increment value to 0.0001 |
| immunityLossRate.setSelection(9); // set the initial value 0.0009 |
| immunityLossRate.addModifyListener(new ModifyListener() { |
| public void modifyText(@SuppressWarnings("unused") final ModifyEvent e) { |
| enableProcessButton(); |
| } |
| }); |
| |
| spinnerComposite.pack(); |
| |
| // population size |
| Label populationSizeLabel = new Label(this, SWT.BORDER); |
| populationSizeLabel.setText(Messages.getString("PROCESSOR.POPULATIONSIZE")); |
| |
| Composite sizeComposite = new Composite(this, SWT.BORDER); |
| gridLayout = new GridLayout(); |
| gridLayout.numColumns = 4; |
| sizeComposite.setLayout(gridLayout); |
| |
| // start year |
| Label populationSizeStartYearLabel = new Label(sizeComposite, SWT.NONE); |
| populationSizeStartYearLabel.setText(Messages.getString("PROCESSOR.STARTYEAR")); |
| |
| populationSizeStartYear = new Spinner(sizeComposite, SWT.NONE); |
| populationSizeStartYear.setDigits(0); // allow 0 decimal places |
| populationSizeStartYear.setMinimum(0); // set the minimum value to 0 |
| populationSizeStartYear.setMaximum(100000000); // set the maximum value to 100,000,000 |
| populationSizeStartYear.setIncrement(1000); // set the increment value to 1000 |
| populationSizeStartYear.setSelection(10000000); // set the initial value 10,000,000 |
| populationSizeStartYear.setEnabled(false); |
| populationSizeStartYear.addModifyListener(new ModifyListener() { |
| public void modifyText(@SuppressWarnings("unused") final ModifyEvent e) { |
| enableProcessButton(); |
| } |
| }); |
| |
| // end year |
| Label populationSizeEndYearLabel = new Label(sizeComposite, SWT.NONE); |
| populationSizeEndYearLabel.setText(Messages.getString("PROCESSOR.ENDYEAR")); |
| |
| populationSizeEndYear = new Spinner(sizeComposite, SWT.NONE); |
| populationSizeEndYear.setDigits(0); // allow 0 decimal places |
| populationSizeEndYear.setMinimum(0); // set the minimum value to 0 |
| populationSizeEndYear.setMaximum(100000000); // set the maximum value to 100,000,000 |
| populationSizeEndYear.setIncrement(1000); // set the increment value to 1000 |
| populationSizeEndYear.setSelection(10000000); // set the initial value 10,000,000 |
| populationSizeEndYear.setEnabled(false); |
| populationSizeEndYear.addModifyListener(new ModifyListener() { |
| public void modifyText(@SuppressWarnings("unused") final ModifyEvent e) { |
| enableProcessButton(); |
| } |
| }); |
| |
| sizeComposite.pack(); |
| |
| // process button |
| processButton = new Button(this, SWT.NONE); |
| processButton.setText(Messages.getString("PROCESSOR.PROCESS")); |
| processButton.addSelectionListener(new SelectionAdapter() { |
| public void widgetSelected(@SuppressWarnings("unused") final SelectionEvent e) { |
| try { |
| DataProcessor processor = new DataProcessor(); |
| processor.process( |
| sourceFolder.getText(), |
| targetFolder.getText(), |
| startDate, |
| endDate, |
| populationDataFile.getText(), |
| Long.parseLong(populationSizeStartYear.getText()), |
| Long.parseLong(populationSizeEndYear.getText()), |
| Double.parseDouble(recoveryRate.getText()), |
| Double.parseDouble(susceptibleRate.getText()), |
| Double.parseDouble(immunityLossRate.getText())); |
| statusLabel.setText(Messages.getString("COMMON.DONE")); |
| } catch(LogInitializationException ex) { |
| statusLabel.setText(ex.getMessage()); |
| } |
| } |
| }); |
| enableProcessButton(); |
| |
| createFormData(null, identifiableTitle, null, null, 0); |
| createFormData(identifiableTitle, sourceFolderLabel, sourceFolder, selectSourceFolderButton, 5); |
| createFormData(sourceFolderLabel, targetFolderLabel, targetFolder, selectTargetFolderButton, 5); |
| createFormData(targetFolderLabel, populationDataFileLabel, populationDataFile, selectPopulationDataFileButton, 5); |
| createFormData(populationDataFileLabel, parametersLabel, spinnerComposite, null, 20); |
| createFormData(spinnerComposite, populationSizeLabel, sizeComposite, null, 5); |
| createFormData(sizeComposite, null, null, processButton, 5); |
| createFormData(processButton, statusLabel, null, null, 100); |
| |
| } // createContents |
| |
| /** |
| * Enable or disable the process button |
| */ |
| void enableProcessButton() { |
| |
| boolean enabled = true; |
| if (enabled && (sourceFolder.getText() == null || sourceFolder.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (targetFolder.getText() == null || targetFolder.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (populationDataFile.getText() == null || populationDataFile.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (recoveryRate.getText() == null || recoveryRate.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (susceptibleRate.getText() == null || susceptibleRate.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (immunityLossRate.getText() == null || immunityLossRate.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (populationSizeStartYear.getText() == null || populationSizeStartYear.getText().length() == 0)) |
| enabled = false; |
| if (enabled && (populationSizeEndYear.getText() == null || populationSizeEndYear.getText().length() == 0)) |
| enabled = false; |
| this.processButton.setEnabled(enabled); |
| |
| } // enableProcessButton |
| |
| /** |
| * Initializes the start and end dates of the data. |
| */ |
| protected void initializeDates() { |
| |
| startDate = null; |
| endDate = null; |
| |
| File file = new File(sourceFolder.getText()); |
| |
| File[] allFiles = file.listFiles(); |
| for (int i = 0; i < allFiles.length; i++) { |
| String fileName = allFiles[i].getName(); |
| if (fileName.indexOf(".txt") >= 0) { |
| BufferedReader fileReader = DataProcessor.openReader(allFiles[i]); |
| if (fileReader != null) { |
| try { |
| String buffer = null; |
| fileReader.readLine(); // skip the header |
| while (DataProcessor.EOF(buffer = fileReader.readLine()) != true) { |
| StringTokenizer tokenizer = new StringTokenizer(buffer, ","); //$NON-NLS-1$ |
| if(tokenizer.countTokens() == 3) { |
| tokenizer.nextToken(","); // iteration |
| String time = tokenizer.nextToken(","); |
| tokenizer.nextToken(","); // incidence |
| |
| if(time!= null) { |
| DateFormat format = new SimpleDateFormat(TIME_FORMAT); |
| Date date = format.parse(time); |
| if(startDate == null || date.before(startDate)) { |
| startDate = date; |
| } |
| if(endDate == null || date.after(endDate)) { |
| endDate = date; |
| } |
| } |
| } |
| } |
| } catch(Exception ex) { |
| // ignore |
| } |
| } // if ! null |
| } // if valid filename |
| } // for |
| |
| } // initializeDates |
| |
| /** |
| * Constructs a new instance of FormData which contains Label, Control and Button. |
| * |
| * @param topControl The control at the top of this FormData |
| * @param label The label of this FormData |
| * @param text The control of this FormData |
| * @param button The button of this FormData |
| * @param spacer Vertical space between controls |
| */ |
| |
| private void createFormData(Control topControl, Label label, Control text, Button button, int spacer) { |
| |
| // label |
| if (label != null) { |
| final FormData labelFormData = new FormData(); |
| if (topControl != null) |
| labelFormData.top = new FormAttachment(topControl, spacer); |
| else |
| labelFormData.top = new FormAttachment(0, 0); |
| // labelFormData.bottom = new FormAttachment(bottom, 0); |
| labelFormData.left = new FormAttachment(0, 0); |
| int numerator = 15; |
| if (text == null && button == null) |
| numerator = 100; |
| labelFormData.right = new FormAttachment(numerator, 0); |
| label.setLayoutData(labelFormData); |
| } |
| |
| // text field |
| if (text != null) { |
| final FormData textFieldFormData = new FormData(); |
| if (topControl != null) |
| textFieldFormData.top = new FormAttachment(topControl, spacer); |
| else |
| textFieldFormData.top = new FormAttachment(0, 0); |
| // textFieldFormData.bottom = new FormAttachment(bottom, 0); |
| if (label != null) |
| textFieldFormData.left = new FormAttachment(label, 5); |
| else |
| textFieldFormData.left = new FormAttachment(0, 0); |
| int numerator = 80; |
| if (button == null) |
| numerator = 100; |
| textFieldFormData.right = new FormAttachment(numerator, 0); |
| text.setLayoutData(textFieldFormData); |
| } |
| |
| // selection button |
| if (button != null) { |
| final FormData buttonFormData = new FormData(); |
| if (topControl != null) |
| buttonFormData.top = new FormAttachment(topControl, 0); |
| else |
| buttonFormData.top = new FormAttachment(0, 0); |
| // buttonFormData.bottom = new FormAttachment(bottom, 0); |
| if (text != null) |
| buttonFormData.left = new FormAttachment(text, 5); |
| else if (label != null) |
| buttonFormData.left = new FormAttachment(label, 5); |
| else |
| buttonFormData.left = new FormAttachment(0, 0); |
| buttonFormData.right = new FormAttachment(100, 0); |
| button.setLayoutData(buttonFormData); |
| } |
| |
| } // createFormData |
| |
| /** |
| * @see org.eclipse.swt.widgets.Widget#dispose() |
| */ |
| @Override |
| public void dispose() { |
| super.dispose(); |
| } // dispose |
| |
| /** |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#remove() |
| */ |
| public void remove() { |
| // do nothing for now |
| } // remove |
| |
| /** |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#initializeHeader(String) |
| */ |
| protected void initializeHeader(@SuppressWarnings("unused") String folderName) { |
| // do nothing for now |
| } // initializeHeader |
| |
| /** |
| * Not used |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#getValues(int, int) |
| */ |
| @Override |
| public double[] getValues(@SuppressWarnings("unused")int chartIndex, @SuppressWarnings("unused")int trajectory) { |
| return null; |
| } // getValues |
| |
| /** |
| * Not used |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#getProperty(int, int) |
| */ |
| public String getProperty(@SuppressWarnings("unused") int chartIndex, @SuppressWarnings("unused") int state) { |
| return null; |
| } // getProperty |
| |
| /** |
| * Not used |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#getNumProperties(int chartIndex) |
| */ |
| public int getNumProperties(@SuppressWarnings("unused") int chartIndex) { |
| return 0; |
| } // getNumProperties |
| |
| /** |
| * @see org.eclipse.stem.util.analysis.views.AnalysisControl#getControlParametersMap() |
| */ |
| public Map<String, Object> getControlParametersMap() { |
| |
| // add nothing for now |
| return controlParametersMap; |
| } // getControlParametersMap |
| |
| } // ProcessorControl |