package jnormaliz;


import com.jezhumble.javasysmon.JavaSysMon;
import com.jezhumble.javasysmon.MemoryStats;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Desktop;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Label;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import java.util.EventObject;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JRadioButton;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.JToolBar;
import javax.swing.JToolBar.Separator;
import javax.swing.KeyStroke;
import javax.swing.LayoutStyle.ComponentPlacement;
import javax.swing.SwingConstants;
import javax.swing.event.ChangeEvent;
import javax.swing.event.DocumentEvent;
import javax.swing.event.UndoableEditEvent;
import org.jdesktop.application.Action;
import org.jdesktop.application.Application;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.print.PrinterException;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URI;
import java.text.MessageFormat;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.standard.JobName;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentListener;
import javax.swing.event.UndoableEditListener;
import javax.swing.filechooser.FileNameExtensionFilter;
import javax.swing.text.DefaultEditorKit;
import javax.swing.undo.UndoManager;

/**
 * This class implements jNormaliz main window, together with all actions
 */
public class MainView extends FrameView
        implements
        UndoableEditListener,
        ChangeListener,
        DocumentListener,
        Application.ExitListener,
        ActionListener {

    private File outputFile = null;
    private final NewFileDialog newFileDialog = new NewFileDialog(this, true);
    private NormalizWorker normalizWorker = null;

    /**
     * File name extension filter for *.in files
     */
    static final FileNameExtensionFilter inputFileFilter = new FileNameExtensionFilter(
            "Normaliz input files (*.in)", "in");

    // Support for undo operation
    private final UndoManager undoManager = new UndoManager();
    // Timer for elapsed time
    private final Timer timer = new Timer(1000, new ActionListener() {

        public void actionPerformed(ActionEvent e) {
            elapsedTimeLabel.setText("Elapsed time: " + elapsedTime.getElapsedTime());
            updateMemory();
        }
    });
    // Timer for memory count
    final Timer memoryTimer = new Timer(10000, new ActionListener() {

        public void actionPerformed(ActionEvent e) {
            updateMemory();
        }
    });
    private final ElapsedTime elapsedTime = new ElapsedTime();
    private final JavaSysMon javaSysMon;
    private File inputFile;
    private final JFileChooser fileChooser = new JFileChooser();
    private final HelpAlgorithmsDialog normalizAlgorithms =
            new HelpAlgorithmsDialog(this.getFrame());
    private boolean inputFileChangeSinceLastRun = true;
    private File outputFileWhenNormalizWasRun = null;
    private final Desktop desktop;

    /**
     * Get the current input file (if any).
     *
     * @return the current input file
     */
    public File getInputFile() {
        return inputFile;
    }

    /**
     * Changes the input file, updating interface and application state
     * accordingly.
     *
     * @param inputFile new input file
     */
    public void setInputFile(File inputFile) {
        this.inputFile = inputFile;

        if (inputFile != null) {
            // Sets new corresponding output file
            outputFile = new File(FileUtils.makeOutFileName(getInputFile().getAbsolutePath()));


            // Changes application state
            setFileLoaded(true);

            // Clears contents of output file tab
            resultTextArea.setText("");

            // Changes titles of the tabs to match the new input (and output)
            // files
            tabbedPane.setTitleAt(0, inputFile.getName());
            tabbedPane.setTitleAt(1, outputFile.getName());

            // Sets the new link to input file folder
            inputFilePathButton.setText("<html><a href=''>" + inputFile.getParentFile().getAbsolutePath() + "</a></html>");
        } else {
            // Changes the state of the application, which will trigger interface
            // updates
            setFileLoaded(false);
            outputFile = null;
            inputFilePathButton.setText("");
        }

        // Restarts undo state
        undoManager.discardAllEdits();
        updateUndoState();

        // Changes frame title
        updateFrameTitle();
    }
    private boolean fileChanged = false;

    /**
     * Tests if input file has unsaved changes
     * @return true if input file has unsaved changes, false otherwise.
     */
    public boolean isFileChanged() {
        return fileChanged;
    }

    private void updateFrameTitle() {
        String newTitle = getResourceMap().getString("Application.title");

        if (getInputFile() != null) {
            newTitle += " - " + getInputFile().getName();

            if (fileChanged) {
                newTitle += "*";
            }
        }

        this.getFrame().setTitle(newTitle);
    }

    private void updateUndoState() {
        setUndo(undoManager.canUndo());
    }

    private void stopTimer() {
        timer.stop();
        elapsedTimeLabel.setText("Elapsed time: " + elapsedTime.getElapsedTime());
    }

    /**
     * Called when a Normaliz execution is finished.
     * @param result true if the execution was ok, false if Normaliz reported
     * some error.
     */
    public void jobFinished(boolean result) {

        stopTimer();
        setRunning(false);
        normalizWorker = null;

        if (!result) {
            JOptionPane.showMessageDialog(null,
                    "Normaliz execution finished abnormally. Output results were NOT updated.\n"
                    + "See console for more information",
                    "ERROR",
                    JOptionPane.ERROR_MESSAGE);
        } else {
            try {
                // Only updates output file if it is still the same output
                // file as of the moment when Normaliz was run
                if (outputFileWhenNormalizWasRun == outputFile) {

                    // Reads the output file
                    resultTextArea.read(new FileReader(outputFile), null);

                    // Selects output tab
                    tabbedPane.setSelectedComponent(outputTab);
                }

                // If input file remains the same (same file and same contents)
                // as of the moment Normaliz was run, removes message about
                // possible mismatch between input and output file
                if (!inputFileChangeSinceLastRun) {
                    syncWarningLabel.setText("");
                }

            } catch (Exception e) {
                JOptionPane.showMessageDialog(this.getFrame(),
                        "Could not read output file:\n" + e.getMessage(),
                        "Error",
                        JOptionPane.WARNING_MESSAGE);
            }
        }
    }

    /**
     * Adds more text to the console area
     * @param text String to be added
     */
    public void updateConsole(String text) {
        consoleTextArea.append(text);
    }

    /**
     * Updates physical memory information
     */
    public void updateMemory() {
        if (javaSysMon != null) {
            final long totalMemory = javaSysMon.physical().getTotalBytes() / (1024 * 1024);
            final long freeMemory = javaSysMon.physical().getFreeBytes() / (1024 * 1024);

            final String displayedTotalMemory;
            final String displayedFreeMemory;

            if (totalMemory >= 1024) {
                displayedTotalMemory = String.format("%.1fG", totalMemory / 1024.);
            } else {
                displayedTotalMemory = String.format("%dM", totalMemory);
            }

            if (freeMemory >= 1024) {
                displayedFreeMemory = String.format("%.1fG", freeMemory / 1024.);
            } else {
                displayedFreeMemory = String.format("%dM", freeMemory);
            }

            memoryProgressBar.setMinimum(0);
            memoryProgressBar.setMaximum((int) totalMemory);
            memoryProgressBar.setValue((int) freeMemory);
            memoryProgressBar.setString(displayedFreeMemory + " / "
                    + displayedTotalMemory);
            memoryProgressBar.setToolTipText("Free " + displayedFreeMemory + " / Total "
                    + displayedTotalMemory);
        }
    }

    /**
     * Builds the main view of jNormaliz
     * @param app the application associated with this view
     */
    public MainView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // Desktop used to interact with the system desktop (opening files,
        // URLs etc.)
        if(Desktop.isDesktopSupported()) {
            desktop = Desktop.getDesktop();
        }
        else
            desktop = null;

        // Initializes file chooser for file operations
        fileChooser.setFileFilter(inputFileFilter);
        fileChooser.setAcceptAllFileFilterUsed(false);
        fileChooser.setCurrentDirectory(new File(System.getProperty("user.dir")));

        // Initializes memory monitoring code
        {
            JavaSysMon jsm = new JavaSysMon();
            if (jsm.osName() == null) {
                // unsupported operating system. No memory count will be
                // supplied
                javaSysMon = null;
            } else {
                javaSysMon = jsm;

                memoryTimer.start();
                updateMemory();

                final MemoryStats memoryStats = jsm.physical();

                // Logs a typical error situation
                if (memoryStats.getFreeBytes() == memoryStats.getTotalBytes()) {
                    Logger.getLogger(MainView.class.getName()).log(Level.WARNING,
                            "Total memory == free memory, probably due to incorrect "
                            + "java runtime architecture");
                }
            }
        }

        ResourceMap resourceMap = getResourceMap();

        // Sets window icon
        this.getFrame().setIconImage(resourceMap.getImageIcon("Application.icon").getImage());

        // Prepares busy icons
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);


        // Change listener to keep track of whether the selected tab
        // contains textual data
        tabbedPane.addChangeListener(new ChangeListener() {

            public void stateChanged(ChangeEvent e) {
                if (tabbedPane.getSelectedComponent() == inputTab
                        || tabbedPane.getSelectedComponent() == outputTab
                        || tabbedPane.getSelectedComponent() == consoleTab) {
                    setTextualTabSelected(true);
                } else {
                    setTextualTabSelected(false);
                }
            }
        });

        // Forces update on interface
        setInputFile(null);
    }

    /**
     * Shows about for of jNormaliz
     */
    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = JNormalizApplication.getApplication().getMainFrame();
            aboutBox = new AboutBoxDialog(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        aboutBox.setVisible(true);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        GridBagConstraints gridBagConstraints;

        mainPanel = new JPanel();
        tabbedPane = new JTabbedPane();
        inputTab = new JPanel();
        jScrollPane2 = new JScrollPane();
        inputDataTextArea = new JTextArea();
        inputFilePathButton = new JButton();
        outputTab = new JPanel();
        resultsScrollPane = new JScrollPane();
        resultTextArea = new JTextArea();
        syncWarningLabel = new JLabel();
        consoleTab = new JPanel();
        jScrollPane1 = new JScrollPane();
        consoleTextArea = new JTextArea();
        jButton1 = new JButton();
        jPanel2 = new JPanel();
        testArithOverflowCheckBox = new JCheckBox();
        outputOptionsPanel = new JPanel();
        outputIntermediateRadioButton = new JRadioButton();
        outputAllRadioButton = new JRadioButton();
        outputDefaultRadioButton = new JRadioButton();
        writeTriangulationFileCheckBox = new JCheckBox();
        writeStanleyDecompositionFileCheckBox = new JCheckBox();
        inputFontSizeSpinner = new JSpinner();
        jLabel4 = new JLabel();
        label1 = new Label();
        controlParalellizationCheckBox = new JCheckBox();
        jLabel1 = new JLabel();
        inputNumberParallelThreads = new JSpinner();
        jLabel5 = new JLabel();
        NmzIntegrateOptionsPanel = new JPanel();
        NmzIntegrateEhrhartRadioButton = new JRadioButton();
        NmzIntegrateLeadingRadioButton = new JRadioButton();
        NmzIntegrateDefaultRadioButton = new JRadioButton();
        NmzIntegrateLebesqueRadioButton = new JRadioButton();
        label2 = new Label();
        statusPanel = new JPanel();
        elapsedTimeLabel = new JLabel();
        physicalMemoryTitleLabel = new JLabel();
        memoryProgressBar = new JProgressBar();
        statusAnimationLabel = new JLabel();
        jToolBar1 = new JToolBar();
        runButton = new JButton();
        stopButton = new JButton();
        jSeparator2 = new Separator();
        jPanel4 = new JPanel();
        jLabel2 = new JLabel();
        computationTypeComboBox = new JComboBox();
        precisionComboBox = new JComboBox();
        jLabel3 = new JLabel();
        algorithmComboBox = new JComboBox();
        jLabel6 = new JLabel();
        menuBar = new JMenuBar();
        fileMenu = new JMenu();
        openMenuItem = new JMenuItem();
        newMenuItem = new JMenuItem();
        closeMenuItem = new JMenuItem();
        jMenuItem3 = new JMenuItem();
        jSeparator3 = new JPopupMenu.Separator();
        saveMenuItem = new JMenuItem();
        saveAsMenuItem = new JMenuItem();
        jSeparator4 = new JPopupMenu.Separator();
        printMenuItem = new JMenuItem();
        jSeparator1 = new JPopupMenu.Separator();
        exitMenuItem = new JMenuItem();
        jMenu2 = new JMenu();
        undoMenuItem = new JMenuItem();
        jSeparator5 = new JPopupMenu.Separator();
        copyMenuItem = new JMenuItem();
        cutMenuItem = new JMenuItem();
        pasteMenuItem = new JMenuItem();
        jMenu3 = new JMenu();
        jMenuItem1 = new JMenuItem();
        jMenuItem2 = new JMenuItem();
        jMenu1 = new JMenu();
        jMenuItem6 = new JMenuItem();
        jMenuItem7 = new JMenuItem();
        openWebMenuItem = new JMenuItem();
        jMenuItem9 = new JMenuItem();
        jMenuItem8 = new JMenuItem();
        outputOptionsButtonGroup = new ButtonGroup();
        NmzIntegrateOptionsButtonGroup = new ButtonGroup();

        mainPanel.setName("mainPanel"); // NOI18N
        mainPanel.setLayout(new GridBagLayout());

        tabbedPane.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
        tabbedPane.setName("tabbedPane"); // NOI18N

        inputTab.setName("inputTab"); // NOI18N

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        inputDataTextArea.setColumns(20);
        inputDataTextArea.setEditable(!isRunning());
        inputDataTextArea.setFont(new Font("Courier New 12 Simplu 12 Simplu", 0, 12));
        inputDataTextArea.setRows(5);
        inputDataTextArea.setName("inputDataTextArea"); // NOI18N
        jScrollPane2.setViewportView(inputDataTextArea);

        ActionMap actionMap = Application.getInstance(JNormalizApplication.class).getContext().getActionMap(MainView.class, this);
        inputFilePathButton.setAction(actionMap.get("openDirectoryAction")); // NOI18N
        inputFilePathButton.setBorderPainted(false);
        inputFilePathButton.setContentAreaFilled(false);
        inputFilePathButton.setHideActionText(true);
        inputFilePathButton.setHorizontalAlignment(SwingConstants.LEFT);
        inputFilePathButton.setName("inputFilePathButton"); // NOI18N

        GroupLayout inputTabLayout = new GroupLayout(inputTab);
        inputTab.setLayout(inputTabLayout);
        inputTabLayout.setHorizontalGroup(
            inputTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, inputTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(inputTabLayout.createParallelGroup(Alignment.TRAILING)
                    .addComponent(inputFilePathButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 662, Short.MAX_VALUE)
                    .addComponent(jScrollPane2, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 662, Short.MAX_VALUE))
                .addContainerGap())
        );
        inputTabLayout.setVerticalGroup(
            inputTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, inputTabLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane2, GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(inputFilePathButton)
                .addContainerGap())
        );

        tabbedPane.addTab("Input data", inputTab);

        outputTab.setName("outputTab"); // NOI18N

        resultsScrollPane.setName("resultsScrollPane"); // NOI18N

        resultTextArea.setColumns(20);
        resultTextArea.setEditable(false);
        resultTextArea.setFont(new Font("Courier New 12 Simplu 12 Simplu", 0, 12));
        resultTextArea.setRows(5);
        resultTextArea.setName("resultTextArea"); // NOI18N
        resultsScrollPane.setViewportView(resultTextArea);

        syncWarningLabel.setForeground(Color.red);
        syncWarningLabel.setText("SYNC WARNING");
        syncWarningLabel.setBorder(BorderFactory.createEmptyBorder(1, 1, 1, 1));
        syncWarningLabel.setName("syncWarningLabel"); // NOI18N

        GroupLayout outputTabLayout = new GroupLayout(outputTab);
        outputTab.setLayout(outputTabLayout);
        outputTabLayout.setHorizontalGroup(
            outputTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, outputTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(outputTabLayout.createParallelGroup(Alignment.TRAILING)
                    .addComponent(syncWarningLabel, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 662, Short.MAX_VALUE)
                    .addComponent(resultsScrollPane, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 662, Short.MAX_VALUE))
                .addContainerGap())
        );
        outputTabLayout.setVerticalGroup(
            outputTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, outputTabLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(resultsScrollPane, GroupLayout.DEFAULT_SIZE, 374, Short.MAX_VALUE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(syncWarningLabel)
                .addContainerGap())
        );

        tabbedPane.addTab("Output", outputTab);

        consoleTab.setName("consoleTab"); // NOI18N

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        consoleTextArea.setColumns(20);
        consoleTextArea.setEditable(false);
        consoleTextArea.setFont(new Font("Courier New 12 Simplu 12 Simplu", 0, 12));
        consoleTextArea.setRows(5);
        consoleTextArea.setMaximumSize(new Dimension(2147483647, 100));
        consoleTextArea.setName("consoleTextArea"); // NOI18N
        jScrollPane1.setViewportView(consoleTextArea);

        jButton1.setAction(actionMap.get("clearConsole")); // NOI18N
        jButton1.setName("jButton1"); // NOI18N

        GroupLayout consoleTabLayout = new GroupLayout(consoleTab);
        consoleTab.setLayout(consoleTabLayout);
        consoleTabLayout.setHorizontalGroup(
            consoleTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, consoleTabLayout.createSequentialGroup()
                .addContainerGap()
                .addGroup(consoleTabLayout.createParallelGroup(Alignment.TRAILING)
                    .addComponent(jButton1, GroupLayout.PREFERRED_SIZE, 108, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 662, Short.MAX_VALUE))
                .addContainerGap())
        );
        consoleTabLayout.setVerticalGroup(
            consoleTabLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, consoleTabLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, GroupLayout.DEFAULT_SIZE, 367, Short.MAX_VALUE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(jButton1)
                .addContainerGap())
        );

        tabbedPane.addTab("Console", consoleTab);

        jPanel2.setMinimumSize(new Dimension(0, 120));
        jPanel2.setName("jPanel2"); // NOI18N
        jPanel2.setPreferredSize(new Dimension(0, 120));

        testArithOverflowCheckBox.setSelected(true);
        testArithOverflowCheckBox.setText("Run tests for arithmetic overflow");
        testArithOverflowCheckBox.setAlignmentX(0.5F);
        testArithOverflowCheckBox.setName("testArithOverflowCheckBox"); // NOI18N

        outputOptionsPanel.setBorder(BorderFactory.createTitledBorder("Output options"));
        outputOptionsPanel.setToolTipText("Chooses which output files will be produced by Normaliz"); // NOI18N
        outputOptionsPanel.setName("outputOptionsPanel"); // NOI18N

        outputOptionsButtonGroup.add(outputIntermediateRadioButton);
        outputIntermediateRadioButton.setText("Write .out, .gen, .inv, .typ, .cst");
        outputIntermediateRadioButton.setName("outputIntermediateRadioButton"); // NOI18N

        outputOptionsButtonGroup.add(outputAllRadioButton);
        outputAllRadioButton.setText("Write all output file types");
        outputAllRadioButton.setName("outputAllRadioButton"); // NOI18N

        outputOptionsButtonGroup.add(outputDefaultRadioButton);
        outputDefaultRadioButton.setSelected(true);
        outputDefaultRadioButton.setText("Write just .out");
        outputDefaultRadioButton.setName("outputDefaultRadioButton"); // NOI18N

        writeTriangulationFileCheckBox.setText("Write triangulation");
        writeTriangulationFileCheckBox.setName("writeTriangulationFileCheckBox"); // NOI18N

        writeStanleyDecompositionFileCheckBox.setText("Write Stanley decomposition");
        writeStanleyDecompositionFileCheckBox.setName("writeStanleyDecompositionFileCheckBox"); // NOI18N

        GroupLayout outputOptionsPanelLayout = new GroupLayout(outputOptionsPanel);
        outputOptionsPanel.setLayout(outputOptionsPanelLayout);
        outputOptionsPanelLayout.setHorizontalGroup(
            outputOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(outputOptionsPanelLayout.createSequentialGroup()
                .addGroup(outputOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
                    .addGroup(outputOptionsPanelLayout.createParallelGroup(Alignment.TRAILING, false)
                        .addComponent(outputDefaultRadioButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(outputAllRadioButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(outputIntermediateRadioButton, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addComponent(writeTriangulationFileCheckBox)
                    .addComponent(writeStanleyDecompositionFileCheckBox))
                .addContainerGap(78, Short.MAX_VALUE))
        );
        outputOptionsPanelLayout.setVerticalGroup(
            outputOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(outputOptionsPanelLayout.createSequentialGroup()
                .addComponent(outputDefaultRadioButton)
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addComponent(outputIntermediateRadioButton)
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addComponent(outputAllRadioButton)
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addComponent(writeTriangulationFileCheckBox)
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addComponent(writeStanleyDecompositionFileCheckBox)
                .addContainerGap(GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        inputFontSizeSpinner.setName("inputFontSizeSpinner"); // NOI18N
        inputFontSizeSpinner.setValue(12);
        inputFontSizeSpinner.addChangeListener(this);

        jLabel4.setText("Font size for textual data (input file, output file and console)");
        jLabel4.setName("jLabel4"); // NOI18N

        label1.setAlignment(Label.CENTER);
        label1.setFont(new Font("Dialog", 1, 12));
        label1.setName("Normaliz options"); // NOI18N
        label1.setText("Normaliz options");

        controlParalellizationCheckBox.setText("Control the number of parallel threads");
        controlParalellizationCheckBox.setAlignmentX(0.5F);
        controlParalellizationCheckBox.setName("controlParalellizationCheckBox"); // NOI18N

        jLabel1.setText(" Maximum number of parallel threads");
        jLabel1.setAlignmentX(0.5F);
        jLabel1.setName("jLabel1"); // NOI18N

        inputNumberParallelThreads.setName("inputNumberPararallelThreads"); // NOI18N
        inputNumberParallelThreads.setValue(1);

        jLabel5.setFont(new Font("Dialog", 1, 12));
        jLabel5.setHorizontalAlignment(SwingConstants.CENTER);
        jLabel5.setText("NmzIntegrate options");
        jLabel5.setHorizontalTextPosition(SwingConstants.CENTER);
        jLabel5.setName("jLabel5"); // NOI18N

        NmzIntegrateOptionsPanel.setBorder(BorderFactory.createTitledBorder("NmzIntegrate options"));
        NmzIntegrateOptionsPanel.setToolTipText("Chooses which NmzIntegrate option will be used by Normaliz"); // NOI18N
        NmzIntegrateOptionsPanel.setName("NmzIntegrateOptionsPanel"); // NOI18N

        NmzIntegrateOptionsButtonGroup.add(NmzIntegrateEhrhartRadioButton);
        NmzIntegrateEhrhartRadioButton.setText("Generalized Ehrhart series");
        NmzIntegrateEhrhartRadioButton.setName("GeneralizedEhrhartseriesRadioButton1"); // NOI18N

        NmzIntegrateOptionsButtonGroup.add(NmzIntegrateLeadingRadioButton);
        NmzIntegrateLeadingRadioButton.setText("Leading coefficient of quasipolynomial");
        NmzIntegrateLeadingRadioButton.setName("NmzIntegrateLeadingRadioButton"); // NOI18N

        NmzIntegrateOptionsButtonGroup.add(NmzIntegrateDefaultRadioButton);
        NmzIntegrateDefaultRadioButton.setSelected(true);
        NmzIntegrateDefaultRadioButton.setText("None");
        NmzIntegrateDefaultRadioButton.setName("NmzIntegrateDefaultRadioButton"); // NOI18N

        NmzIntegrateOptionsButtonGroup.add(NmzIntegrateLebesqueRadioButton);
        NmzIntegrateLebesqueRadioButton.setText("Lebesque integral");
        NmzIntegrateLebesqueRadioButton.setName("NmzIntegrateLebesqueRadioButton"); // NOI18N

        GroupLayout NmzIntegrateOptionsPanelLayout = new GroupLayout(NmzIntegrateOptionsPanel);
        NmzIntegrateOptionsPanel.setLayout(NmzIntegrateOptionsPanelLayout);
        NmzIntegrateOptionsPanelLayout.setHorizontalGroup(
            NmzIntegrateOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(NmzIntegrateOptionsPanelLayout.createSequentialGroup()
                .addGroup(NmzIntegrateOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
                    .addGroup(NmzIntegrateOptionsPanelLayout.createSequentialGroup()
                        .addComponent(NmzIntegrateEhrhartRadioButton, GroupLayout.DEFAULT_SIZE, 156, Short.MAX_VALUE)
                        .addGap(207, 207, 207))
                    .addComponent(NmzIntegrateLebesqueRadioButton)
                    .addComponent(NmzIntegrateLeadingRadioButton, GroupLayout.DEFAULT_SIZE, 363, Short.MAX_VALUE)
                    .addComponent(NmzIntegrateDefaultRadioButton, GroupLayout.PREFERRED_SIZE, 302, GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        NmzIntegrateOptionsPanelLayout.setVerticalGroup(
            NmzIntegrateOptionsPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(NmzIntegrateOptionsPanelLayout.createSequentialGroup()
                .addComponent(NmzIntegrateDefaultRadioButton)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(NmzIntegrateEhrhartRadioButton)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(NmzIntegrateLeadingRadioButton)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(NmzIntegrateLebesqueRadioButton)
                .addContainerGap(42, Short.MAX_VALUE))
        );

        label2.setAlignment(Label.CENTER);
        label2.setFont(new Font("Dialog", 1, 12));
        label2.setName("jNormaliz options"); // NOI18N
        label2.setText("jNormaliz options");

        GroupLayout jPanel2Layout = new GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel2Layout.createParallelGroup(Alignment.LEADING)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGroup(jPanel2Layout.createParallelGroup(Alignment.LEADING)
                            .addComponent(outputOptionsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(label1, GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
                            .addComponent(testArithOverflowCheckBox, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
                            .addComponent(controlParalellizationCheckBox, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE)
                            .addComponent(jLabel1, GroupLayout.DEFAULT_SIZE, 271, Short.MAX_VALUE))
                        .addPreferredGap(ComponentPlacement.RELATED))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addComponent(inputNumberParallelThreads, GroupLayout.PREFERRED_SIZE, 47, GroupLayout.PREFERRED_SIZE)
                        .addGap(228, 228, 228)))
                .addGroup(jPanel2Layout.createParallelGroup(Alignment.TRAILING)
                    .addComponent(NmzIntegrateOptionsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(inputFontSizeSpinner, Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 48, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel4, GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE)
                    .addComponent(label2, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE)
                    .addComponent(jLabel5, Alignment.LEADING, GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE))
                .addContainerGap())
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel2Layout.createSequentialGroup()
                .addGroup(jPanel2Layout.createParallelGroup(Alignment.LEADING, false)
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addGap(223, 223, 223)
                        .addComponent(testArithOverflowCheckBox, GroupLayout.PREFERRED_SIZE, 35, GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addComponent(controlParalellizationCheckBox, GroupLayout.PREFERRED_SIZE, 36, GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel2Layout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(jPanel2Layout.createParallelGroup(Alignment.LEADING, false)
                            .addComponent(jLabel5, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(label1, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 38, Short.MAX_VALUE))
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addGroup(jPanel2Layout.createParallelGroup(Alignment.TRAILING, false)
                            .addComponent(NmzIntegrateOptionsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(outputOptionsPanel, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(ComponentPlacement.RELATED)
                        .addComponent(label2, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
                .addGap(7, 7, 7)
                .addGroup(jPanel2Layout.createParallelGroup(Alignment.LEADING, false)
                    .addComponent(jLabel1, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, 33, Short.MAX_VALUE)
                    .addComponent(jLabel4, Alignment.TRAILING, GroupLayout.DEFAULT_SIZE, GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addGroup(jPanel2Layout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(inputNumberParallelThreads, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE)
                    .addComponent(inputFontSizeSpinner, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addContainerGap(53, Short.MAX_VALUE))
        );

        tabbedPane.addTab("Options", jPanel2);

        tabbedPane.setSelectedIndex(3);

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 1;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.ipadx = 147;
        gridBagConstraints.ipady = 86;
        gridBagConstraints.anchor = GridBagConstraints.NORTHEAST;
        gridBagConstraints.weightx = 1.0;
        gridBagConstraints.weighty = 1.0;
        gridBagConstraints.insets = new Insets(6, 0, 0, 0);
        mainPanel.add(tabbedPane, gridBagConstraints);

        statusPanel.setMinimumSize(new Dimension(0, 30));
        statusPanel.setName("statusPanel"); // NOI18N
        statusPanel.setPreferredSize(new Dimension(512, 30));

        elapsedTimeLabel.setText("Elapsed time: -");
        elapsedTimeLabel.setName("elapsedTimeLabel"); // NOI18N

        physicalMemoryTitleLabel.setHorizontalAlignment(SwingConstants.RIGHT);
        physicalMemoryTitleLabel.setText("Physical mem. (free/total):");
        physicalMemoryTitleLabel.setName("physicalMemoryTitleLabel"); // NOI18N

        memoryProgressBar.setBackground(new Color(255, 255, 255));
        memoryProgressBar.setName("memoryProgressBar"); // NOI18N
        memoryProgressBar.setStringPainted(true);

        statusAnimationLabel.setHorizontalAlignment(SwingConstants.CENTER);
        statusAnimationLabel.setHorizontalTextPosition(SwingConstants.CENTER);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        GroupLayout statusPanelLayout = new GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(Alignment.TRAILING, statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(elapsedTimeLabel, GroupLayout.DEFAULT_SIZE, 166, Short.MAX_VALUE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(physicalMemoryTitleLabel, GroupLayout.PREFERRED_SIZE, 222, GroupLayout.PREFERRED_SIZE)
                .addGap(84, 84, 84)
                .addComponent(memoryProgressBar, GroupLayout.PREFERRED_SIZE, 178, GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel, GroupLayout.PREFERRED_SIZE, 17, GroupLayout.PREFERRED_SIZE))
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addGroup(statusPanelLayout.createParallelGroup(Alignment.CENTER)
                    .addComponent(statusAnimationLabel, GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)
                    .addComponent(elapsedTimeLabel, GroupLayout.DEFAULT_SIZE, 30, Short.MAX_VALUE)
                    .addComponent(physicalMemoryTitleLabel, GroupLayout.PREFERRED_SIZE, 30, GroupLayout.PREFERRED_SIZE)
                    .addComponent(memoryProgressBar, GroupLayout.PREFERRED_SIZE, GroupLayout.DEFAULT_SIZE, GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 3;
        gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
        gridBagConstraints.ipadx = 224;
        gridBagConstraints.ipady = 2;
        gridBagConstraints.anchor = GridBagConstraints.SOUTHWEST;
        mainPanel.add(statusPanel, gridBagConstraints);

        jToolBar1.setFloatable(false);
        jToolBar1.setRollover(true);
        jToolBar1.setName("jToolBar1"); // NOI18N

        runButton.setAction(actionMap.get("runNormalize")); // NOI18N
        runButton.setFocusable(false);
        runButton.setHorizontalTextPosition(SwingConstants.CENTER);
        runButton.setName("runButton"); // NOI18N
        runButton.setVerticalTextPosition(SwingConstants.BOTTOM);
        jToolBar1.add(runButton);

        stopButton.setAction(actionMap.get("stopNormaliz")); // NOI18N
        stopButton.setFocusable(false);
        stopButton.setHorizontalTextPosition(SwingConstants.CENTER);
        stopButton.setName("stopButton"); // NOI18N
        stopButton.setVerticalTextPosition(SwingConstants.BOTTOM);
        jToolBar1.add(stopButton);

        jSeparator2.setName("jSeparator2"); // NOI18N
        jToolBar1.add(jSeparator2);

        jPanel4.setName("jPanel4"); // NOI18N
        jPanel4.setOpaque(false);

        jLabel2.setText("Computation mode");
        jLabel2.setName("jLabel2"); // NOI18N

        computationTypeComboBox.setMaximumRowCount(11);
        computationTypeComboBox.setModel(new DefaultComboBoxModel(new String[] { "default", "support hyperplanes", "triangulation", "volume", "volume degree 1 elements", "Hilbert basis volume", "Hilbert basis", "degree 1 elements", "Hilbert series", "Hilbert series degree 1 elements", "Hilbert basis series" }));
        computationTypeComboBox.setLightWeightPopupEnabled(false);
        computationTypeComboBox.setMaximumSize(new Dimension(179, 25));
        computationTypeComboBox.setMinimumSize(new Dimension(170, 18));
        computationTypeComboBox.setName("computationTypeComboBox"); // NOI18N
        computationTypeComboBox.setPreferredSize(new Dimension(170, 23));

        precisionComboBox.setModel(new DefaultComboBoxModel(new String[] { "64 bits precision (normaliz)", "Infinite precision (normaliz -B)" }));
        precisionComboBox.setMaximumSize(new Dimension(179, 25));
        precisionComboBox.setMinimumSize(new Dimension(170, 18));
        precisionComboBox.setName("precisionComboBox"); // NOI18N
        precisionComboBox.setPreferredSize(new Dimension(170, 23));

        jLabel3.setText("Precision");
        jLabel3.setName("jLabel3"); // NOI18N

        algorithmComboBox.setMaximumRowCount(3);
        algorithmComboBox.setModel(new DefaultComboBoxModel(new String[] { "primal", "dual", "approximation" }));
        algorithmComboBox.setMaximumSize(new Dimension(179, 25));
        algorithmComboBox.setMinimumSize(new Dimension(170, 18));
        algorithmComboBox.setName("algorithmComboBox"); // NOI18N
        algorithmComboBox.setPreferredSize(new Dimension(170, 23));

        jLabel6.setText("Algorithm");
        jLabel6.setName("jLabel6"); // NOI18N

        GroupLayout jPanel4Layout = new GroupLayout(jPanel4);
        jPanel4.setLayout(jPanel4Layout);
        jPanel4Layout.setHorizontalGroup(
            jPanel4Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel4Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel4Layout.createParallelGroup(Alignment.LEADING)
                    .addComponent(jLabel6, GroupLayout.PREFERRED_SIZE, 62, GroupLayout.PREFERRED_SIZE)
                    .addComponent(algorithmComboBox, GroupLayout.PREFERRED_SIZE, 179, GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(ComponentPlacement.UNRELATED)
                .addGroup(jPanel4Layout.createParallelGroup(Alignment.TRAILING)
                    .addGroup(jPanel4Layout.createSequentialGroup()
                        .addComponent(jLabel2)
                        .addGap(100, 100, 100))
                    .addComponent(computationTypeComboBox, Alignment.LEADING, GroupLayout.PREFERRED_SIZE, 179, GroupLayout.PREFERRED_SIZE))
                .addGap(1, 1, 1)
                .addGroup(jPanel4Layout.createParallelGroup(Alignment.LEADING)
                    .addComponent(precisionComboBox, GroupLayout.PREFERRED_SIZE, 179, GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel3))
                .addGap(37, 37, 37))
        );
        jPanel4Layout.setVerticalGroup(
            jPanel4Layout.createParallelGroup(Alignment.LEADING)
            .addGroup(jPanel4Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel4Layout.createParallelGroup(Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(jLabel6)
                    .addComponent(jLabel3))
                .addPreferredGap(ComponentPlacement.RELATED)
                .addGroup(jPanel4Layout.createParallelGroup(Alignment.LEADING)
                    .addGroup(jPanel4Layout.createParallelGroup(Alignment.BASELINE)
                        .addComponent(computationTypeComboBox, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE)
                        .addComponent(algorithmComboBox, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE))
                    .addComponent(precisionComboBox, GroupLayout.PREFERRED_SIZE, 25, GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );

        jToolBar1.add(jPanel4);

        gridBagConstraints = new GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = GridBagConstraints.BOTH;
        gridBagConstraints.anchor = GridBagConstraints.WEST;
        mainPanel.add(jToolBar1, gridBagConstraints);

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setMnemonic('F');
        fileMenu.setText("File");
        fileMenu.setName("fileMenu"); // NOI18N

        openMenuItem.setAction(actionMap.get("loadInputFileAction")); // NOI18N
        openMenuItem.setName("openMenuItem"); // NOI18N
        fileMenu.add(openMenuItem);

        newMenuItem.setAction(actionMap.get("newFileAction")); // NOI18N
        newMenuItem.setName("newMenuItem"); // NOI18N
        fileMenu.add(newMenuItem);

        closeMenuItem.setAction(actionMap.get("closeFileAction")); // NOI18N
        closeMenuItem.setName("closeMenuItem"); // NOI18N
        fileMenu.add(closeMenuItem);

        jMenuItem3.setAction(actionMap.get("openDirectoryAction")); // NOI18N
        jMenuItem3.setName("jMenuItem3"); // NOI18N
        fileMenu.add(jMenuItem3);

        jSeparator3.setName("jSeparator3"); // NOI18N
        fileMenu.add(jSeparator3);

        saveMenuItem.setAction(actionMap.get("saveFileAction")); // NOI18N
        saveMenuItem.setName("saveMenuItem"); // NOI18N
        fileMenu.add(saveMenuItem);

        saveAsMenuItem.setAction(actionMap.get("saveFileAsAction")); // NOI18N
        saveAsMenuItem.setName("saveAsMenuItem"); // NOI18N
        fileMenu.add(saveAsMenuItem);

        jSeparator4.setName("jSeparator4"); // NOI18N
        fileMenu.add(jSeparator4);

        printMenuItem.setAction(actionMap.get("printAction")); // NOI18N
        printMenuItem.setName("printMenuItem"); // NOI18N
        fileMenu.add(printMenuItem);

        jSeparator1.setName("jSeparator1"); // NOI18N
        fileMenu.add(jSeparator1);

        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        jMenu2.setMnemonic('E');
        jMenu2.setText("Edit");
        jMenu2.setName("jMenu2"); // NOI18N

        undoMenuItem.setAction(actionMap.get("undoAction")); // NOI18N
        undoMenuItem.setName("undoMenuItem"); // NOI18N
        jMenu2.add(undoMenuItem);

        jSeparator5.setName("jSeparator5"); // NOI18N
        jMenu2.add(jSeparator5);

        copyMenuItem.setAction(new DefaultEditorKit.CopyAction());
        copyMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.CTRL_MASK));
        copyMenuItem.setText("Copy");
        copyMenuItem.setName("copyMenuItem"); // NOI18N
        copyMenuItem.addActionListener(this);
        jMenu2.add(copyMenuItem);

        cutMenuItem.setAction(new DefaultEditorKit.CutAction());
        cutMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_X, InputEvent.CTRL_MASK));
        cutMenuItem.setText("Cut");
        cutMenuItem.setName("cutMenuItem"); // NOI18N
        jMenu2.add(cutMenuItem);

        pasteMenuItem.setAction(new DefaultEditorKit.PasteAction());
        pasteMenuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_MASK));
        pasteMenuItem.setText("Paste");
        pasteMenuItem.setName("pasteMenuItem"); // NOI18N
        jMenu2.add(pasteMenuItem);

        menuBar.add(jMenu2);

        jMenu3.setText("Normaliz");
        jMenu3.setName("jMenu3"); // NOI18N

        jMenuItem1.setAction(actionMap.get("runNormalize")); // NOI18N
        jMenuItem1.setName("jMenuItem1"); // NOI18N
        jMenu3.add(jMenuItem1);

        jMenuItem2.setAction(actionMap.get("stopNormaliz")); // NOI18N
        jMenuItem2.setName("jMenuItem2"); // NOI18N
        jMenu3.add(jMenuItem2);

        menuBar.add(jMenu3);

        jMenu1.setMnemonic('H');
        jMenu1.setText("Help");
        jMenu1.setName("jMenu1"); // NOI18N

        jMenuItem6.setAction(actionMap.get("helpJNormalizAction")); // NOI18N
        jMenuItem6.setName("jMenuItem6"); // NOI18N
        jMenu1.add(jMenuItem6);

        jMenuItem7.setAction(actionMap.get("helpNormaliz")); // NOI18N
        jMenuItem7.setName("jMenuItem7"); // NOI18N
        jMenu1.add(jMenuItem7);

        openWebMenuItem.setAction(actionMap.get("openWebAction")); // NOI18N
        openWebMenuItem.setName("openWebMenuItem"); // NOI18N
        jMenu1.add(openWebMenuItem);

        jMenuItem9.setAction(actionMap.get("helpAlgorith")); // NOI18N
        jMenuItem9.setName("jMenuItem9"); // NOI18N
        jMenu1.add(jMenuItem9);

        jMenuItem8.setAction(actionMap.get("showAboutBox")); // NOI18N
        jMenuItem8.setName("jMenuItem8"); // NOI18N
        jMenu1.add(jMenuItem8);

        menuBar.add(jMenu1);

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
        setToolBar(jToolBar1);
    }

    // Code for dispatching events from components to event handlers.

    public void actionPerformed(java.awt.event.ActionEvent evt) {
        if (evt.getSource() == copyMenuItem) {
            MainView.this.copyMenuItemActionPerformed(evt);
        }
    }

    public void stateChanged(javax.swing.event.ChangeEvent evt) {
        if (evt.getSource() == inputFontSizeSpinner) {
            MainView.this.inputFontSizeSpinnerStateChanged(evt);
        }
    }// </editor-fold>//GEN-END:initComponents

    private void inputFontSizeSpinnerStateChanged(ChangeEvent evt) {//GEN-FIRST:event_inputFontSizeSpinnerStateChanged
        Font currentFont = inputDataTextArea.getFont();
        Font newFont = new Font(currentFont.getName(), currentFont.getStyle(), (Integer) inputFontSizeSpinner.getValue());
        inputDataTextArea.setFont(newFont);
        resultTextArea.setFont(newFont);
        consoleTextArea.setFont(newFont);
    }//GEN-LAST:event_inputFontSizeSpinnerStateChanged

    private void copyMenuItemActionPerformed(ActionEvent evt) {//GEN-FIRST:event_copyMenuItemActionPerformed
        // handling code here:
    }//GEN-LAST:event_copyMenuItemActionPerformed

    /**
     * Runs Normaliz command-line in background. It saves the file if there are
     * unsaved changes.
     */
    @Action(enabledProperty = "runnable")
    public void runNormalize() {

        // Changes the application state
        setRunning(true);

        // save file if it is unsaved
        saveFileAction();

        // Marks that the current input file will be in sync with the produced
        // output file (if nothing is changed meantime)
        inputFileChangeSinceLastRun = false;
        outputFileWhenNormalizWasRun = outputFile;

        // Prepares configuration info for Normaliz run
        NormalizConfig config = new NormalizConfig();

        // Precision
        switch (precisionComboBox.getSelectedIndex()) {
            case 0:
                config.precision = NormalizConfig.Precision.PRECISION64;
                break;

            case 1:
                config.precision = NormalizConfig.Precision.PRECISIONBIG;
                break;

            default:
                throw new RuntimeException("Unknown precision value: "
                        + precisionComboBox.getSelectedIndex());
        }

        // Computation type
        switch (computationTypeComboBox.getSelectedIndex()) {
             case 0:
                config.computationType =
                        NormalizConfig.ComputationType.DEFAULT;
                break;
            case 1:
                config.computationType =
                        NormalizConfig.ComputationType.SUPPORT_HYPERPLANES;
                break;

            case 2:
                config.computationType =
                        NormalizConfig.ComputationType.TRIANGULATION;
                break;

            case 3:
                config.computationType =
                        NormalizConfig.ComputationType.VOLUME;
                break;
                
            case 4:
                config.computationType =
                        NormalizConfig.ComputationType.VOLUME_DEGREE_1_ELEMENTS;
                break;

            case 5:
                config.computationType =
                        NormalizConfig.ComputationType.HILBERT_BASIS_VOLUME;
                break;

            case 6:
                config.computationType =
                        NormalizConfig.ComputationType.HILBERT_BASIS;
                break;

            case 7:
                config.computationType =
                        NormalizConfig.ComputationType.DEGREE_1_ELEMENTS;
                break;

            case 8:
                config.computationType =
                        NormalizConfig.ComputationType.HILBERT_SERIES;
                break;
                
            case 9:
                config.computationType =
                        NormalizConfig.ComputationType.HILBERT_SERIES_DEGREE_1_ELEMENTS;
                break;

            case 10:
                config.computationType =
                        NormalizConfig.ComputationType.HILBERT_BASIS_SERIES;
                break;



            default:
                throw new RuntimeException("Unknown computation type");

        }
        
        // Algorithm
        switch (algorithmComboBox.getSelectedIndex()) {
            case 0:
                config.algorithm =
                        NormalizConfig.Algorithm.PRIMAL;
                break;

            case 1:
                config.algorithm =
                        NormalizConfig.Algorithm.DUAL;
                break;

            case 2:
                config.algorithm =
                        NormalizConfig.Algorithm.APPROXIMATION;
                break;



            default:
                throw new RuntimeException("Unknown algorithm");

        }

        // Output files options
        if (outputIntermediateRadioButton.isSelected()) {
            config.outputFiles = NormalizConfig.OutputFiles.SOME;

        } else if (outputAllRadioButton.isSelected()) {
            config.outputFiles = NormalizConfig.OutputFiles.ALL;

        } else {
            config.outputFiles = NormalizConfig.OutputFiles.ONLY_OUT;

        }
        
        // NmzIntegrate options
        if (NmzIntegrateEhrhartRadioButton.isSelected()) {
            config.nmzIntegrateOptions = NormalizConfig.NmzIntegrateOptions.EHRHART;

        } else if (NmzIntegrateLeadingRadioButton.isSelected()) {
            config.nmzIntegrateOptions = NormalizConfig.NmzIntegrateOptions.LEADING;

        } else if (NmzIntegrateLebesqueRadioButton.isSelected()) {
            config.nmzIntegrateOptions = NormalizConfig.NmzIntegrateOptions.LEBESQUE;

        } else {
            config.nmzIntegrateOptions = NormalizConfig.NmzIntegrateOptions.NONE;

        }

        // Memory option for Normaliz 2.1, 2.2
        //config.saveMemory = saveMemoryCheckBox.isSelected();

        // Overflow option
        config.testArithmeticOverflow = testArithOverflowCheckBox.isSelected();
        
        // Write triangulation option
        config.writeTriangulationFile = writeTriangulationFileCheckBox.isSelected();
        
        // Write Stanley decomposition option
        config.writeStanleyDecompositionFile = writeStanleyDecompositionFileCheckBox.isSelected();

        // Control paralellization option
        config.controlParalellization = controlParalellizationCheckBox.isSelected();

        //Number of parallel threads
        config.numberParallelThreads = (Integer) inputNumberParallelThreads.getValue();

        config.inFile = getInputFile();
        
        /** The output file is changes to NmzIntegrate .intOut file
         * in case NmzIntegrate will be run
         */
        
        if ( config.nmzIntegrateOptions != NormalizConfig.NmzIntegrateOptions.NONE ){
        outputFile = new File(FileUtils.makeOutFileNameNmzIntegrate(getInputFile().getAbsolutePath()));
        outputFileWhenNormalizWasRun = outputFile;
        } else {
        outputFile = new File(FileUtils.makeOutFileName(getInputFile().getAbsolutePath()));
        outputFileWhenNormalizWasRun = outputFile;   
        }

        normalizWorker = new NormalizWorker(config);

        // Initializes "elapsed time" timer
        elapsedTime.reset();
        elapsedTimeLabel.setText("Elapsed time: 0:00:00");
        timer.start();

        // Starts worker that executes Normaliz
        normalizWorker.execute();

        // Changes to console tab, so the user can track progress
        tabbedPane.setSelectedComponent(consoleTab);
    }

    /**
     * Clears the contents of the console
     */
    @Action
    public void clearConsole() {
        consoleTextArea.setText(null);
    }

    /**
     * Offers the user the possibility of opening another input file. If the
     * currently opened input file has unsaved changes, offers the possibility
     * of saving them or canceling the operation.
     */
    @Action
    public void loadInputFileAction() {

        if (!checkSaveBeforeClosing("Save it before loading another file?")) {
            return;
        }

        // Gets file name
        int result = fileChooser.showOpenDialog(this.getFrame());

        if (result == JFileChooser.CANCEL_OPTION) {
            return;
        }

        if (result == JFileChooser.APPROVE_OPTION) {
            final File file = fileChooser.getSelectedFile();

            if (!file.getName().endsWith(".in")) {
                JOptionPane.showMessageDialog(this.getFrame(),
                        "Only *.in files allowed as input files",
                        "Error",
                        JOptionPane.ERROR_MESSAGE);

                return;
            }

            boolean loaded = loadInputFile(file);

            if (loaded) {
                setInputFile(file);
                loadOutputFile(outputFile);
                tabbedPane.setSelectedComponent(inputTab);
            }
        }
    }

    /**
     * Effectively loads a new input file, forcing the update of the
     * interface accordingly
     * @param file the new input file to be loaded
     * @return true if operation was successful, false otherwise.
     */
    public boolean loadInputFile(File file) {
        try {
            inputDataTextArea.read(new FileReader(file), null);
            inputDataTextArea.getDocument().addUndoableEditListener(this);
            inputDataTextArea.getDocument().addDocumentListener(this);
        } catch (IOException ex) {
            // TODO Test this exception
            JOptionPane.showMessageDialog(this.getFrame(),
                    "Unable to load file " + file.getAbsolutePath() + ":\n" + ex.getMessage(),
                    "Error",
                    JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);

            return false;
        }

        setFileChanged(false);

        syncWarningLabel.setText("Warning: Normaliz has not been run yet. Output file may be out of sync with input file");

        return true;
    }

    /**
     * Loads the contents of the output file to the output file tab.
     * @param file output file to be loaded.
     * @return true if operation was successful, false otherwise.
     */
    public boolean loadOutputFile(File file) {
        try {
            if (file.exists()) {
                resultTextArea.read(new FileReader(file), null);
            }
        } catch (IOException ex) {
            // Test this exception
            JOptionPane.showMessageDialog(this.getFrame(),
                    "Unable to load output file " + file.getAbsolutePath() + ":\n" + ex.getMessage(),
                    "Error",
                    JOptionPane.WARNING_MESSAGE);
            Logger.getLogger(MainView.class.getName()).log(Level.WARNING, null, ex);

            return false;
        }

        setFileChanged(false);

        return true;
    }

    /**
     * Interrupts a currently running execution of Normaliz
     */
    @Action(enabledProperty = "running")
    public void stopNormaliz() {
        normalizWorker.stop();
        normalizWorker = null;

        stopTimer();

        JOptionPane.showMessageDialog(null,
                "Normaliz execution interrupted. Output results were NOT updated.",
                "Attention",
                JOptionPane.WARNING_MESSAGE);

        setRunning(false);

    }

    /**
     * Saves the currently opened input file.
     */
    @Action(enabledProperty = "fileChanged")
    public void saveFileAction() {
        try {
            inputDataTextArea.write(new FileWriter(getInputFile()));
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(null,
                    "Unable to save file\nReason: " + ex.getMessage(),
                    "Error",
                    JOptionPane.ERROR_MESSAGE);

            Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);
            return;
        }

        setFileChanged(false);
    }

    /**
     * Closes the currently opened input and output files, forcing the update of
     * the interface. It offers the possibility of saving the input file
     * if it has unsaved changes
     */
    @Action(enabledProperty = "fileLoaded")
    public void closeFileAction() {

        if (isRunning()) {
            int result = JOptionPane.showConfirmDialog(this.getFrame(),
                    "Closing the file will interrupt computation. Are you sure?",
                    "Warning",
                    JOptionPane.WARNING_MESSAGE);

            if (result == JOptionPane.OK_OPTION) {
                stopNormaliz();
            } else {
                return;
            }
        }

        if (!checkSaveBeforeClosing("Save it before closing?")) {
            return;
        }

        setInputFile(null);
    }

    /**
     * Offers the possibility of saving the currently opened input file with
     * another name.
     */
    @Action(enabledProperty = "fileLoaded")
    public void saveFileAsAction() {

        // Gets file name
        fileChooser.setSelectedFile(inputFile);

        int result = fileChooser.showSaveDialog(mainPanel);

        if (result == JFileChooser.APPROVE_OPTION) {

            File chosenFile = fileChooser.getSelectedFile();

            if (!chosenFile.getName().endsWith(".in")) {
                JOptionPane.showMessageDialog(this.getFrame(),
                        "Input files must have the .in extension", "Invalid file name",
                        JOptionPane.ERROR_MESSAGE);
                return;
            }

            if (chosenFile.exists()) {
                result = JOptionPane.showConfirmDialog(
                        this.getFrame(),
                        "File already exists. Overwrite it?",
                        "Attention",
                        JOptionPane.YES_NO_OPTION,
                        JOptionPane.WARNING_MESSAGE);

                if (result == JOptionPane.NO_OPTION) {
                    return;
                }
            }

            setInputFile(chosenFile);

            saveFileAction();
        }
    }

    /**
     * Method that opens a dialog box with the specified message, offering the
     * possibility of saving the input file and of canceling the operation
     * @param message the message to be displayed to the user
     * @return false if user opted to cancel the operation, true otherwise
     */
    public boolean checkSaveBeforeClosing(String message) {

        if (getInputFile() == null || !fileChanged) {
            return true;
        }

        int result = JOptionPane.showConfirmDialog(getFrame(),
                message,
                "Attention", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);

        switch (result) {
            case JOptionPane.YES_OPTION:
                saveFileAction();
                return true;

            case JOptionPane.NO_OPTION:
                return true;

            case JOptionPane.CANCEL_OPTION:
                return false;

            default:
                throw new RuntimeException("Internal Error");
        }
    }

    /**
     * Opens the dialog for creating a new input file
     */
    @Action
    public void newFileAction() {

        // Check if InFile has unsaved modifications
        if (!checkSaveBeforeClosing("Save it before creating new file?")) {
            return;
        }

        // Opens dialog to get the filename, the row/columns size and the mode
        newFileDialog.showDialog(fileChooser.getCurrentDirectory());
    }

    /**
     * Undoes the most recent change in input file.
     */
    @Action(enabledProperty = "undo")
    public void undoAction() {
        undoManager.undo();
        updateUndoState();
    }
    private boolean fileLoaded = false;

    /**
     * Checks if there is a loaded input file
     * @return true if there is an input file loaded, false otherwise
     */
    public boolean isFileLoaded() {
        return fileLoaded;
    }

    /**
     * Updates the situation regarding whether or not there is an input file
     * currently loaded, updating the interface accordingly.
     * @param b true if there is an input file loaded, false otherwise
     */
    public void setFileLoaded(boolean b) {
        boolean old = isFileLoaded();
        this.fileLoaded = b;
        firePropertyChange("fileLoaded", old, isFileLoaded());
        firePropertyChange("runnable", !isRunnable(), isRunnable());

        if (isFileLoaded() && tabbedPane.getComponentAt(0) != inputTab) {
            tabbedPane.insertTab(outputFile.getName(), null, outputTab, null, 0);
            tabbedPane.insertTab(getInputFile().getName(), null, inputTab, null, 0);
            tabbedPane.setSelectedComponent(inputTab);

        } else if (!isFileLoaded() && tabbedPane.getComponentAt(0) == inputTab) {
            tabbedPane.remove(inputTab);
            tabbedPane.remove(outputTab);
        }
    }

    /**
     * Opens the java print dialog to print the currently selected tab contents.
     */
    @Action(enabledProperty = "textualTabSelected")
    public void printAction() {
        MessageFormat footer = new MessageFormat("Page {0}");
        MessageFormat header;
        PrintRequestAttributeSet p = new HashPrintRequestAttributeSet();

        try {
            if (tabbedPane.getSelectedComponent() == inputTab) {
                header = new MessageFormat(getInputFile().getName());
                p.add(new JobName(getInputFile().getName() + " - jNormaliz", null));
                inputDataTextArea.print(header, footer, true, null, p, true);
            } else if (tabbedPane.getSelectedComponent() == outputTab) {
                header = new MessageFormat(outputFile.getName());
                p.add(new JobName(outputFile.getName() + " - jNormaliz", null));
                resultTextArea.print(header, footer, true, null, p, true);
            } else if (tabbedPane.getSelectedComponent() == consoleTab) {
                header = new MessageFormat("Console");
                p.add(new JobName("console text - jNormaliz", null));
                consoleTextArea.print(header, footer, true, null, p, true);
            }
        } catch (PrinterException ex) {
            JOptionPane.showMessageDialog(this.getFrame(),
                    "Unable to print: " + ex.getMessage(),
                    "Error",
                    JOptionPane.ERROR_MESSAGE);
            Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    private boolean textualTabSelected = false;

    /**
     * Indicates whether or not the currently selected tab has text to be printed.
     * @return true is current tab is input, output or console, false otherwise
     */
    public boolean isTextualTabSelected() {
        return textualTabSelected;
    }

    /**
     * Sets whether or not the currently selected tab has text to be printed.
     * @param b the new value of this property.
     */
    public void setTextualTabSelected(boolean b) {
        boolean old = isTextualTabSelected();
        this.textualTabSelected = b;
        firePropertyChange("textualTabSelected", old, isTextualTabSelected());
    }

    /**
     * Opens Normaliz PDF documentation
     */
    @Action
    public void helpNormaliz() {

        if (desktop != null) {
            File helpPdf = new File("doc", "Normaliz_2.12.pdf");
            if (!helpPdf.exists()) {
                JOptionPane.showMessageDialog(this.getFrame(),
                        "Help file not found", "Error", JOptionPane.ERROR_MESSAGE);

                return;
            }
            try {
                desktop.open(helpPdf);
            } catch (IOException ex) {
                Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    /**
     * Opens the dialog with help for the algorithms
     */
    @Action
    public void helpAlgorith() {
        normalizAlgorithms.setVisible(true);
    }
    private boolean running = false;

    /**
     * Returns whether or not there is a currently running computation.
     * @return the current state of this property.
     */
    public boolean isRunning() {
        return running;
    }

    /**
     * Sets whether or not there is a currently running computation.
     * @param b the new state of this property.
     */
    public void setRunning(boolean b) {
        boolean old = isRunning();
        this.running = b;
        firePropertyChange("running", old, isRunning());
        firePropertyChange("runnable", !isRunnable(), isRunnable());

        if (b) {
            busyIconTimer.start();
        } else {
            busyIconTimer.stop();
            statusAnimationLabel.setIcon(idleIcon);
        }
    }

    /**
     * Returns whether or not the option for running Normaliz is available.
     * This happens when there is a loaded input file and there is not a
     * currently running computation
     */
    public boolean isRunnable() {
        return !isRunning() && isFileLoaded();
    }
    private boolean undo = false;

    /**
     * Returns whether or not there are undoable operations.
     */
    public boolean isUndo() {
        return undo;
    }

    void setUndo(boolean b) {
        boolean old = isUndo();
        this.undo = b;
        firePropertyChange("undo", old, isUndo());
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private JRadioButton NmzIntegrateDefaultRadioButton;
    private JRadioButton NmzIntegrateEhrhartRadioButton;
    private JRadioButton NmzIntegrateLeadingRadioButton;
    private JRadioButton NmzIntegrateLebesqueRadioButton;
    private ButtonGroup NmzIntegrateOptionsButtonGroup;
    private JPanel NmzIntegrateOptionsPanel;
    private JComboBox algorithmComboBox;
    private JMenuItem closeMenuItem;
    private JComboBox computationTypeComboBox;
    private JPanel consoleTab;
    private JTextArea consoleTextArea;
    private JCheckBox controlParalellizationCheckBox;
    private JMenuItem copyMenuItem;
    private JMenuItem cutMenuItem;
    private JLabel elapsedTimeLabel;
    private JMenuItem exitMenuItem;
    private JMenu fileMenu;
    private JTextArea inputDataTextArea;
    private JButton inputFilePathButton;
    private JSpinner inputFontSizeSpinner;
    private JSpinner inputNumberParallelThreads;
    private JPanel inputTab;
    private JButton jButton1;
    private JLabel jLabel1;
    private JLabel jLabel2;
    private JLabel jLabel3;
    private JLabel jLabel4;
    private JLabel jLabel5;
    private JLabel jLabel6;
    private JMenu jMenu1;
    private JMenu jMenu2;
    private JMenu jMenu3;
    private JMenuItem jMenuItem1;
    private JMenuItem jMenuItem2;
    private JMenuItem jMenuItem3;
    private JMenuItem jMenuItem6;
    private JMenuItem jMenuItem7;
    private JMenuItem jMenuItem8;
    private JMenuItem jMenuItem9;
    private JPanel jPanel2;
    private JPanel jPanel4;
    private JScrollPane jScrollPane1;
    private JScrollPane jScrollPane2;
    private JPopupMenu.Separator jSeparator1;
    private Separator jSeparator2;
    private JPopupMenu.Separator jSeparator3;
    private JPopupMenu.Separator jSeparator4;
    private JPopupMenu.Separator jSeparator5;
    private JToolBar jToolBar1;
    private Label label1;
    private Label label2;
    private JPanel mainPanel;
    private JProgressBar memoryProgressBar;
    private JMenuBar menuBar;
    private JMenuItem newMenuItem;
    private JMenuItem openMenuItem;
    private JMenuItem openWebMenuItem;
    private JRadioButton outputAllRadioButton;
    private JRadioButton outputDefaultRadioButton;
    private JRadioButton outputIntermediateRadioButton;
    private ButtonGroup outputOptionsButtonGroup;
    private JPanel outputOptionsPanel;
    private JPanel outputTab;
    private JMenuItem pasteMenuItem;
    private JLabel physicalMemoryTitleLabel;
    private JComboBox precisionComboBox;
    private JMenuItem printMenuItem;
    private JTextArea resultTextArea;
    private JScrollPane resultsScrollPane;
    private JButton runButton;
    private JMenuItem saveAsMenuItem;
    private JMenuItem saveMenuItem;
    private JLabel statusAnimationLabel;
    private JPanel statusPanel;
    private JButton stopButton;
    private JLabel syncWarningLabel;
    private JTabbedPane tabbedPane;
    private JCheckBox testArithOverflowCheckBox;
    private JMenuItem undoMenuItem;
    private JCheckBox writeStanleyDecompositionFileCheckBox;
    private JCheckBox writeTriangulationFileCheckBox;
    // End of variables declaration//GEN-END:variables
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;

    private void setFileChanged(boolean b) {
        boolean old = getFileChanged();
        this.fileChanged = b;
        firePropertyChange("fileChanged", old, getFileChanged());
        updateFrameTitle();

        if (b) {
            inputFileChangeSinceLastRun = true;
            syncWarningLabel.setText("Warning: input file changed since last Normaliz run");
        }
    }

    private boolean getFileChanged() {
        return fileChanged;
    }

    @Action
    public void openWebAction() {
        if (desktop != null) {
            try {
                desktop.browse(new URI("http://www.mathematik.uni-osnabrueck.de/normaliz/"));
            } catch (Exception ex) {
                Logger.getLogger(MainView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

    /**
     * Confirms whether or not the user really wants to exit. This confirmation
     * is asked only when there is an
     * unsaved input file or running computations. jNormaliz offers the
     * possibility of saving
     * the input file and/or keep the computation running.
     * @param event
     * @return returns false if the user decides not to exit, true otherwise
     */
    public boolean canExit(EventObject event) {
        if (!checkSaveBeforeClosing("Save it before exiting?")) {
            return false;
        }

        if (isRunning()) {
            int result = JOptionPane.showOptionDialog(this.getFrame(),
                    "Do you want to interrupt current running task?",
                    "Attention",
                    JOptionPane.YES_NO_CANCEL_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null, null, null);

            switch (result) {
                case JOptionPane.YES_OPTION:
                    normalizWorker.stop();
                    return true;

                case JOptionPane.NO_OPTION:
                    return true;

                default:
                    return false;
            }
        }

        return true;
    }

    public void willExit(EventObject event) {
        // Does nothing
    }

    /**
     * Registers a new undoable edit
     * @param e
     */
    public void undoableEditHappened(UndoableEditEvent e) {
        undoManager.undoableEditHappened(e);
        updateUndoState();
    }

    /**
     * Take note that file was changed
     * @param e
     */
    public void insertUpdate(DocumentEvent e) {
        if (!fileChanged) {
            setFileChanged(true);
        }
    }

   /**
     * Take note that file was changed
     * @param e
     */
   public void removeUpdate(DocumentEvent e) {
        if (!fileChanged) {
            setFileChanged(true);
        }
    }

    public void changedUpdate(DocumentEvent e) {
        // Does nothing
    }

    @Action
    public void helpJNormalizAction() {
        if (desktop != null) {
            File helpPdf = new File("doc", "jNormaliz_1.6.pdf");
            if (!helpPdf.exists()) {
                JOptionPane.showMessageDialog(this.getFrame(),
                        "Help file not found:\n" + helpPdf.getAbsolutePath(), "Error", JOptionPane.ERROR_MESSAGE);

                return;
            }
            try {
                desktop.open(helpPdf);
            } catch (IOException ex) {
                Logger.getLogger(MainView.class.getName()).log(Level.WARNING, null, ex);
            }
        }
    }

    @Action(enabledProperty = "fileLoaded")
    public void openDirectoryAction() {
        if (desktop != null) {
            try {
                desktop.open(inputFile.getParentFile());
            } catch (IOException ex) {
                Logger.getLogger(MainView.class.getName()).log(Level.WARNING, null, ex);
            }
        }

    }
}
