nz.ac.waikato.cms.supernova.gui.Supernova.java Source code

Java tutorial

Introduction

Here is the source code for nz.ac.waikato.cms.supernova.gui.Supernova.java

Source

/*
 *   This program is free software: you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation, either version 3 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *   You should have received a copy of the GNU General Public License
 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

/**
 * Supernova.java
 * Copyright (C) 2017 University of Waikato, Hamilton, NZ
 */

package nz.ac.waikato.cms.supernova.gui;

import com.github.fracpete.jclipboardhelper.ClipboardHelper;
import com.googlecode.jfilechooserbookmarks.core.Utils;
import com.googlecode.jfilechooserbookmarks.gui.BasePanel;
import com.googlecode.jfilechooserbookmarks.gui.BaseScrollPane;
import nz.ac.waikato.cms.core.BrowserHelper;
import nz.ac.waikato.cms.gui.core.BaseFrame;
import nz.ac.waikato.cms.gui.core.DirectoryChooserPanel;
import nz.ac.waikato.cms.gui.core.ExtensionFileFilter;
import nz.ac.waikato.cms.gui.core.FileChooserPanel;
import nz.ac.waikato.cms.gui.core.GUIHelper;
import nz.ac.waikato.cms.supernova.core.Registry;
import nz.ac.waikato.cms.supernova.io.AbstractOutputGenerator;
import nz.ac.waikato.cms.supernova.io.AbstractOutputGeneratorWithDimensions;
import nz.ac.waikato.cms.supernova.io.PNG;
import nz.ac.waikato.cms.supernova.triangle.AbstractTriangleCenterCalculation;
import nz.ac.waikato.cms.supernova.triangle.Incenter;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.commons.csv.CSVRecord;

import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileReader;
import java.io.Reader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 * Interface for I Am Supernova.
 *
 * @author FracPete (fracpete at waikato dot ac dot nz)
 * @version $Revision$
 */
public class Supernova extends BasePanel {

    /** for logging. */
    protected Logger m_Logger;

    /** tabbed pane. */
    protected JTabbedPane m_TabbedPane;

    /** the panel for generating a single graph. */
    protected BasePanel m_PanelSingle;

    /** the preview of the generated image. */
    protected ImagePanel m_PanelSinglePreview;

    /** the table for the statistics. */
    protected StatisticsTable m_SingleStatistics;

    /** the background. */
    protected ColorButton m_SingleBackground;

    /** the opacity. */
    protected JSpinner m_SingleOpacity;

    /** the margin. */
    protected JSpinner m_SingleMargin;

    /** the width. */
    protected JSpinner m_SingleWidth;

    /** the height. */
    protected JSpinner m_SingleHeight;

    /** the generator. */
    protected JComboBox m_SingleGenerator;

    /** the center. */
    protected JComboBox m_SingleCenter;

    /** the output. */
    protected FileChooserPanel m_SingleOutput;

    /** generates the preview. */
    protected JButton m_SinglePreview;

    /** copies the preview. */
    protected JButton m_SingleCopy;

    /** generates the output. */
    protected JButton m_SingleGenerate;

    /** the panel for batch processing. */
    protected BasePanel m_PanelBatch;

    /** the log for batch processing. */
    protected JTextArea m_BatchLog;

    /** the table for the statistics. */
    protected ColorTable m_BatchColors;

    /** the background. */
    protected ColorButton m_BatchBackground;

    /** the opacity. */
    protected JSpinner m_BatchOpacity;

    /** the margin. */
    protected JSpinner m_BatchMargin;

    /** the width. */
    protected JSpinner m_BatchWidth;

    /** the height. */
    protected JSpinner m_BatchHeight;

    /** the generator. */
    protected JComboBox m_BatchGenerator;

    /** the center. */
    protected JComboBox m_BatchCenter;

    /** the CSV file. */
    protected FileChooserPanel m_BatchCSV;

    /** the output. */
    protected DirectoryChooserPanel m_BatchOutput;

    /** generates the output. */
    protected JButton m_BatchGenerate;

    /** the collected labels to be adjusted. */
    protected List<JLabel> m_ParamLabels;

    /**
     * Initializes the widgets.
     */
    @Override
    protected void initialize() {
        super.initialize();

        m_ParamLabels = new ArrayList<>();
        m_Logger = Logger.getLogger(getClass().getName());
    }

