CompareDialog.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.CompareConfiguration;
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 compare mode.
 * 
 * @author Yi Wei
 * 
 */
public class CompareDialog extends JDialog implements ActionListener {

  // Content panel
  private JPanel contentPanel = null;

  // First section of the dialog is source file selection.
  private JTextField specFileSelection = null;
  private JLabel specFileSelectionLabel = null;
  private JTextField implFileSelection = null;
  private JLabel implFileSelectionLabel = null;
  private JButton browseSpecFile = null;
  private JButton browseImplFile = null;
  private JFileChooser fileChooser = null;
  private JPanel filePanel = null;
  private File specFile = null;
  private File implFile = 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 JCheckBox loopOption = null;
  private JSpinner specProcessNumberOption = null;
  private JLabel specProcessNumberLabel = null;
  private JSpinner implProcessNumberOption = null;
  private JLabel implProcessNumberLabel = null;
  private SpinnerNumberModel specProcessNumberModel = null;
  private SpinnerNumberModel implProcessNumberModel = 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 compareButton = null;
  private JPanel buttonPanel = null;

  public static final long serialVersionUID = 2;
  
  public CompareDialog() {
    initializeComponents();
  }

  private void initializeComponents() {
    this.setTitle("Compare 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
    setUpCompareOptions();
    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);

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

    // Spec Text field
    this.specFileSelection = new JTextField(38);
    layout.setConstraints(this.specFileSelection, con);
    this.specFileSelectionLabel.setLabelFor(this.specFileSelection);
    this.filePanel.add(this.specFileSelection);

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

    this.filePanel.add(this.browseSpecFile);

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

    // Impl Text field
    this.implFileSelection = new JTextField(38);
    layout.setConstraints(this.implFileSelection, con);
    this.implFileSelectionLabel.setLabelFor(this.implFileSelection);
    this.filePanel.add(this.implFileSelection);

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

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

  private void setUpCompareOptions() {

    // 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.loopOption = new JCheckBox("Loop");
    this.loopOption.setSelected(false);

    this.specProcessNumberLabel = new JLabel("Spec Process Number");
    this.specProcessNumberModel = new SpinnerNumberModel();
    this.specProcessNumberModel.setValue(1);
    this.specProcessNumberModel.setMinimum(1);
    this.specProcessNumberModel.setStepSize(1);

    this.implProcessNumberModel = new SpinnerNumberModel();
    this.implProcessNumberModel.setValue(1);
    this.implProcessNumberModel.setMinimum(1);
    this.implProcessNumberModel.setStepSize(1);

    this.specProcessNumberOption = new JSpinner(this.specProcessNumberModel);
    this.specProcessNumberLabel.setLabelFor(this.specProcessNumberOption);
    this.implProcessNumberLabel = new JLabel("Impl Process Number");
    this.implProcessNumberOption = new JSpinner(this.implProcessNumberModel);
    this.implProcessNumberLabel.setLabelFor(this.implProcessNumberOption);

    this.otherOptionsPanel = new JPanel();
    this.otherOptionsPanel.setBorder(BorderFactory.createTitledBorder("Other"));
    this.otherOptionsPanel.setLayout(new GridLayout(7, 1));
    this.otherOptionsPanel.add(this.verboseOption);
    this.otherOptionsPanel.add(this.simplifyOption);
    this.otherOptionsPanel.add(this.loopOption);
    this.otherOptionsPanel.add(this.specProcessNumberLabel);
    this.otherOptionsPanel.add(this.specProcessNumberOption);
    this.otherOptionsPanel.add(this.implProcessNumberLabel);
    this.otherOptionsPanel.add(this.implProcessNumberOption);

    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);

    // "Compare" button
    this.compareButton = new JButton("Compare");
    // Run TASS in compare mode.
    this.compareButton.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.compareButton);
  }

  public void actionPerformed(ActionEvent event) {

    if (event.getSource().equals(this.browseSpecFile)
        || event.getSource().equals(this.browseImplFile)) {
      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) {
        if (event.getSource().equals(this.browseSpecFile)) {
          this.specFile = this.fileChooser.getSelectedFile();
          this.specFileSelection.setText(this.specFile.getAbsolutePath());
        } else {
          this.implFile = this.fileChooser.getSelectedFile();
          this.implFileSelection.setText(this.implFile.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.specProcessNumberOption.setValue(1);
      this.implProcessNumberOption.setValue(1);
      this.specFileSelection.setText("");
      this.implFileSelection.setText("");
      this.inputValueArea.setText("");
    }
  }
  
 private void launchVerification() {
    
    CompareConfiguration configuration = new CompareConfiguration();

    if(this.specFile == null)
    {
      // If source file field is empty, give the reminder.
      if(this.specFileSelection.getText().length() == 0) {
        JOptionPane.showMessageDialog(this, "Please type in the specification file name", "Information", JOptionPane.INFORMATION_MESSAGE);
        return;
      }
      else {
        this.specFile = new File(this.specFileSelection.getText());
        // Give the error message if source file doesn't exist.
        if(!this.specFile.exists()) {
          JOptionPane.showMessageDialog(this, "Specification file \"" + this.specFileSelection.getText() + "\" doesn't exist.", "Error", JOptionPane.ERROR_MESSAGE);
          return;
        }
      } 
    }
    
    if(this.implFile == null)
    {
      // If source file field is empty, give the reminder.
      if(this.implFileSelection.getText().length() == 0) {
        JOptionPane.showMessageDialog(this, "Please type in the implementation file name", "Information", JOptionPane.INFORMATION_MESSAGE);
        return;
      }
      else {
        this.implFile = new File(this.implFileSelection.getText());
        // Give the error message if source file doesn't exist.
        if(!this.implFile.exists()) {
          JOptionPane.showMessageDialog(this, "Implementation file \"" + this.implFileSelection.getText() + "\" doesn't exist.", "Error", JOptionPane.ERROR_MESSAGE);
          return;
        }
      } 
    }
    
    configuration.setSpecSourceFile(this.specFile);
    configuration.setImplSourceFile(this.implFile);
    configuration.setSpecModelName(Strings.rootName(this.specFile.getName()));
    configuration.setImplModelName(Strings.rootName(this.implFile.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);
    }
    
    if(this.loopOption.isSelected()) {
      configuration.setLoopTechnique(true);
    }
    
    configuration.setSpecNumProcs((Integer)(this.specProcessNumberOption.getValue()));
    configuration.setImplNumProcs((Integer)(this.implProcessNumberOption.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);
  }
}