org.fhaes.fhsamplesize.view.FHSampleSize.java Source code

Java tutorial

Introduction

Here is the source code for org.fhaes.fhsamplesize.view.FHSampleSize.java

Source

/**************************************************************************************************
 * Fire History Analysis and Exploration System (FHAES), Copyright (C) 2015
 * 
 * Contributors: Joshua Brogan and Peter Brewer
 * 
 *       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/>.
 * 
 *************************************************************************************************/
package org.fhaes.fhsamplesize.view;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.io.File;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;

import javax.swing.DefaultComboBoxModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JSplitPane;
import javax.swing.JTabbedPane;
import javax.swing.JTextField;
import javax.swing.JToolBar;
import javax.swing.JViewport;
import javax.swing.ScrollPaneConstants;
import javax.swing.Scrollable;
import javax.swing.SpinnerNumberModel;
import javax.swing.SwingWorker;
import javax.swing.border.TitledBorder;

import net.miginfocom.swing.MigLayout;

import org.codehaus.plexus.util.FileUtils;
import org.fhaes.components.JToolBarButton;
import org.fhaes.enums.EventTypeToProcess;
import org.fhaes.enums.FireFilterType;
import org.fhaes.enums.MiddleMetric;
import org.fhaes.enums.ResamplingType;
import org.fhaes.fhfilereader.FHX2FileReader;
import org.fhaes.fhsamplesize.controller.SSIZController;
import org.fhaes.fhsamplesize.model.AnalysisResultsModel;
import org.fhaes.fhsamplesize.model.SSIZAnalysisModel;
import org.fhaes.filefilter.CSVFileFilter;
import org.fhaes.filefilter.FHXFileFilter;
import org.fhaes.filefilter.PDFFilter;
import org.fhaes.filefilter.TABFilter;
import org.fhaes.preferences.App;
import org.fhaes.preferences.FHAESPreferences.PrefKey;
import org.fhaes.preferences.wrappers.CheckBoxWrapper;
import org.fhaes.preferences.wrappers.EventTypeWrapper;
import org.fhaes.preferences.wrappers.FireFilterTypeWrapper;
import org.fhaes.preferences.wrappers.ResamplingTypeWrapper;
import org.fhaes.preferences.wrappers.SpinnerWrapper;
import org.fhaes.segmentation.SegmentModel;
import org.fhaes.segmentation.SegmentationPanel;
import org.fhaes.util.Builder;
import org.fhaes.util.FHAESAction;
import org.fhaes.util.JTableSpreadsheetByRowAdapter;
import org.jfree.chart.editor.ChartEditor;
import org.jfree.chart.editor.ChartEditorManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * FHSampleSize Class.
 * 
 * This is the GUI class for running the FHSampleSize analysis. This is a complete rewrite of the original SSIZ application, extended to
 * perform additional analyses described by Don Falk in his PhD thesis.
 * 
 * @author Joshua Brogan and Peter Brewer
 */
public class FHSampleSize extends JFrame implements ActionListener {

    private static final long serialVersionUID = 1L;
    private static final Logger log = LoggerFactory.getLogger(FHSampleSize.class);

    private static final int MAX_DRAW_HEIGHT = 1080;
    private static final int MAX_DRAW_WIDTH = 1920;

    protected JTableSpreadsheetByRowAdapter adapter;

    private JScrollPane scrollPaneAsymptote;
    private JScrollPane scrollPaneSimulations;

    private JCheckBox chkCommonYears;
    private JCheckBox chkExcludeSeriesWithNoEvents;
    private JSpinner spnSeed;
    private JSpinner spnSimulations;
    private JSpinner spnThresholdValueGT;
    private JSplitPane splitPaneResults;
    private JPanel panelChart;
    private JTextField txtInputFile;
    @SuppressWarnings("rawtypes")
    private JComboBox cboEventType;
    @SuppressWarnings("rawtypes")
    private JComboBox cboResampling;
    @SuppressWarnings("rawtypes")
    private JComboBox cboThresholdType;
    @SuppressWarnings("rawtypes")
    private JComboBox cboChartMetric;
    @SuppressWarnings("rawtypes")
    private JComboBox cboSegment;

    private JProgressBar progressBar;
    private JPanel panelProgressBar;
    private DrawSSIZAnalysisTask task;

    private JButton btnCancelAnalysis;
    private Boolean taskWasCancelled;

    private SSIZCurveChart curveChart;
    private SSIZResultsTable simulationsTable;
    private AsymptoteTable asymptoteTable;
    private SegmentationPanel segmentationPanel;
    private int segmentsDone = 0;

    private Boolean mouseListenersActive;

    private FHAESAction actionRun;
    private FHAESAction actionBrowse;
    private FHAESAction actionSaveTable;
    private FHAESAction actionExportPDF;
    private FHAESAction actionExportPNG;
    private FHAESAction actionClose;

    private FHX2FileReader reader;
    private Boolean fileDialogWasUsed;
    private JSpinner spnThresholdValueLT;
    private JCheckBox chkEnableLessThan;
    private JLabel lblLessThan;
    private JLabel lblAnd;