    /**
     * Initializes the widgets.
     */
    @Override
    protected void initGUI() {
        super.initGUI();

        setLayout(new BorderLayout());

        m_ParamLabels.clear();
        m_PanelSingle = createSinglePanel();

        m_ParamLabels.clear();
        m_PanelBatch = createBatchPanel();

        m_TabbedPane = new JTabbedPane();
        m_TabbedPane.addTab("Graph", m_PanelSingle);
        m_TabbedPane.addTab("Batch", m_PanelBatch);
        add(m_TabbedPane);
    }

    /**
     * Creates a panel with a parameter.
     *
     * @param labelText   the label text
     * @param comp   the component
     * @return      the panel
     */
    protected JPanel createParameter(String labelText, JComponent comp) {
        JPanel param;
        JLabel label;

        label = new JLabel(labelText);
        label.setLabelFor(comp);
        param = new JPanel(new FlowLayout(FlowLayout.LEFT));
        param.add(label);
        param.add(comp);
        m_ParamLabels.add(label);

        return param;
    }

    /**
     * Adjusts the collected labels.
     */
    protected void adjustLabels() {
        int max;

        max = 0;
        for (JLabel label : m_ParamLabels)
            max = (int) Math.max(label.getPreferredSize().getWidth(), max);

        for (JLabel label : m_ParamLabels)
            label.setPreferredSize(new Dimension(max, (int) label.getPreferredSize().getHeight()));
    }

