VerifyDialog.java

package edu.udel.cis.vsl.tass.gui.impl;

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextArea;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import edu.udel.cis.vsl.tass.config.VerifyConfiguration;
import edu.udel.cis.vsl.tass.config.RunConfiguration.DeadlockStrategy;
import edu.udel.cis.vsl.tass.config.RunConfiguration.ReductionStrategy;
import edu.udel.cis.vsl.tass.util.Strings;

/**
 * A dialog window that allows user to select different options in verify mode.
 * 
 * @author Yi Wei
 * 
 */
public class VerifyDialog extends JDialog implements ActionListener {

	// Content panel
	private JPanel contentPanel = null;

	// First section of the dialog is source file selection.
	private JTextField fileSelection = null;
	private JLabel fileSelectionLabel = null;
	private JButton browseFile = null;
	private JFileChooser fileChooser = null;
	private JPanel filePanel = null;
	private File sourceFile = null;

	// Second section contains verify options.
	private JRadioButton urgentReduce = null;
	private JRadioButton standardReduce = null;
	private JPanel reducePanel = null;
	private ButtonGroup reduceGroup = null;

	private JRadioButton absoluteDeadlock = null;
	private JRadioButton potentialDeadlock = null;
	private JRadioButton ignoreDeadlock = null;
	private JPanel deadlockPanel = null;
	private ButtonGroup deadlockGroup = null;

	private JCheckBox verboseOption = null;
	private JCheckBox simplifyOption = null;
	private JSpinner processNumberOption = null;
	private JLabel processNumberLabel = null;
	private SpinnerNumberModel processNumberModel = null;
	private JPanel otherOptionsPanel = null;

	private JPanel optionsPanel = null;

	// Third section contains input values for input variables
	private JLabel inputLabel = null;
	private JTextArea inputValueArea = null;
	private JScrollPane scrollPanel = null;
	private JPanel inputPanel = null;

	// Buttons
	private JButton defaultButton = null;
	private JButton cancelButton = null;
	private JButton verifyButton = null;
	private JPanel buttonPanel = null;

	public static final long serialVersionUID = 1;

	public VerifyDialog() {
		initializeComponents();
	}

	private void initializeComponents() {
		this.setTitle("Verify Options");
		this.setSize(TassUserFrame.frameWidth / 2, TassUserFrame.frameHeight);
		this.setModal(true);
		this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
		this.setResizable(false);

		this.contentPanel = new JPanel();
		this.setContentPane(this.contentPanel);
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints con = new GridBagConstraints();
		this.contentPanel.setLayout(layout);
		this.contentPanel.setBorder(BorderFactory.createEtchedBorder());

		// File selection
		setUpFileChooser();
		con.gridy = 0;
		con.weighty = 0.5;
		con.fill = GridBagConstraints.HORIZONTAL;
		this.contentPanel.add(this.filePanel, con);

		// Options
		setUpVerifyOptions();
		con.gridy = 1;
		this.contentPanel.add(this.optionsPanel, con);

		// Input values
		setUpInputValueArea();
		con.gridy = 2;
		this.contentPanel.add(this.inputPanel, con);

		// Buttons
		setUpButtons();
		con.gridy = 3;
		con.gridheight = GridBagConstraints.REMAINDER;
		this.contentPanel.add(this.buttonPanel, con);

		this.setVisible(true);
	}

	private void setUpFileChooser() {

		this.filePanel = new JPanel();

		// Layout manager
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints con = new GridBagConstraints();

		this.filePanel.setLayout(layout);

		// Label
		this.fileSelectionLabel = new JLabel("Select source file:");
		con.fill = GridBagConstraints.HORIZONTAL;
		con.gridwidth = GridBagConstraints.REMAINDER;
		layout.setConstraints(this.fileSelectionLabel, con);
		this.filePanel.add(this.fileSelectionLabel);

		// Text field
		this.fileSelection = new JTextField(38);
		layout.setConstraints(this.fileSelection, con);
		this.fileSelectionLabel.setLabelFor(this.fileSelection);
		this.filePanel.add(this.fileSelection);

		// "Browse" button
		this.browseFile = new JButton("Browse");
		con.fill = GridBagConstraints.NONE;
		con.anchor = GridBagConstraints.EAST;
		layout.setConstraints(this.browseFile, con);
		this.browseFile.addActionListener(this);

		this.filePanel.add(this.browseFile);
	}