    /**
     * Launch as stand-alone application.
     */
    public static void main(String[] args) {

        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {

                try {
                    FHSampleSize window = new FHSampleSize(null);
                    window.setVisible(true);
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    /**
     * Standard constructor for the window.
     * 
     * @param parent
     */
    public FHSampleSize(Window parent) {

        initActions();
        initGUI();
        initMenu();
        setLocationRelativeTo(parent);
    }

    /**
     * Set up the Menu bar using actions wherever possible.
     */
    private void initMenu() {

        JMenuBar menuBar = new JMenuBar();
        setJMenuBar(menuBar);

        JMenu mnFile = new JMenu("File");
        menuBar.add(mnFile);

        JMenuItem mntmOpen = new JMenuItem(this.actionBrowse);
        mntmOpen.setText("Open...");
        mnFile.add(mntmOpen);

        JMenu mnSave = new JMenu("Save...");
        mnFile.add(mnSave);

        JMenuItem mntmSaveTable = new JMenuItem(this.actionSaveTable);
        mnSave.add(mntmSaveTable);

        JMenuItem mntmSaveChartPDF = new JMenuItem(this.actionExportPDF);
        mnSave.add(mntmSaveChartPDF);

        JMenuItem mntmSaveChartPNG = new JMenuItem(this.actionExportPNG);
        mnSave.add(mntmSaveChartPNG);

        mnFile.addSeparator();

        JMenuItem mntmExit = new JMenuItem(this.actionClose);
        mnFile.add(mntmExit);
    }

    /**
     * Initialize shared actions.
     */
    private void initActions() {

        final FHSampleSize glue = this;

        actionRun = new FHAESAction("Run Analysis", "run.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                try {
                    // Run the analysis task normally if the file dialog was used to load a file
                    if (fileDialogWasUsed && reader != null)
                        runSSIZAnalysisTask();

                    // Otherwise get file manually from the path in the input box and attempt analysis from there
                    else {
                        String filePath = txtInputFile.getText();
                        File theFHX2File = new File(filePath);
                        reader = new FHX2FileReader(theFHX2File);
                        setGUIForFHFileReader();

                        if (reader != null)
                            runSSIZAnalysisTask();
                    }
                } catch (Exception ex) {
                    JOptionPane.showMessageDialog(glue,
                            "Could not open the selected file. Try opening directly in FHAES for a detailed error message.");
                    ex.printStackTrace();

                    reader = null;
                    actionRun.setEnabled(false);
                    actionSaveTable.setEnabled(false);
                    actionExportPDF.setEnabled(false);
                    actionExportPNG.setEnabled(false);
                }
            }
        };
        actionRun.setEnabled(false);

        actionBrowse = new FHAESAction("Browse", "fileopen.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                File theFHX2File = loadFromOpenFileDialog();
                openFile(theFHX2File);
            }
        };
        actionBrowse.setEnabled(true);

        actionSaveTable = new FHAESAction("Save table", "save.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                saveTableToTextFile();
            }
        };
        actionSaveTable.setEnabled(false);