    /**
     * Creates the panel for generating a single graph.
     *
     * @return      the panel
     */
    protected BasePanel createSinglePanel() {
        BasePanel result;
        JPanel params;
        JPanel left1;
        JPanel left2;
        JPanel panel;
        JPanel panel2;

        result = new BasePanel(new BorderLayout());
        panel = new JPanel(new BorderLayout());
        result.add(panel, BorderLayout.CENTER);
        m_PanelSinglePreview = new ImagePanel();
        panel.add(new BaseScrollPane(m_PanelSinglePreview), BorderLayout.CENTER);
        panel2 = new JPanel(new FlowLayout(FlowLayout.RIGHT));
        panel.add(panel2, BorderLayout.SOUTH);
        m_SingleCopy = new JButton(GUIHelper.getIcon("copy.gif"));
        m_SingleCopy.setEnabled(false);
        m_SingleCopy.addActionListener((ActionEvent e) -> copySinglePreview());
        panel2.add(m_SingleCopy);

        left1 = new JPanel(new BorderLayout());
        result.add(left1, BorderLayout.WEST);

        // params with height 2
        params = new JPanel(new GridLayout(0, 1));
        left1.add(params, BorderLayout.NORTH);

        m_SingleStatistics = new StatisticsTable();
        left1.add(new BaseScrollPane(m_SingleStatistics), BorderLayout.NORTH);

        // params with height 1
        panel = new JPanel(new BorderLayout());
        left1.add(panel, BorderLayout.CENTER);
        left2 = new JPanel(new BorderLayout());
        panel.add(left2, BorderLayout.NORTH);
        params = new JPanel(new GridLayout(0, 1));
        left2.add(params, BorderLayout.NORTH);

        // background
        m_SingleBackground = new ColorButton(Color.BLACK);
        params.add(createParameter("Background", m_SingleBackground));

        // opacity
        m_SingleOpacity = new JSpinner();
        m_SingleOpacity.setValue(10);
        ((SpinnerNumberModel) m_SingleOpacity.getModel()).setMinimum(0);
        ((SpinnerNumberModel) m_SingleOpacity.getModel()).setMaximum(100);
        ((SpinnerNumberModel) m_SingleOpacity.getModel()).setStepSize(10);
        ((JSpinner.DefaultEditor) m_SingleOpacity.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Opacity %", m_SingleOpacity));

        // margin
        m_SingleMargin = new JSpinner();
        m_SingleMargin.setValue(20);
        ((SpinnerNumberModel) m_SingleMargin.getModel()).setMinimum(0);
        ((SpinnerNumberModel) m_SingleMargin.getModel()).setMaximum(100);
        ((SpinnerNumberModel) m_SingleMargin.getModel()).setStepSize(10);
        ((JSpinner.DefaultEditor) m_SingleMargin.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Margin %", m_SingleMargin));

        // width
        m_SingleWidth = new JSpinner();
        m_SingleWidth.setValue(400);
        ((SpinnerNumberModel) m_SingleWidth.getModel()).setMinimum(1);
        ((SpinnerNumberModel) m_SingleWidth.getModel()).setStepSize(100);
        ((JSpinner.DefaultEditor) m_SingleWidth.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Width", m_SingleWidth));

        // height
        m_SingleHeight = new JSpinner();
        m_SingleHeight.setValue(400);
        ((SpinnerNumberModel) m_SingleHeight.getModel()).setMinimum(1);
        ((SpinnerNumberModel) m_SingleHeight.getModel()).setStepSize(100);
        ((JSpinner.DefaultEditor) m_SingleHeight.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Height", m_SingleHeight));

        // generator
        m_SingleGenerator = new JComboBox<>(Registry.toStringArray(Registry.getGenerators(), true));
        m_SingleGenerator.addActionListener((ActionEvent e) -> {
            updateSingleOutput();
        });
        params.add(createParameter("Generator", m_SingleGenerator));

        // center
        m_SingleCenter = new JComboBox<>(Registry.toStringArray(Registry.getCenters(), true));
        params.add(createParameter("Center", m_SingleCenter));

        // output
        m_SingleOutput = new FileChooserPanel();
        m_SingleOutput.setUseSaveDialog(true);
        m_SingleOutput.setPreferredSize(new Dimension(170, (int) m_SingleOutput.getPreferredSize().getHeight()));
        params.add(createParameter("Output", m_SingleOutput));

        // preview/generate
        panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        m_SinglePreview = new JButton("Preview");
        m_SinglePreview.addActionListener((ActionEvent e) -> generateSinglePreview());
        m_SingleGenerate = new JButton("Generate");
        m_SingleGenerate.addActionListener((ActionEvent e) -> generateSingleOutput());
        panel.add(m_SinglePreview);
        panel.add(m_SingleGenerate);
        params.add(panel);

        adjustLabels();

        return result;
    }

    /**
     * Updates the filechooser for the single output.
     */
    protected void updateSingleOutput() {
        ExtensionFileFilter filter;
        String cls;
        AbstractOutputGenerator generator;

        if (m_SingleGenerator.getSelectedIndex() == -1)
            return;
        try {
            cls = AbstractOutputGenerator.class.getPackage().getName() + "." + m_SingleGenerator.getSelectedItem();
            generator = (AbstractOutputGenerator) Class.forName(cls).newInstance();
            filter = new ExtensionFileFilter(generator.getExtension().toUpperCase() + " files",
                    generator.getExtension());
            m_SingleOutput.removeChoosableFileFilters();
            m_SingleOutput.addChoosableFileFilter(filter);
            m_SingleOutput.setFileFilter(filter);
        } catch (Exception ex) {
            m_SingleOutput.removeChoosableFileFilters();
        }
    }

    /**
     * Copies the current preview to the clipboard.
     */
    protected void copySinglePreview() {
        if (m_PanelSinglePreview.getImage() != null)
            ClipboardHelper.copyToClipboard(m_PanelSinglePreview.getImage());
    }

    /**
     * Creates the panel for batch generation.
     *
     * @return      the panel
     */
    protected BasePanel createBatchPanel() {
        BasePanel result;
        JPanel params;
        JPanel left1;
        JPanel left2;
        JPanel panel;

        result = new BasePanel(new BorderLayout());
        m_BatchLog = new JTextArea(20, 40);
        m_BatchLog.setFont(Font.decode("Monospaced-PLAIN-12"));
        result.add(new BaseScrollPane(m_BatchLog), BorderLayout.CENTER);

        left1 = new JPanel(new BorderLayout());
        result.add(left1, BorderLayout.WEST);

        // params with height 2
        params = new JPanel(new GridLayout(0, 1));
        left1.add(params, BorderLayout.NORTH);

        m_BatchColors = new ColorTable();
        left1.add(new BaseScrollPane(m_BatchColors), BorderLayout.NORTH);

        // params with height 1
        panel = new JPanel(new BorderLayout());
        left1.add(panel, BorderLayout.CENTER);
        left2 = new JPanel(new BorderLayout());
        panel.add(left2, BorderLayout.NORTH);
        params = new JPanel(new GridLayout(0, 1));
        left2.add(params, BorderLayout.NORTH);

        // background
        m_BatchBackground = new ColorButton(Color.BLACK);
        params.add(createParameter("Background", m_BatchBackground));

        // opacity
        m_BatchOpacity = new JSpinner();
        m_BatchOpacity.setValue(10);
        ((SpinnerNumberModel) m_BatchOpacity.getModel()).setMinimum(0);
        ((SpinnerNumberModel) m_BatchOpacity.getModel()).setMaximum(100);
        ((SpinnerNumberModel) m_BatchOpacity.getModel()).setStepSize(10);
        ((JSpinner.DefaultEditor) m_BatchOpacity.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Opacity %", m_BatchOpacity));

        // margin
        m_BatchMargin = new JSpinner();
        m_BatchMargin.setValue(20);
        ((SpinnerNumberModel) m_BatchMargin.getModel()).setMinimum(0);
        ((SpinnerNumberModel) m_BatchMargin.getModel()).setMaximum(100);
        ((SpinnerNumberModel) m_BatchMargin.getModel()).setStepSize(10);
        ((JSpinner.DefaultEditor) m_BatchMargin.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Margin %", m_BatchMargin));

        // width
        m_BatchWidth = new JSpinner();
        m_BatchWidth.setValue(400);
        ((SpinnerNumberModel) m_BatchWidth.getModel()).setMinimum(1);
        ((SpinnerNumberModel) m_BatchWidth.getModel()).setStepSize(100);
        ((JSpinner.DefaultEditor) m_BatchWidth.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Width", m_BatchWidth));

        // height
        m_BatchHeight = new JSpinner();
        m_BatchHeight.setValue(400);
        ((SpinnerNumberModel) m_BatchHeight.getModel()).setMinimum(1);
        ((SpinnerNumberModel) m_BatchHeight.getModel()).setStepSize(100);
        ((JSpinner.DefaultEditor) m_BatchHeight.getEditor()).getTextField().setColumns(5);
        params.add(createParameter("Height", m_BatchHeight));

        // generator
        m_BatchGenerator = new JComboBox<>(Registry.toStringArray(Registry.getGenerators(), true));
        params.add(createParameter("Generator", m_BatchGenerator));

        // center
        m_BatchCenter = new JComboBox<>(Registry.toStringArray(Registry.getCenters(), true));
        params.add(createParameter("Center", m_BatchCenter));

        // csv
        m_BatchCSV = new FileChooserPanel();
        m_BatchCSV.addChoosableFileFilter(new ExtensionFileFilter("CSV files", "csv"));
        m_BatchCSV.setPreferredSize(new Dimension(170, (int) m_BatchCSV.getPreferredSize().getHeight()));
        params.add(createParameter("CSV", m_BatchCSV));

        // output
        m_BatchOutput = new DirectoryChooserPanel();
        m_BatchOutput.setPreferredSize(new Dimension(170, (int) m_BatchOutput.getPreferredSize().getHeight()));
        params.add(createParameter("Output", m_BatchOutput));

        // generate
        panel = new JPanel(new FlowLayout(FlowLayout.LEFT));
        m_BatchGenerate = new JButton("Generate");
        m_BatchGenerate.addActionListener((ActionEvent e) -> {
            SwingWorker worker = new SwingWorker() {
                @Override
                protected Object doInBackground() throws Exception {
                    generateBatchOutput();
                    return null;
                }
            };
            worker.execute();
        });
        panel.add(m_BatchGenerate);
        params.add(panel);

        adjustLabels();

        return result;
    }

    /**
     * Finishes the initialization.
     */
    @Override
    protected void finishInit() {
        super.finishInit();
        updateSingleOutput();
    }

    /**
     * Creates the menu bar.
     *
     * @return      the menu bar
     */
    public JMenuBar createMenuBar() {
        JMenuBar result;
        JMenu menu;
        JMenuItem menuitem;

        result = new JMenuBar();

        menu = new JMenu("Program");
        result.add(menu);

        menuitem = new JMenuItem("Close", GUIHelper.getIcon("stop.gif"));
        menuitem.addActionListener((ActionEvent e) -> closeParent());
        menu.add(menuitem);

        menu = new JMenu("Help");
        result.add(menu);

        menuitem = new JMenuItem("Homepage", GUIHelper.getIcon("homepage.png"));
        menuitem.addActionListener(
                (ActionEvent e) -> BrowserHelper.openURL("https://github.com/fracpete/i-am-supernova"));
        menu.add(menuitem);

        return result;
    }

    /**
     * Updates the generator with the values from the "single" tab.
     *
     * @param generator   the generator to update
     */
    protected void configureSingle(AbstractOutputGenerator generator) {
        String cls;
        AbstractOutputGeneratorWithDimensions pixel;

        generator.setColors(m_SingleStatistics.getColors());
        generator.setBackground(m_SingleBackground.getColor());
        generator.setOpacity(((Number) m_SingleOpacity.getValue()).doubleValue() / 100.0);
        generator.setMargin(((Number) m_SingleMargin.getValue()).doubleValue() / 100.0);
        if (generator instanceof AbstractOutputGeneratorWithDimensions) {
            pixel = (AbstractOutputGeneratorWithDimensions) generator;
            pixel.setWidth(((Number) m_SingleWidth.getValue()).intValue());
            pixel.setHeight(((Number) m_SingleHeight.getValue()).intValue());
        }
        try {
            cls = AbstractTriangleCenterCalculation.class.getPackage().getName() + "."
                    + m_SingleCenter.getSelectedItem();
            generator.setCenter((AbstractTriangleCenterCalculation) Class.forName(cls).newInstance());
        } catch (Exception e) {
            generator.setCenter(new Incenter());
        }
    }

    /**
     * Updates the generator with the values from the "batch" tab.
     *
     * @param generator   the generator to update
     */
    protected void configureBatch(AbstractOutputGenerator generator) {
        String cls;
        AbstractOutputGeneratorWithDimensions pixel;

        generator.setColors(m_BatchColors.getColors());
        generator.setBackground(m_BatchBackground.getColor());
        generator.setOpacity(((Number) m_BatchOpacity.getValue()).doubleValue() / 100.0);
        generator.setMargin(((Number) m_BatchMargin.getValue()).doubleValue() / 100.0);
        if (generator instanceof AbstractOutputGeneratorWithDimensions) {
            pixel = (AbstractOutputGeneratorWithDimensions) generator;
            pixel.setWidth(((Number) m_BatchWidth.getValue()).intValue());
            pixel.setHeight(((Number) m_BatchHeight.getValue()).intValue());
        }
        try {
            cls = AbstractTriangleCenterCalculation.class.getPackage().getName() + "."
                    + m_BatchCenter.getSelectedItem();
            generator.setCenter((AbstractTriangleCenterCalculation) Class.forName(cls).newInstance());
        } catch (Exception e) {
            generator.setCenter(new Incenter());
        }
    }

    /**
     * Updates the preview of the "single" tab.
     */
    protected void generateSinglePreview() {
        PNG generator;
        BufferedImage img;
        StringBuilder errors;

        errors = new StringBuilder();
        generator = new PNG();
        configureSingle(generator);
        img = generator.generatePlot(m_SingleStatistics.getStatistics(), errors);
        if (errors.length() == 0)
            m_PanelSinglePreview.setImage(img);
        m_SingleCopy.setEnabled(m_PanelSinglePreview.getImage() != null);
    }

    /**
     * Generates the output of the "single" tab.
     */
    protected void generateSingleOutput() {
        String cls;
        AbstractOutputGenerator generator;
        String msg;

        SwingUtilities.invokeLater(() -> m_SingleGenerate.setEnabled(false));

        try {
            cls = AbstractOutputGenerator.class.getPackage().getName() + "." + m_SingleGenerator.getSelectedItem();
            generator = (AbstractOutputGenerator) Class.forName(cls).newInstance();
        } catch (Exception e) {
            m_Logger.log(Level.SEVERE, "Failed to instantiate output generator - falling back on PNG", e);
            generator = new PNG();
        }
        configureSingle(generator);
        m_Logger.info("Generating: " + m_SingleOutput.getCurrent());
        m_Logger.info("Using: " + m_SingleStatistics.getStatistics());
        msg = generator.generate(m_SingleStatistics.getStatistics(), m_SingleOutput.getCurrent());
        if (msg != null) {
            m_Logger.severe("Failed to generate output:\n" + msg);
            GUIHelper.showErrorMessage(this, "Failed to generate output:\n" + msg);
        }

        SwingUtilities.invokeLater(() -> m_SingleGenerate.setEnabled(true));
    }

    /**
     * Logs an exception during batch processing.
     *
     * @param msg      the message
     * @param t       the exception
     */
    protected void batchLog(String msg, Throwable t) {
        m_Logger.log(Level.SEVERE, msg, t);
        m_BatchLog.append(msg + "\n" + Utils.throwableToString(t) + "\n");
    }

    /**
     * Logs a message/error during batch processing.
     *
     * @param msg      the message
     * @param error   true if error
     */
    protected void batchLog(String msg, boolean error) {
        if (error) {
            m_BatchLog.append(msg + "\n");
            m_Logger.severe(msg);
        } else {
            m_BatchLog.append(msg + "\n");
            m_Logger.info(msg);
        }
    }

    /**
     * Generates the output of the "batch" tab.
     */
    protected void generateBatchOutput() {
        String cls;
        AbstractOutputGenerator generator;
        int colID;
        int colMeasure;
        int colScore;
        int colPercentile;
        Reader reader;
        CSVParser csvparser;
        String oldID;
        Map<String, List<Double>> test;
        String id;
        File outfile;
        String msg;
        String measure;
        double score;
        double percentile;
        String error;

        m_BatchLog.setText("");
        m_BatchGenerate.setEnabled(false);

        try {
            cls = AbstractOutputGenerator.class.getPackage().getName() + "." + m_SingleGenerator.getSelectedItem();
            generator = (AbstractOutputGenerator) Class.forName(cls).newInstance();
        } catch (Exception e) {
            batchLog("Failed to instantiate output generator - falling back on PNG", e);
            generator = new PNG();
        }

        try {
            colID = 0;
            colMeasure = 1;
            colScore = 2;
            colPercentile = 3;
            reader = new FileReader(m_BatchCSV.getCurrent());
            csvparser = new CSVParser(reader, CSVFormat.EXCEL.withHeader());
            oldID = "";
            test = new HashMap<>();
            for (CSVRecord rec : csvparser) {
                if (rec.size() < 4)
                    continue;
                id = rec.get(colID);
                if (!id.equals(oldID)) {
                    if (!test.isEmpty()) {
                        outfile = new File(m_BatchOutput.getCurrent() + File.separator + oldID + "."
                                + generator.getExtension());
                        batchLog("Generating: " + outfile, false);
                        batchLog("Using: " + test, false);
                        msg = generator.generate(test, outfile);
                        if (msg != null) {
                            error = "Failed to generate output for ID: " + oldID;
                            batchLog(error, true);
                        }
                    }
                    test.clear();
                    oldID = id;
                }
                measure = rec.get(colMeasure);
                score = Double.parseDouble(rec.get(colScore));
                percentile = Double.parseDouble(rec.get(colPercentile));
                test.put(measure, new ArrayList<>(Arrays.asList(new Double[] { score, percentile })));
            }
            if (!test.isEmpty()) {
                outfile = new File(
                        m_BatchOutput.getCurrent() + File.separator + oldID + "." + generator.getExtension());
                batchLog("Generating: " + outfile, false);
                batchLog("Using: " + test, false);
                msg = generator.generate(test, outfile);
                if (msg != null) {
                    error = "Failed to generate output for ID: " + oldID;
                    batchLog(error, true);
                }
            }
        } catch (Exception e) {
            batchLog("Failed to generate output!", e);
        }

        m_BatchGenerate.setEnabled(true);
    }

    /**
     * Starts the GUI.
     *
     * @param args   ignored
     */
    public static void main(String[] args) {
        BaseFrame frame = new BaseFrame("I Am Supernova");
        frame.setDefaultCloseOperation(BaseFrame.EXIT_ON_CLOSE);
        Supernova panel = new Supernova();
        frame.setJMenuBar(panel.createMenuBar());
        frame.getContentPane().setLayout(new BorderLayout());
        frame.getContentPane().add(panel);
        frame.setSize(1024, 768);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}