	private void setUpVerifyOptions() {

		// Reduce strategy options.
		this.urgentReduce = new JRadioButton("Urgent");
		// Default choice
		this.urgentReduce.setSelected(true);
		this.standardReduce = new JRadioButton("Standard");
		this.reduceGroup = new ButtonGroup();
		this.reduceGroup.add(urgentReduce);
		this.reduceGroup.add(standardReduce);

		this.reducePanel = new JPanel();
		this.reducePanel.setLayout(new GridLayout(2, 0));
		this.reducePanel.setBorder(BorderFactory
				.createTitledBorder("Reduction"));
		this.reducePanel.add(this.urgentReduce);
		this.reducePanel.add(this.standardReduce);

		// Deadlock strategy options.
		this.absoluteDeadlock = new JRadioButton("Absolute");
		// Default choice
		this.absoluteDeadlock.setSelected(true);
		this.potentialDeadlock = new JRadioButton("Potential");
		this.ignoreDeadlock = new JRadioButton("Ignore");
		this.deadlockGroup = new ButtonGroup();
		this.deadlockGroup.add(absoluteDeadlock);
		this.deadlockGroup.add(potentialDeadlock);
		this.deadlockGroup.add(ignoreDeadlock);

		this.deadlockPanel = new JPanel();
		this.deadlockPanel.setBorder(BorderFactory
				.createTitledBorder("Deadlock"));
		this.deadlockPanel.setLayout(new GridLayout(3, 0));
		this.deadlockPanel.add(this.absoluteDeadlock);
		this.deadlockPanel.add(this.potentialDeadlock);
		this.deadlockPanel.add(this.ignoreDeadlock);

		// Other options.
		this.verboseOption = new JCheckBox("Verbose");
		this.verboseOption.setSelected(false);
		this.simplifyOption = new JCheckBox("Simplify");
		this.simplifyOption.setSelected(false);
		this.processNumberLabel = new JLabel("Process Number:");
		this.processNumberModel = new SpinnerNumberModel();
		this.processNumberModel.setValue(1);
		this.processNumberModel.setMinimum(1);
		this.processNumberModel.setStepSize(1);
		this.processNumberOption = new JSpinner(this.processNumberModel);
		this.processNumberLabel.setLabelFor(this.processNumberOption);

		this.otherOptionsPanel = new JPanel();
		this.otherOptionsPanel.setBorder(BorderFactory
				.createTitledBorder("Other"));
		this.otherOptionsPanel.setLayout(new GridLayout(4, 1));
		this.otherOptionsPanel.add(this.verboseOption);
		this.otherOptionsPanel.add(this.simplifyOption);
		this.otherOptionsPanel.add(this.processNumberLabel);
		this.otherOptionsPanel.add(this.processNumberOption);

		this.optionsPanel = new JPanel();
		this.optionsPanel
				.setBorder(BorderFactory.createTitledBorder("Options"));
		this.optionsPanel.setLayout(new GridLayout(1, 3));
		this.optionsPanel.add(this.reducePanel);
		this.optionsPanel.add(this.deadlockPanel);
		this.optionsPanel.add(this.otherOptionsPanel);
	}

	private void setUpInputValueArea() {

		this.inputPanel = new JPanel();
		// Layout manager
		GridBagLayout layout = new GridBagLayout();
		GridBagConstraints con = new GridBagConstraints();
		this.inputPanel.setLayout(layout);

		// Input label
		this.inputLabel = new JLabel("Input Values:");
		con.gridx = 0;
		con.gridwidth = GridBagConstraints.REMAINDER;
		con.fill = GridBagConstraints.HORIZONTAL;
		layout.setConstraints(this.inputLabel, con);
		this.inputPanel.add(this.inputLabel);

		// Input area
		this.inputValueArea = new JTextArea(7, 38);
		this.inputValueArea.setLineWrap(true);
		this.inputValueArea.setWrapStyleWord(true);
		this.inputLabel.setLabelFor(this.inputValueArea);
		this.inputValueArea.setBorder(BorderFactory.createLoweredBevelBorder());

		this.scrollPanel = new JScrollPane();
		this.scrollPanel.getViewport().add(this.inputValueArea);
		layout.setConstraints(this.inputValueArea, con);
		this.inputPanel.add(this.scrollPanel);
	}