        actionExportPDF = new FHAESAction("Export chart to PDF", "pdf.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                saveChartToPDF();
            }
        };
        actionExportPDF.setEnabled(false);

        actionExportPNG = new FHAESAction("Export chart to PNG", "formatpng.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                saveChartToPNG();
            }
        };
        actionExportPNG.setEnabled(false);

        actionClose = new FHAESAction("Close", "close.png") {

            private static final long serialVersionUID = 1L;

            @Override
            public void actionPerformed(ActionEvent event) {

                dispose();
            }
        };
    }

    /**
     * Open the specified file
     * 
     * @param theFHX2File
     */
    public void openFile(File theFHX2File) {

        try {
            if (theFHX2File != null) {
                reader = new FHX2FileReader(theFHX2File);
                setGUIForFHFileReader();

                segmentationPanel.chkSegmentation.setEnabled(true);
                fileDialogWasUsed = true;
            }
        } catch (Exception ex) {
            JOptionPane.showMessageDialog(this,
                    "Could not open the selected file. Try opening directly in FHAES for a detailed error message.");
            ex.printStackTrace();

            reader = null;
            actionRun.setEnabled(false);
            actionSaveTable.setEnabled(false);
            actionExportPDF.setEnabled(false);
            actionExportPNG.setEnabled(false);
        }
    }

    /**
     * Initialize GUI components.
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    private void initGUI() {

        App.init();

        // setBounds(100, 100, 972, 439);
        setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        setIconImage(Builder.getApplicationIcon());
        setTitle("Sample Size Analysis");
        getContentPane().setLayout(new MigLayout("", "[1136px,grow,fill]", "[30px][405px,grow]"));

        JToolBar toolBar = new JToolBar();
        toolBar.setFloatable(false);
        getContentPane().add(toolBar, "cell 0 0,growx,aligny top");

        JToolBarButton btnOpen = new JToolBarButton(actionBrowse);
        btnOpen.setIcon(Builder.getImageIcon("fileopen.png"));
        toolBar.add(btnOpen);

        JToolBarButton btnSave = new JToolBarButton(actionSaveTable);
        btnSave.setIcon(Builder.getImageIcon("save.png"));
        toolBar.add(btnSave);

        JToolBarButton btnExportPDF = new JToolBarButton(actionExportPDF);
        btnExportPDF.setIcon(Builder.getImageIcon("pdf.png"));
        toolBar.add(btnExportPDF);

        JToolBarButton btnExportPNG = new JToolBarButton(actionExportPNG);
        btnExportPNG.setIcon(Builder.getImageIcon("formatpng.png"));
        toolBar.add(btnExportPNG);

        toolBar.addSeparator();

        JToolBarButton btnRun = new JToolBarButton(actionRun);
        btnRun.setIcon(Builder.getImageIcon("run.png"));
        toolBar.add(btnRun);

        JPanel panelMain = new JPanel();
        getContentPane().add(panelMain, "cell 0 1,grow");
        panelMain.setLayout(new BorderLayout(0, 0));

        JSplitPane splitPaneMain = new JSplitPane();
        splitPaneMain.setOneTouchExpandable(true);
        panelMain.add(splitPaneMain);

        JPanel panelParameters = new JPanel();
        splitPaneMain.setLeftComponent(panelParameters);
        panelParameters.setLayout(new MigLayout("", "[grow,right]", "[][][][193.00,grow,fill][]"));

        JPanel panelInput = new JPanel();
        panelInput.setBorder(new TitledBorder(null, "Input", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelParameters.add(panelInput, "cell 0 0,grow");
        panelInput.setLayout(new MigLayout("", "[100px:100px:180px,right][grow,fill][]", "[]"));

        JLabel lblInputFile = new JLabel("Input file:");
        panelInput.add(lblInputFile, "cell 0 0");

        txtInputFile = new JTextField();
        panelInput.add(txtInputFile, "cell 1 0,growx");
        txtInputFile.setActionCommand("NewFileTyped");
        txtInputFile.addActionListener(this);
        txtInputFile.setColumns(10);

        JButton btnBrowse = new JButton("");
        panelInput.add(btnBrowse, "cell 2 0");
        btnBrowse.setAction(actionBrowse);
        btnBrowse.setText("");
        btnBrowse.setIcon(Builder.getImageIcon("fileopen16.png"));
        btnBrowse.setPreferredSize(new Dimension(25, 25));
        btnBrowse.setMaximumSize(new Dimension(25, 25));
        btnBrowse.putClientProperty("JButton.buttonType", "segmentedTextured");
        btnBrowse.putClientProperty("JButton.segmentPosition", "middle");

        JPanel panelAnalysisOptions = new JPanel();
        panelAnalysisOptions.setBorder(new TitledBorder(null, "Analysis and filtering options",
                TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelParameters.add(panelAnalysisOptions, "cell 0 1,grow");
        panelAnalysisOptions.setLayout(new MigLayout("", "[100px:100px:180px,right][grow][][]", "[][][][][]"));

        JLabel lblEventTypes = new JLabel("Event type:");
        panelAnalysisOptions.add(lblEventTypes, "cell 0 0");

        cboEventType = new JComboBox();
        panelAnalysisOptions.add(cboEventType, "cell 1 0 3 1");
        cboEventType.setModel(new DefaultComboBoxModel(EventTypeToProcess.values()));
        new EventTypeWrapper(cboEventType, PrefKey.EVENT_TYPE_TO_PROCESS, EventTypeToProcess.FIRE_EVENT);

        chkCommonYears = new JCheckBox("<html>Only analyze years all series have in common");
        chkCommonYears.setEnabled(false);
        new CheckBoxWrapper(chkCommonYears, PrefKey.SSIZ_CHK_COMMON_YEARS, false);
        panelAnalysisOptions.add(chkCommonYears, "cell 1 1 3 1");

        chkExcludeSeriesWithNoEvents = new JCheckBox("<html>Exclude series/segments with no events");
        chkExcludeSeriesWithNoEvents.setEnabled(false);
        new CheckBoxWrapper(chkExcludeSeriesWithNoEvents, PrefKey.SSIZ_CHK_EXCLUDE_SERIES_WITH_NO_EVENTS, false);
        panelAnalysisOptions.add(chkExcludeSeriesWithNoEvents, "cell 1 2 3 1");

        JLabel lblThresholdType = new JLabel("Threshold:");
        panelAnalysisOptions.add(lblThresholdType, "cell 0 3");

        cboThresholdType = new JComboBox();
        panelAnalysisOptions.add(cboThresholdType, "cell 1 3");
        cboThresholdType.setModel(new DefaultComboBoxModel(FireFilterType.values()));
        new FireFilterTypeWrapper(cboThresholdType, PrefKey.COMPOSITE_FILTER_TYPE_WITH_ALL_TREES,
                FireFilterType.NUMBER_OF_EVENTS);

        JLabel label = new JLabel(">=");
        panelAnalysisOptions.add(label, "flowx,cell 2 3");

        spnThresholdValueGT = new JSpinner();
        panelAnalysisOptions.add(spnThresholdValueGT, "cell 3 3");
        spnThresholdValueGT.setModel(new SpinnerNumberModel(1, 1, 999, 1));
        new SpinnerWrapper(spnThresholdValueGT, PrefKey.COMPOSITE_FILTER_VALUE, 1);

        chkEnableLessThan = new JCheckBox("");
        chkEnableLessThan.setActionCommand("LessThanThresholdStatus");
        chkEnableLessThan.addActionListener(this);
        panelAnalysisOptions.add(chkEnableLessThan, "flowx,cell 1 4,alignx right");

        lblLessThan = new JLabel("<=");
        lblLessThan.setEnabled(false);
        panelAnalysisOptions.add(lblLessThan, "cell 2 4");

        spnThresholdValueLT = new JSpinner();
        spnThresholdValueLT.setEnabled(false);
        spnThresholdValueLT.setModel(new SpinnerNumberModel(1, 1, 999, 1));
        panelAnalysisOptions.add(spnThresholdValueLT, "cell 3 4");

        lblAnd = new JLabel("and");
        panelAnalysisOptions.add(lblAnd, "cell 1 4");

        JPanel panelSimulations = new JPanel();
        panelSimulations.setBorder(
                new TitledBorder(null, "Simulations", TitledBorder.LEADING, TitledBorder.TOP, null, null));
        panelParameters.add(panelSimulations, "cell 0 2,grow");
        panelSimulations.setLayout(new MigLayout("", "[100px:100px:180px,right][fill]", "[][][]"));

        JLabel lblSimulations = new JLabel("Simulations:");
        panelSimulations.add(lblSimulations, "cell 0 0");

        spnSimulations = new JSpinner();
        panelSimulations.add(spnSimulations, "cell 1 0");
        spnSimulations.setModel(new SpinnerNumberModel(new Integer(1000), new Integer(1), null, new Integer(1)));
        new SpinnerWrapper(spnSimulations, PrefKey.SSIZ_SIMULATION_COUNT, 1000);

        JLabel lblSeedNumber = new JLabel("Seed number:");
        panelSimulations.add(lblSeedNumber, "cell 0 1");

        spnSeed = new JSpinner();
        panelSimulations.add(spnSeed, "cell 1 1");
        spnSeed.setModel(new SpinnerNumberModel(new Integer(30188), null, null, new Integer(1)));
        new SpinnerWrapper(spnSeed, PrefKey.SSIZ_SEED_NUMBER, 30188);

        JLabel lblResampling = new JLabel("Resampling:");
        panelSimulations.add(lblResampling, "cell 0 2");

        cboResampling = new JComboBox();
        panelSimulations.add(cboResampling, "cell 1 2");
        cboResampling
                .setModel(new DefaultComboBoxModel(new String[] { "With replacement", "Without replacement" }));
        new ResamplingTypeWrapper(cboResampling, PrefKey.SSIZ_RESAMPLING_TYPE, ResamplingType.WITH_REPLACEMENT);

        segmentationPanel = new SegmentationPanel();
        segmentationPanel.chkSegmentation.setText("Process subset or segments of dataset?");
        segmentationPanel.chkSegmentation.setEnabled(false);
        panelParameters.add(segmentationPanel, "cell 0 3,growx");

        JPanel panel_3 = new JPanel();
        panelParameters.add(panel_3, "cell 0 4,grow");
        panel_3.setLayout(new MigLayout("", "[left][grow][right]", "[]"));

        JButton btnReset = new JButton("Reset");
        btnReset.setActionCommand("Reset");
        btnReset.addActionListener(this);
        panel_3.add(btnReset, "cell 0 0,grow");

        JButton btnRunAnalysis = new JButton("Run Analysis");
        btnRunAnalysis.setAction(actionRun);
        panel_3.add(btnRunAnalysis, "cell 2 0,grow");

        JPanel panelResults = new JPanel();
        splitPaneMain.setRightComponent(panelResults);
        panelResults.setLayout(new BorderLayout(0, 0));

        splitPaneResults = new JSplitPane();
        splitPaneResults.setResizeWeight(0.5);
        splitPaneResults.setOneTouchExpandable(true);
        splitPaneResults.setDividerLocation(0.5d);
        panelResults.add(splitPaneResults, BorderLayout.CENTER);
        splitPaneResults.setOrientation(JSplitPane.VERTICAL_SPLIT);

        JPanel panelResultsTop = new JPanel();
        splitPaneResults.setLeftComponent(panelResultsTop);
        panelResultsTop.setLayout(new BorderLayout(0, 0));

        JPanel panelChartOptions = new JPanel();
        panelChartOptions.setBackground(Color.WHITE);
        panelResultsTop.add(panelChartOptions, BorderLayout.SOUTH);
        panelChartOptions.setLayout(new MigLayout("", "[][][][][][grow][grow]", "[15px,center]"));

        JLabel lblNewLabel = new JLabel("Plot:");
        panelChartOptions.add(lblNewLabel, "cell 0 0,alignx trailing,aligny center");

        cboChartMetric = new JComboBox();
        cboChartMetric.setEnabled(false);
        cboChartMetric.setModel(new DefaultComboBoxModel(MiddleMetric.values()));
        panelChartOptions.add(cboChartMetric, "cell 1 0,growx");
        cboChartMetric.setBackground(Color.WHITE);

        JLabel lblOfSegment = new JLabel("of segment:");
        panelChartOptions.add(lblOfSegment, "cell 2 0,alignx trailing");

        cboSegment = new JComboBox();
        cboSegment.setBackground(Color.WHITE);
        cboSegment.setActionCommand("UpdateChart");
        cboSegment.addActionListener(this);

        panelChartOptions.add(cboSegment, "cell 3 0,growx");
        cboChartMetric.setActionCommand("UpdateChart");

        JLabel lblWithAsymptoteType = new JLabel("with asymptote type:");
        panelChartOptions.add(lblWithAsymptoteType, "cell 4 0,alignx trailing");

        JComboBox comboBox = new JComboBox();
        comboBox.setEnabled(false);
        comboBox.setModel(new DefaultComboBoxModel(new String[] { "none", "Weibull", "Michaelis-Menten",
                "Modified Michaelis-Menten", "Logistic", "Modified exponential" }));
        comboBox.setBackground(Color.WHITE);
        panelChartOptions.add(comboBox, "cell 5 0,growx");
        cboChartMetric.addActionListener(this);

        panelChart = new JPanel();
        panelChart.setMinimumSize(new Dimension(200, 200));
        panelResultsTop.add(panelChart, BorderLayout.CENTER);
        panelChart.setLayout(new BorderLayout(0, 0));
        panelChart.setBackground(Color.WHITE);

        JTabbedPane panelResultsBottom = new JTabbedPane(JTabbedPane.BOTTOM);
        splitPaneResults.setRightComponent(panelResultsBottom);

        simulationsTable = new SSIZResultsTable();
        simulationsTable.setEnabled(false);
        simulationsTable.addMouseListener(new TablePopClickListener());
        simulationsTable.setVisibleRowCount(10);

        adapter = new JTableSpreadsheetByRowAdapter(simulationsTable);

        scrollPaneSimulations = new JScrollPane();
        panelResultsBottom.addTab("Simulations", null, scrollPaneSimulations, null);
        scrollPaneSimulations.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPaneSimulations.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPaneSimulations.setViewportView(simulationsTable);

        JPanel panelAsymptote = new JPanel();

        asymptoteTable = new AsymptoteTable();
        asymptoteTable.setEnabled(false);
        // asymptoteTable.addMouseListener(new TablePopClickListener());
        asymptoteTable.setVisibleRowCount(10);

        scrollPaneAsymptote = new JScrollPane();

        scrollPaneAsymptote.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED);
        scrollPaneAsymptote.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
        scrollPaneAsymptote.setViewportView(asymptoteTable);
        panelAsymptote.setLayout(new BorderLayout());
        panelAsymptote.add(scrollPaneAsymptote, BorderLayout.CENTER);
        panelResultsBottom.addTab("Asymptote", null, panelAsymptote, null);

        // Disable asymptote tab until it is implemented
        panelResultsBottom.setEnabledAt(1, false);

        panelProgressBar = new JPanel();
        panelProgressBar.setLayout(new BorderLayout());

        btnCancelAnalysis = new JButton("Cancel");
        btnCancelAnalysis.setIcon(Builder.getImageIcon("delete.png"));
        btnCancelAnalysis.setVisible(false);
        btnCancelAnalysis.setActionCommand("CancelAnalysis");
        btnCancelAnalysis.addActionListener(this);

        progressBar = new JProgressBar();
        panelProgressBar.add(progressBar, BorderLayout.CENTER);
        panelProgressBar.add(btnCancelAnalysis, BorderLayout.EAST);
        progressBar.setStringPainted(true);

        fileDialogWasUsed = false;
        mouseListenersActive = false;

        this.setGUIForFHFileReader();
        this.setGUIForThresholdStatus();

        pack();
        this.setExtendedState(this.getExtendedState() | JFrame.MAXIMIZED_BOTH);
        setVisible(true);
    }

    /**
     * TODO
     */
    @Override
    public void actionPerformed(ActionEvent evt) {

        if (evt.getActionCommand().equals("Reset")) {
            // Reset the GUI for a new run
            int response = JOptionPane.showConfirmDialog(this, "Are you sure you want to start a new analysis?");
            if (response != JOptionPane.YES_OPTION)
                return;

            this.txtInputFile.setText(null);
            this.cboEventType.setSelectedIndex(0);
            this.spnSimulations.setValue(1000);
            this.spnSeed.setValue(30188);
            this.cboResampling.setSelectedIndex(0);
            this.cboThresholdType.setSelectedIndex(0);
            this.spnThresholdValueGT.setValue(1);
            segmentationPanel.chkSegmentation.setSelected(false);
            segmentationPanel.table.tableModel.clearSegments();
            this.panelChart.removeAll();
            this.panelChart.repaint();
            this.simulationsTable.removeAllRows();
            this.cboChartMetric.setEnabled(false);
            this.cboSegment.setEnabled(false);
        } else if (evt.getActionCommand().equals("NewFileTyped")) {
            // A new file name was typed
            try {
                if (filePathHasValidFile(txtInputFile.getText())) {
                    actionRun.setEnabled(true);
                    actionSaveTable.setEnabled(true);
                    segmentationPanel.chkSegmentation.setEnabled(true);
                } else {
                    actionRun.setEnabled(false);
                    actionSaveTable.setEnabled(false);
                    segmentationPanel.chkSegmentation.setEnabled(false);
                }
            } catch (Exception ex) {
                actionRun.setEnabled(false);
                actionSaveTable.setEnabled(false);
                segmentationPanel.chkSegmentation.setEnabled(false);
            }
        } else if (evt.getActionCommand().equals("UpdateChart")) {
            updateChart();
        } else if (evt.getActionCommand().equals("CancelAnalysis")) {
            // Cancel the analysis that is currently running
            taskWasCancelled = true;
            task.cancel(true);
        } else if (evt.getActionCommand().equals("LessThanThresholdStatus")) {
            setGUIForThresholdStatus();
        }
    }

    private void setGUIForThresholdStatus() {

        this.spnThresholdValueLT.setEnabled(this.chkEnableLessThan.isSelected());
        this.lblAnd.setEnabled(this.chkEnableLessThan.isSelected());
        this.lblLessThan.setEnabled(this.chkEnableLessThan.isSelected());

    }

    /**
     * Show open file dialog so the user may choose a file to edit.
     * 
     * @return the chosen file if okay was pressed, null if cancel was pressed
     */
    private File loadFromOpenFileDialog() {

        String lastVisitedFolder = App.prefs.getPref(PrefKey.PREF_LAST_READ_FOLDER, null);
        JFileChooser fc;

        if (lastVisitedFolder != null)
            fc = new JFileChooser(lastVisitedFolder);
        else
            fc = new JFileChooser();

        fc.setDialogTitle("Select a FHX2 file for sample size analysis");
        fc.setFileFilter(new FHXFileFilter());
        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.setMultiSelectionEnabled(true);

        int returnVal = fc.showOpenDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            App.prefs.setPref(PrefKey.PREF_LAST_READ_FOLDER, fc.getSelectedFile().getPath());
            return fc.getSelectedFile();
        }
        return null;
    }

    /**
     * Open a JFileChooser and return the file that the user specified for saving. Takes a parameter that specifies the type of file. Either
     * TAB or PNG.
     * 
     * @return
     */
    private File getFileFromSaveDialog(String fileTypeToSave) {

        String lastVisitedFolder = App.prefs.getPref(PrefKey.PREF_LAST_EXPORT_FOLDER, null);
        JFileChooser fc = new JFileChooser(lastVisitedFolder);
        File outputFile;

        if (fileTypeToSave == "TAB") {
            TABFilter filterTAB = new TABFilter();
            fc.addChoosableFileFilter(filterTAB);
            fc.setFileFilter(filterTAB);
            fc.setDialogTitle("Export table as text file...");

        } else if (fileTypeToSave == "PDF") {
            PDFFilter filterPDF = new PDFFilter();
            fc.addChoosableFileFilter(filterPDF);
            fc.setFileFilter(filterPDF);
            fc.setDialogTitle("Export chart as PDF...");
        }

        fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
        fc.setMultiSelectionEnabled(false);

        int returnVal = fc.showSaveDialog(this);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            outputFile = fc.getSelectedFile();

            if (FileUtils.getExtension(outputFile.getAbsolutePath()) == "") {
                log.debug("Output file extension not set by user");

                if (fc.getFileFilter().getDescription().equals(new CSVFileFilter().getDescription())) {
                    log.debug("Adding csv extension to output file name");
                    outputFile = new File(outputFile.getAbsolutePath() + ".csv");
                } else if (fc.getFileFilter().getDescription().equals(new PDFFilter().getDescription())) {
                    log.debug("Adding pdf extension to output file name");
                    outputFile = new File(outputFile.getAbsolutePath() + ".pdf");
                }
            } else {
                log.debug("Output file extension set my user to '"
                        + FileUtils.getExtension(outputFile.getAbsolutePath()) + "'");
            }

            App.prefs.setPref(PrefKey.PREF_LAST_EXPORT_FOLDER, outputFile.getAbsolutePath());
        } else {
            return null;
        }

        if (outputFile.exists()) {
            Object[] options = { "Overwrite", "No", "Cancel" };

            // notes about parameters: null (don't use custom icon), options (the titles of buttons), options[0] (default button title)
            int response = JOptionPane.showOptionDialog(App.mainFrame,
                    "The file '" + outputFile.getName() + "' already exists.  Are you sure you want to overwrite?",
                    "Confirm", JOptionPane.YES_NO_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE, null, options,
                    options[0]);

            if (response != JOptionPane.YES_OPTION)
                return null;
        }
        return outputFile;
    }

    /**
     * Checks whether or not the file at the specified path is valid.
     * 
     * @return true if the file is valid, false otherwise
     */
    private Boolean filePathHasValidFile(String inFilePath) {

        if (inFilePath == null)
            return false;

        if (!(inFilePath.substring(inFilePath.length() - 4, inFilePath.length()).equals(".fhx")))
            return false;

        File theFHX2File = new File(inFilePath);
        FHX2FileReader tempReader = new FHX2FileReader(theFHX2File);

        if (tempReader.getNumberOfSeries() < 6)
            return false;

        if (!tempReader.passesBasicSyntaxCheck())
            return false;

        return true;
    }

    /**
     * Set up analysis parameters in SSIZController according to the selected settings in the GUI.
     */
    private SSIZAnalysisModel createSSIZAnalysisModel() {

        if (reader == null)
            return null;

        SSIZAnalysisModel model = new SSIZAnalysisModel((Integer) spnSeed.getValue(), reader,
                (EventTypeToProcess) cboEventType.getSelectedItem());

        model.setNumSimulationsToRun((Integer) spnSimulations.getValue());
        model.setResamplingType((ResamplingType) cboResampling.getSelectedItem());
        model.setThresholdType((FireFilterType) cboThresholdType.getSelectedItem());
        model.setThresholdValueGT((Integer) spnThresholdValueGT.getValue());
        model.setThresholdValueLT((Integer) spnThresholdValueLT.getValue());
        model.enabledLowerThreshold(this.chkEnableLessThan.isSelected());

        // Do this before restricting to common years (otherwise common year restriction may have no effect)
        if (chkExcludeSeriesWithNoEvents.isSelected())
            SSIZController.restrictAnalysisToSeriesWithEvents(model);

        // Defaults to the original first and last years if no common years are found among the samples
        if (chkCommonYears.isSelected())
            SSIZController.restrictAnalysisToCommonYears(model);

        model.setSegmentArray(segmentationPanel.table.tableModel.getSegments());

        return model;
    }

    /**
     * Set up GUI restrictions depending on the current FHFileReader.
     */
    private void setGUIForFHFileReader() {

        if (reader == null) {
            log.debug("File is null so not setting GUI items accordingly");
            actionRun.setEnabled(false);
            return;
        }

        if (reader.getNumberOfSeries() < 6) {
            JOptionPane.showMessageDialog(this,
                    "Sample size analysis requires an input file with 5\nor more series. This file has just "
                            + reader.getNumberOfSeries() + " series.",
                    "Not enough series", JOptionPane.ERROR_MESSAGE);
            actionRun.setEnabled(false);
            return;
        }

        if (!reader.passesBasicSyntaxCheck()) {
            JOptionPane.showMessageDialog(this, "Error reading file", "FHX file error", JOptionPane.ERROR_MESSAGE);
            actionRun.setEnabled(false);
            return;
        }

        int firstyear = reader.getFirstYear();
        int lastyear = reader.getLastYear();

        if (reader.getFirstYear() != null && reader.getLastYear() != null) {
            log.debug("Setting year range to " + firstyear + " - " + lastyear);

            segmentationPanel.table.setEarliestYear(firstyear);
            segmentationPanel.table.setLatestYear(lastyear);
        }

        txtInputFile.setText(reader.getFile().getAbsolutePath());

        // Force segments to be specified if they've chosen segmentation
        if (segmentationPanel.chkSegmentation.isSelected()
                && (segmentationPanel.table.tableModel.getSegments() == null
                        || segmentationPanel.table.tableModel.getSegments().size() == 0)) {
            actionRun.setEnabled(false);
            actionSaveTable.setEnabled(false);
            return;
        }

        actionRun.setEnabled(true);
        actionSaveTable.setEnabled(true);
    }

    /**
     * Run the actual analysis task. This function calls a SwingWorker task so the GUI remains responsive during processing.
     */
    private void runSSIZAnalysisTask() {

        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        mouseListenersActive = false;

        this.getContentPane().add(panelProgressBar, BorderLayout.SOUTH);
        panelProgressBar.setVisible(true);
        progressBar.setValue(0);

        // Enable and disable the appropriate GUI components during analysis
        actionBrowse.setEnabled(false);
        actionExportPDF.setEnabled(false);
        actionExportPNG.setEnabled(false);
        actionRun.setEnabled(false);
        actionSaveTable.setEnabled(false);
        chkCommonYears.setEnabled(false);
        chkExcludeSeriesWithNoEvents.setEnabled(false);
        segmentationPanel.chkSegmentation.setEnabled(false);
        simulationsTable.setEnabled(false);
        btnCancelAnalysis.setVisible(true);

        SSIZAnalysisModel analysisModel = createSSIZAnalysisModel();

        (task = new DrawSSIZAnalysisTask(analysisModel)).execute();

        validate();
        repaint();
    }

    private static class ResultPair {

        private final Integer progress;
        private final SSIZAnalysisModel model;

        ResultPair(Integer progress, SSIZAnalysisModel model) {

            this.progress = progress;
            this.model = model;
        }
    }

    /**
     * SwingWorker class for handling the calling of the analysis and drawing the progress bar.
     */
    private class DrawSSIZAnalysisTask extends SwingWorker<SSIZAnalysisModel, ResultPair> {

        private final SSIZAnalysisModel analysisModel;

        public DrawSSIZAnalysisTask(SSIZAnalysisModel analysisModel) {

            super();
            this.analysisModel = analysisModel;
            taskWasCancelled = false;
        }

        @Override
        protected void process(List<ResultPair> progressList) {

            ResultPair current = progressList.get(progressList.size() - 1);

            int maxitems = current.model.getSegments().size() * current.model.getSeriesPoolToAnalyze().size();
            progressBar.setMaximum(maxitems);

            progressBar.setValue(current.progress);
            displayChartAndTableOutput(current.model);

            if (current.model.getSegments().size() > 1 && segmentsDone < current.model.getSegments().size()) {
                if (segmentsDone > 0)
                    cboSegment.setSelectedIndex(segmentsDone);
            }

        }

        /**
         * Run the analysis in the background updating progress bar as it goes
         */
        @Override
        protected SSIZAnalysisModel doInBackground() throws Exception {

            SSIZController.doPreRunSetup(analysisModel);

            segmentsDone = 0;

            // Loop through from 1 to n series
            for (SegmentModel segment : analysisModel.getSegments()) {
                Double centuryMultiplier = SSIZController.getCenturyMultiplier(analysisModel, segment);

                for (int n = 1; n <= analysisModel.getSeriesPoolToAnalyze().size(); n++) {
                    if (task.isCancelled()) {
                        log.debug("Current analysis task has been cancelled");
                        return null;
                    }

                    SSIZController.runSampleSizeAnalysisLoopIteration(analysisModel, centuryMultiplier, n, segment);

                    Integer currentItem = (segmentsDone * analysisModel.getSeriesPoolToAnalyze().size()) + n;
                    // progressBar.setValue(currentItem);

                    // Draws the chart and table once for every 25 iterations completed (only when there is one segment)
                    // if (currentItem % 25 == 0 && analysisModel.getSegments().size() == 1)
                    // displayChartAndTableOutput(analysisModel);
                    publish(new ResultPair(currentItem, analysisModel));
                }

                // Draws the chart and table after every segment is completed (when multiple segments have been specified)
                /*
                 * if (analysisModel.getSegments().size() > 1 && segmentsDone < analysisModel.getSegments().size()) { if (segmentsDone > 0)
                 * cboSegment.setSelectedIndex(segmentsDone);
                 * 
                 * displayChartAndTableOutput(analysisModel); }
                 */

                segmentsDone++;
            }
            return analysisModel;
        }

        /**
         * Function called when the analysis is complete. This draws the results and resets the progress bar/cursor etc.
         */
        @Override
        public void done() {

            panelProgressBar.setVisible(false);
            getContentPane().remove(panelProgressBar);

            mouseListenersActive = true;
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));

            // Enable and disable the appropriate GUI components after analysis
            actionBrowse.setEnabled(true);
            actionExportPDF.setEnabled(true);
            actionExportPNG.setEnabled(true);
            actionRun.setEnabled(true);
            actionSaveTable.setEnabled(true);
            chkCommonYears.setEnabled(true);
            chkExcludeSeriesWithNoEvents.setEnabled(true);
            segmentationPanel.chkSegmentation.setEnabled(true);
            simulationsTable.setEnabled(true);
            btnCancelAnalysis.setVisible(false);

            SSIZAnalysisModel mdl = null;
            try {
                mdl = get();
            } catch (InterruptedException e) {
                log.debug("Interrupted exception caught");

            } catch (ExecutionException e) {
                log.debug("Execution exception caught");
            } catch (CancellationException e) {
                log.debug("Cancellation exception caught");

            }

            if (!taskWasCancelled) {
                // Reset segmentsDone so that the chart defaults to the first segment when displaying
                segmentsDone = 0;
                displayChartAndTableOutput(mdl);
            }

            // Reset this flag so that file names may be loaded from the text field again.
            fileDialogWasUsed = false;
        }
    }

    /**
     * Updates and redraws the results table and curve chart on the GUI.
     */
    private void displayChartAndTableOutput(SSIZAnalysisModel analysisModel) {

        try {
            // Generate the SSIZAnalysisModel for this analysis
            populateFromAnalysisModel(analysisModel);

            // Update the results table with the analysis results
            simulationsTable.redrawTable(SSIZController.getAnalysisResults());

            // Update the curve chart with the analysis results
            updateChart();

            validate();
            repaint();
        } catch (Exception e) {
            e.printStackTrace();
            log.error("Error redrawing chart and table");
        }
    }

    /**
     * Generate the SSIZAnalysisModel representing the data and parameters for this analysis.
     * 
     * @param model
     */
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public void populateFromAnalysisModel(SSIZAnalysisModel model) {

        DefaultComboBoxModel combomodel = new DefaultComboBoxModel();

        for (SegmentModel segment : model.getSegments())
            combomodel.addElement(segment);

        cboSegment.setModel(combomodel);
        cboSegment.setEnabled(model.getSegments().size() > 1);

        // cboSegment.setSelectedIndex(segmentsDone);
        cboChartMetric.setEnabled(true);
    }

    /**
     * Update the chart on the screen using the parameters specified by the user.
     */
    private void updateChart() {

        curveChart = new SSIZCurveChart(
                SSIZController.getAnalysisResults()
                        .toArray(new AnalysisResultsModel[SSIZController.getAnalysisResults().size()]),
                (MiddleMetric) this.cboChartMetric.getSelectedItem(), (SegmentModel) cboSegment.getSelectedItem());
        curveChart.addMouseListener(new ChartPopClickListener());
        curveChart.setMaximumDrawHeight(MAX_DRAW_HEIGHT);
        curveChart.setMaximumDrawWidth(MAX_DRAW_WIDTH);
        panelChart.removeAll();
        panelChart.add(curveChart, BorderLayout.CENTER);
        panelChart.revalidate();
        panelChart.repaint();
    }

    /**
     * Copy the simulations chart to the system clip-board.
     */
    private void copyChartToClipboard() {

        curveChart.doCopy();
    }

    /**
     * Copy the simulations data currently selected in the table to the system clip-board.
     */
    private void copyTableToClipboard() {

        adapter.doCopy();
    }

    /**
     * TODO
     */
    @SuppressWarnings("unused")
    private class ScrollViewport extends JViewport implements Scrollable {

        private static final long serialVersionUID = 1L;

        @Override
        public Dimension getPreferredScrollableViewportSize() {

            return getPreferredSize();
        }

        @Override
        public int getScrollableBlockIncrement(Rectangle visibleRect, int orientation, int direction) {

            return 30;
        }

        @Override
        public boolean getScrollableTracksViewportHeight() {

            return false;
        }

        @Override
        public boolean getScrollableTracksViewportWidth() {

            return true;
        }

        @Override
        public int getScrollableUnitIncrement(Rectangle visibleRect, int orientation, int direction) {

            return 1;
        }
    }

    /**
     * The pop-up menu for the simulations chart
     */
    private class ChartPopupMenu extends JPopupMenu {

        private static final long serialVersionUID = 1L;

        JMenuItem exportToPDF;
        JMenuItem exportToPNG;

        public ChartPopupMenu() {

            JMenuItem chartProperties = new JMenuItem("Properties");
            chartProperties.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {

                    ChartEditor editor = ChartEditorManager.getChartEditor(curveChart.getChart());
                    int result = JOptionPane.showConfirmDialog(null, editor, "Properties",
                            JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE);

                    if (result == JOptionPane.OK_OPTION)
                        editor.updateChart(curveChart.getChart());
                }
            });
            add(chartProperties);

            exportToPDF = new JMenuItem("Export to PDF");
            exportToPDF.setAction(actionExportPDF);
            exportToPDF.setIcon(Builder.getImageIcon("pdf.png"));
            add(exportToPDF);

            exportToPNG = new JMenuItem("Export to PNG");
            exportToPNG.setAction(actionExportPNG);
            exportToPNG.setIcon(Builder.getImageIcon("formatpng.png"));
            add(exportToPNG);

            addSeparator();

            JMenuItem copy = new JMenuItem("Copy");
            copy.setIcon(Builder.getImageIcon("edit_copy.png"));
            copy.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {

                    copyChartToClipboard();
                }
            });
            add(copy);
        }
    }

    /**
     * The pop-up menu for the simulations data table
     */
    private class TablePopupMenu extends JPopupMenu {

        private static final long serialVersionUID = 1L;

        JMenuItem exportToTAB;

        public TablePopupMenu() {

            exportToTAB = new JMenuItem("Export to tab delimited text file");
            exportToTAB.setIcon(Builder.getImageIcon("formattab.png"));
            exportToTAB.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent arg0) {

                    saveTableToTextFile();
                }
            });
            add(exportToTAB);

            addSeparator();

            JMenuItem selectAll = new JMenuItem("Select all");
            selectAll.setIcon(Builder.getImageIcon("selectall.png"));
            selectAll.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {

                    simulationsTable.selectAll();
                }
            });
            add(selectAll);

            JMenuItem copy = new JMenuItem("Copy");
            copy.setIcon(Builder.getImageIcon("edit_copy.png"));
            copy.addActionListener(new ActionListener() {

                @Override
                public void actionPerformed(ActionEvent e) {

                    copyTableToClipboard();
                }
            });
            add(copy);
        }
    }

    public void saveTableToTextFile() {

        File fileToSave = getFileFromSaveDialog("TAB");
        if (fileToSave != null)
            SSIZResultsTable.exportResultsTableToTAB(fileToSave, adapter);
    }

    public void saveChartToPDF() {

        try {
            File fileToSave = getFileFromSaveDialog("PDF");
            if (fileToSave != null)
                SSIZCurveChart.writeAsPDF(fileToSave, curveChart.getWidth(), curveChart.getHeight());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void saveChartToPNG() {

        try {
            curveChart.doSaveAs();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    /**
     * The pop-up listener for the simulations chart
     */
    private class ChartPopClickListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent arg0) {

            if (arg0.isPopupTrigger() && mouseListenersActive)
                doPop(arg0);
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {

            if (arg0.isPopupTrigger() && mouseListenersActive)
                doPop(arg0);
        }

        private void doPop(MouseEvent arg0) {

            ChartPopupMenu menu = new ChartPopupMenu();
            menu.show(arg0.getComponent(), arg0.getX(), arg0.getY());
        }
    }

    /**
     * The pop-up listener for the simulations data table.
     */
    private class TablePopClickListener extends MouseAdapter {

        @Override
        public void mousePressed(MouseEvent arg0) {

            if (arg0.isPopupTrigger() && mouseListenersActive)
                doPop(arg0);
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {

            if (arg0.isPopupTrigger() && mouseListenersActive)
                doPop(arg0);
        }

        private void doPop(MouseEvent arg0) {

            TablePopupMenu menu = new TablePopupMenu();
            menu.show(arg0.getComponent(), arg0.getX(), arg0.getY());
        }
    }

}