	private void setUpButtons() {

		// "Default" button
		this.defaultButton = new JButton("Default");
		// Restore the default setting
		this.defaultButton.addActionListener(this);

		// "Cancel" button
		this.cancelButton = new JButton("Cancel");
		// Close the dialog
		this.cancelButton.addActionListener(this);

		// "Verify" button
		this.verifyButton = new JButton("Verify");
		// Run TASS in verify mode.
		this.verifyButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent event) {
				launchVerification();
			}
		});

		this.buttonPanel = new JPanel();
		this.buttonPanel.add(this.defaultButton);
		this.buttonPanel.add(this.cancelButton);
		this.buttonPanel.add(this.verifyButton);
	}

	public void actionPerformed(ActionEvent event) {

		if (event.getSource().equals(this.browseFile)) {
			if (this.fileChooser == null) {
				this.fileChooser = new JFileChooser();
				this.fileChooser.addChoosableFileFilter(new SourceFilter());
				this.fileChooser.setAcceptAllFileFilterUsed(false);
				this.fileChooser.setDialogTitle("Select MiniMP source file");
			}
			int returnValue = this.fileChooser.showDialog(this, "Select");
			if (returnValue == JFileChooser.APPROVE_OPTION) {
				this.sourceFile = this.fileChooser.getSelectedFile();
				this.fileSelection.setText(this.sourceFile.getAbsolutePath());
			}
		} else if (event.getSource().equals(this.cancelButton)) {
			this.setVisible(false);
		} else if (event.getSource().equals(this.defaultButton)) {
			this.urgentReduce.setSelected(true);
			this.absoluteDeadlock.setSelected(true);
			this.verboseOption.setSelected(false);
			this.simplifyOption.setSelected(false);
			this.processNumberOption.setValue(1);
			this.fileSelection.setText("");
			this.inputValueArea.setText("");
		}
	}

	private void launchVerification() {

		VerifyConfiguration configuration = new VerifyConfiguration();

		if (this.sourceFile == null) {
			// If source file field is empty, give the reminder.
			if (this.fileSelection.getText().length() == 0) {
				JOptionPane.showMessageDialog(this,
						"Please type in the source file name", "Information",
						JOptionPane.INFORMATION_MESSAGE);
				return;
			} else {
				this.sourceFile = new File(this.fileSelection.getText());
				// Give the error message if source file doesn't exist.
				if (!this.sourceFile.exists()) {
					JOptionPane.showMessageDialog(this, "Source file \""
							+ this.fileSelection.getText()
							+ "\" doesn't exist.", "Error",
							JOptionPane.ERROR_MESSAGE);
					return;
				}
			}
		}
		configuration.setSourceFile(this.sourceFile);
		configuration.setModelName(Strings.rootName(this.sourceFile.getName()));

		// Set reduce strategy
		if (this.urgentReduce.isSelected()) {
			configuration.setReductionStrategy(ReductionStrategy.URGENT);
		} else {
			configuration.setReductionStrategy(ReductionStrategy.STANDARD);
		}

		// Set deadlock strategy
		if (this.absoluteDeadlock.isSelected()) {
			configuration.setDeadlockStrategy(DeadlockStrategy.ABSOLUTE);
		} else if (this.potentialDeadlock.isSelected()) {
			configuration.setDeadlockStrategy(DeadlockStrategy.POTENTIAL);
		} else {
			configuration.setDeadlockStrategy(DeadlockStrategy.IGNORE);
		}

		if (this.verboseOption.isSelected()) {
			configuration.setVerbose(true);
		}

		if (this.simplifyOption.isSelected()) {
			configuration.setSimplify(true);
		}

		configuration.setNumProcs((Integer) (this.processNumberOption
				.getValue()));

		if (this.inputValueArea.getText().length() > 0) {
			String[] inputValues = this.inputValueArea.getText().split(" ");

			for (int i = 0; i < inputValues.length; i++) {
				int equalsIndex = inputValues[i].indexOf('=');
				String variableName;
				String valueString;
				Object value;
				int decimalPosition = inputValues[i].indexOf('.');

				if (equalsIndex < 0) {
					JOptionPane
							.showMessageDialog(
									this,
									"Syntax for input variable value is \"-inputN=V\",\n"
											+ " where N is an input variable name and V a value.",
									"Format Error", JOptionPane.ERROR_MESSAGE);
					return;
				}
				variableName = inputValues[i].substring(6, equalsIndex);
				valueString = inputValues[i].substring(equalsIndex + 1,
						inputValues[i].length());
				if ("true".equals(valueString)) {
					value = new Boolean(true);
				} else if ("false".equals(valueString)) {
					value = new Boolean(false);
				} else if (decimalPosition < 0) {
					try {
						value = new Integer(valueString);
					} catch (NumberFormatException e) {
						JOptionPane.showMessageDialog(this,
								"Illegal numeric value for input: "
										+ inputValues[i], "Format Error",
								JOptionPane.ERROR_MESSAGE);
						return;
					}
				} else {
					try {
						value = new Double(valueString);
					} catch (NumberFormatException e) {
						JOptionPane.showMessageDialog(this,
								"Illegal numeric value for input: "
										+ inputValues[i], "Format Error",
								JOptionPane.ERROR_MESSAGE);
						return;
					}
				}
				configuration.setInput(variableName, value);
			}
		}
		TassUserFrame.setConfiguration(configuration);
		TassUserFrame.optionsSet();
		setVisible(false);
	}
}