it.unifi.rcl.chess.traceanalysis.gui.TracePanel.java Source code

Java tutorial

Introduction

Here is the source code for it.unifi.rcl.chess.traceanalysis.gui.TracePanel.java

Source

/*******************************************************************************
 * Copyright (c) 2015-2017 Resilient Computing Lab, University of Firenze.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Leonardo Montecchi      lmontecchi@unifi.it
 ******************************************************************************/
package it.unifi.rcl.chess.traceanalysis.gui;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Font;
import java.awt.Stroke;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.lang.reflect.Array;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;

import it.unifi.rcl.chess.traceanalysis.Trace;
import it.unifi.rcl.chess.traceanalysis.Utils;
import it.unifi.rcl.chess.traceanalysis.distributions.CHDistribution;

import javax.swing.AbstractAction;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JProgressBar;
import javax.swing.JScrollPane;
import javax.swing.JTabbedPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.border.EmptyBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableModel;

import org.eclipse.swt.graphics.RGB;
import org.jfree.chart.ChartColor;
import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.chart.renderer.xy.XYItemRenderer;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.data.xy.WindDataset;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;
import org.jfree.ui.Align;

import com.jgoodies.forms.layout.CellConstraints.Alignment;

import monitoringService.MonitoringService;
import monitoringService.distributions.Distribution;

public class TracePanel extends JPanel {

    private static final String TXT_NOFILE = "No file loaded.";

    private Trace trace;

    JTextField txtFile;
    JButton btnReload, btnClose;
    JButton btnUpdateBoundsTable, btnClearBoundsTable;
    JButton btnPhaseDetection;
    JLabel lblInfo;
    JLabel lblSize;
    JLabel lblPoints;
    JProgressBar progressBar;
    JScrollPane scrollTabBounds, scrollTabWSize;
    BoundsTable tableBounds;
    JDynamicTable tableWindowSize;
    JLabel lblTraceName;
    JLabel lblStat;
    JButton btnPlot, btnClearWSizeTable, btnBoundExport, btnCompareAll;
    JScrollPane scrollTabPhases;
    JTable tablePhases;

    JLabel lblPhasesWSize;
    JTextField txtPhasesWSize;
    JLabel lblPhasesCoverage;
    JTextField txtPhasesCoverage;

    JLabel lblSectionBounds;
    JLabel lblSectionPlot;
    JLabel lblSectionPhases;

    public TracePanel() {
        initialize();
    }

    public TracePanel(File f) {
        this();
        loadTrace(f);
    }

    public void setTitle(String t) {
        JTabbedPane parent = ((JTabbedPane) getParent());
        parent.setTitleAt(parent.indexOfComponent(TracePanel.this), t);
    }

    public String getTitle() {
        JTabbedPane parent = ((JTabbedPane) getParent());
        return parent.getTitleAt(parent.indexOfComponent(TracePanel.this));
    }

    public Trace getTrace() {
        return trace;
    }

    public void loadTrace(File file) {
        ;
        loadTrace(new Trace(file), file.getAbsolutePath());
    }

    public void loadTrace(Trace t, String name) {
        trace = t;

        tableBounds.setTrace(trace);

        refresh();
    }

    private void refresh() {
        lblTraceName.setText(trace.getName(30));
        lblTraceName.setToolTipText(trace.getName());
        ;

        if (trace == null) {
            lblPoints.setText("No data.");
        } else {
            lblPoints.setText(trace.getSampleSize() + " points loaded.");

            lblStat.setText("<html><br/><b>Min:</b> " + trace.getMin() + "<br/><b>Max:</b> " + trace.getMax()
                    + "<br/><b>Average:</b> " + trace.getAverage() + "<br/><br/></html>");
        }

        tableBounds.updateValues();
    }

    public void dispose() {
        JTabbedPane parent = ((JTabbedPane) getParent());
        parent.removeTabAt(parent.indexOfComponent(this));
    }

    private void initialize() {

        this.setLayout(new FlowLayout(FlowLayout.CENTER, 5, 5));

        JPanel pnlInfo = new JPanel();
        JPanel pnlBound = new JPanel();
        JPanel pnlPlot = new JPanel();
        JPanel pnlPhases = new JPanel();

        pnlInfo.setLayout(new BoxLayout(pnlInfo, BoxLayout.Y_AXIS));
        pnlBound.setLayout(new BoxLayout(pnlBound, BoxLayout.Y_AXIS));
        pnlPlot.setLayout(new BoxLayout(pnlPlot, BoxLayout.Y_AXIS));
        pnlPhases.setLayout(new BoxLayout(pnlPhases, BoxLayout.Y_AXIS));

        //      pnlInfo.setBorder(BorderFactory.createLineBorder(Color.black));
        //      pnlBound.setBorder(BorderFactory.createLineBorder(Color.black));
        //      pnlPlot.setBorder(BorderFactory.createLineBorder(Color.black));
        //      pnlPhases.setBorder(BorderFactory.createLineBorder(Color.black));
        pnlInfo.setPreferredSize(new Dimension(300, 250));
        pnlBound.setPreferredSize(new Dimension(400, 250));
        pnlPlot.setPreferredSize(new Dimension(300, 250));
        pnlPhases.setPreferredSize(new Dimension(400, 250));

        pnlInfo.setBorder(new EmptyBorder(6, 6, 6, 6));
        pnlBound.setBorder(new EmptyBorder(6, 6, 6, 6));
        pnlPlot.setBorder(new EmptyBorder(6, 6, 6, 6));
        pnlPhases.setBorder(new EmptyBorder(6, 6, 6, 6));

        this.add(pnlInfo);
        this.add(pnlBound);
        this.add(pnlPlot);
        this.add(pnlPhases);

        lblInfo = new JPlainLabel("<html><b>TRACE SUMMARY</b><br/>"
                + "<em>Information about the loaded trace.</em><br/><br/></html>");
        pnlInfo.add(lblInfo);

        lblPoints = new JPlainLabel("#Points");
        pnlInfo.add(lblPoints);

        lblTraceName = new JPlainLabel();
        pnlInfo.add(lblTraceName);

        lblStat = new JPlainLabel();
        pnlInfo.add(lblStat);

        btnReload = new JButton("Reload");
        btnReload.addActionListener(new ButtonAction("Reload", KeyEvent.VK_L));
        pnlInfo.add(btnReload);

        btnClose = new JButton("Close");
        btnClose.addActionListener(new ButtonAction("Close", KeyEvent.VK_U));
        pnlInfo.add(btnClose);

        /* Bound evaluation */
        lblSectionBounds = new JPlainLabel("<html><b>BOUND EVALUATION</b><br/>"
                + "<em>Compute probabilistic bounds on manually selected portions of the trace.</em></html>");
        lblSectionBounds.setToolTipText("Compute probabilistic bounds on manually selected portions of the trace");
        lblSectionBounds.setFont(new Font("Dialog", Font.PLAIN, 12));
        //      lblSectionBounds.setBorder(BorderFactory.createLineBorder(Color.black));
        pnlBound.add(lblSectionBounds);

        scrollTabBounds = new JScrollPane();
        scrollTabBounds.setPreferredSize(new Dimension(400, 100));
        pnlBound.add(scrollTabBounds);

        tableBounds = new BoundsTable();
        scrollTabBounds.setViewportView(tableBounds);

        btnUpdateBoundsTable = new JButton("Update");
        btnUpdateBoundsTable.addActionListener(new ButtonAction("Update", KeyEvent.VK_U));
        pnlBound.add(btnUpdateBoundsTable);

        btnClearBoundsTable = new JButton("Clear Table");
        btnClearBoundsTable.addActionListener(new ButtonAction("Clear Table", KeyEvent.VK_C));
        pnlBound.add(btnClearBoundsTable);

        /* Plotting */
        lblSectionPlot = new JPlainLabel("<html><b>PLOTTING</b><br/>"
                + "<em>Plot the trace, together with \"dynamic\" probabilistic bounds, i.e., bounds obtained dynamically as if they were evaluated at runtime with a fixed window size.</em></html>");
        lblSectionPlot.setToolTipText("Plot the trace and dynamic bounds");
        pnlPlot.add(lblSectionPlot);

        scrollTabWSize = new JScrollPane();
        scrollTabWSize.setPreferredSize(new Dimension(400, 200));
        pnlPlot.add(scrollTabWSize);

        tableWindowSize = new JDynamicTable();
        tableWindowSize.setModel(new DefaultTableModel(new Object[][] { { 100, 0.99 }, { null, null } },
                new String[] { "WindowSize", "Confidence" }) {

            Class[] columnTypes = new Class[] { Integer.class, Double.class };

            public Class getColumnClass(int columnIndex) {
                return columnTypes[columnIndex];
            }
        });
        tableWindowSize.setMonitoredColumn(0);
        tableWindowSize.setMonitoredColumn(1);
        tableWindowSize.getColumnModel().getColumn(0).setPreferredWidth(10);
        tableWindowSize.getColumnModel().getColumn(1).setPreferredWidth(10);
        scrollTabWSize.setViewportView(tableWindowSize);

        btnPlot = new JButton("Plot");
        btnPlot.addActionListener(new ButtonAction("Plot", KeyEvent.VK_P));
        pnlPlot.add(btnPlot);

        btnBoundExport = new JButton("Export");
        btnBoundExport.addActionListener(new ButtonAction("Export", KeyEvent.VK_E));
        pnlPlot.add(btnBoundExport);

        btnCompareAll = new JButton("Compare All Traces");
        btnCompareAll.addActionListener(new ButtonAction("Compare All Traces", KeyEvent.VK_A));
        pnlPlot.add(btnCompareAll);

        btnClearWSizeTable = new JButton("Clear Table");
        btnClearWSizeTable.addActionListener(new ButtonAction("Clear Table", KeyEvent.VK_C));
        pnlPlot.add(btnClearWSizeTable);

        /* Phases analysis */
        lblSectionPhases = new JPlainLabel("<html><b>PHASES ANALYSIS</b><br/>"
                + "<em>Detect phases in the trace having different probabilistic properties.</em></html>.");
        lblSectionPhases.setToolTipText("Detect phases in the trace having different probabilistic properties");
        pnlPhases.add(lblSectionPhases);

        scrollTabPhases = new JScrollPane();
        scrollTabPhases.setPreferredSize(new Dimension(200, 150));
        pnlPhases.add(scrollTabPhases);

        tablePhases = new JTable();
        tablePhases.setModel(new DefaultTableModel(new Object[][] { { null, null, null, null } },
                new String[] { "Start", "End", "Distribution*", "Bound*" }) {

            Class[] columnTypes = new Class[] { Integer.class, Integer.class, String.class, String.class };

            public Class getColumnClass(int columnIndex) {
                return columnTypes[columnIndex];
            }

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        });
        tablePhases.getColumnModel().getColumn(0).setPreferredWidth(10);
        tablePhases.getColumnModel().getColumn(1).setPreferredWidth(10);
        tablePhases.getColumnModel().getColumn(2).setPreferredWidth(100);
        tablePhases.getColumnModel().getColumn(3).setPreferredWidth(100);
        scrollTabPhases.setViewportView(tablePhases);

        lblPhasesCoverage = new JPlainLabel("Coverage: ");
        pnlPhases.add(lblPhasesCoverage);
        txtPhasesCoverage = new JTextField("0.99");
        pnlPhases.add(txtPhasesCoverage);

        lblPhasesWSize = new JPlainLabel("Window Size: ");
        pnlPhases.add(lblPhasesWSize);
        txtPhasesWSize = new JTextField("20");
        pnlPhases.add(txtPhasesWSize);

        btnPhaseDetection = new JButton("Phases Analysis");
        ;
        btnPhaseDetection.addActionListener(new ButtonAction("PhasesAnalysis", KeyEvent.VK_P));
        pnlPhases.add(btnPhaseDetection);
    }

    private void phaseDetection() {
        final class Phase {
            int start;
            int end;
            CHDistribution dist;
            double bound;

            public Phase(int start, int end) {
                this.start = start;
                this.end = end;
            }
        }

        double coverage = Double.parseDouble(txtPhasesCoverage.getText());
        int wsize = Integer.parseInt(txtPhasesWSize.getText());

        CHDistribution[] dists = trace.getPhases(coverage, wsize);
        CHDistribution curDist = null;
        CHDistribution lastDist = null;
        int iPhaseBegin, iPhaseEnd;
        Phase p = null;

        DefaultTableModel model = (DefaultTableModel) tablePhases.getModel();
        while (model.getRowCount() > 0) {
            model.removeRow(0);
        }

        if (wsize > 1) {
            // ignore initial window
            model.addRow(new Object[] { 1, (wsize - 1), "{undefined}", "" });
        }

        iPhaseBegin = 0;
        iPhaseEnd = 0;
        curDist = dists[0];
        for (int i = 1; i < dists.length; i++) {
            lastDist = curDist;
            curDist = dists[i];
            if (!curDist.equals(lastDist)) {
                // distribution is different from the previous: phase change
                p = new Phase(iPhaseBegin, iPhaseEnd + (wsize - 1));
                p.dist = lastDist;
                p.bound = trace.getSubTrace(p.start, p.end).getBound(coverage);

                iPhaseBegin = i;
                iPhaseEnd = i;

                model.addRow(new Object[] { p.start + 1 + (wsize - 1), p.end + 1, p.dist.toString(), p.bound });
            } else {
                // distribution is the same (also parameters), phase is extended
                iPhaseEnd++;
            }
        }

        p = new Phase(iPhaseBegin, iPhaseEnd + (wsize - 1));
        p.dist = lastDist;
        p.bound = trace.getSubTrace(p.start, p.end).getBound(coverage);

        model.addRow(new Object[] { p.start + 1 + (wsize - 1), p.end + 1, p.dist.toString(), p.bound });
        tablePhases.setModel(model);
    }

    private void exportBounds() {
        int rows = tableWindowSize.getRowCount();
        double coverage;
        int wsize;
        File fExport;
        Writer wr;
        double[] bounds;
        for (int i = 0; i < rows; i++) {
            try {
                wsize = (Integer) tableWindowSize.getValueAt(i, 0);
                coverage = (Double) tableWindowSize.getValueAt(i, 1);
                bounds = trace.getDynamicBound(coverage, wsize);

                fExport = new File(trace.getName() + "_w" + wsize + "_c" + coverage);
                wr = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(fExport)));
                wr.write("# window size: " + wsize + "\r\n" + "# coverage: " + coverage + "\r\n");
                for (int j = 0; j < bounds.length; j++) {
                    wr.write(bounds[j] + "\r\n");
                }

                wr.close();

            } catch (NullPointerException e) {
                ;
            } catch (FileNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
    }

    private void plotTrace() {
        XYSeriesCollection dataset = new XYSeriesCollection();

        XYSeries xyBoundsPositive = null;
        XYSeries xyBoundsNegative = null;
        Trace[] posNeg = null;

        dataset.addSeries(Plotter.traceToSeries(trace));
        dataset.addSeries(Plotter.valueToSeries(trace.getMax(), "Max", trace.getSampleSize()));
        dataset.addSeries(Plotter.valueToSeries(trace.getAverage(), "Average", trace.getSampleSize()));
        dataset.addSeries(Plotter.valueToSeries(trace.getMin(), "Min", trace.getSampleSize()));

        int rows = tableWindowSize.getRowCount();
        double coverage;
        int wsize;
        for (int i = 0; i < rows; i++) {
            try {
                wsize = (Integer) tableWindowSize.getValueAt(i, 0);
                coverage = (Double) tableWindowSize.getValueAt(i, 1);

                if (trace.hasNegativeValues()) {
                    posNeg = trace.splitPositiveNegative();
                    xyBoundsPositive = Plotter.arrayToSeries(posNeg[0].getDynamicBound(coverage, wsize),
                            "c=" + coverage + ",w=" + wsize, wsize - 1);
                    xyBoundsNegative = Plotter.arrayToSeriesInvert(posNeg[1].getDynamicBound(coverage, wsize),
                            "c=" + coverage + ",w=" + wsize + "(neg)", wsize - 1);
                    dataset.addSeries(xyBoundsPositive);
                    dataset.addSeries(xyBoundsNegative);
                } else {
                    dataset.addSeries(Plotter.arrayToSeries(trace.getDynamicBound(coverage, wsize),
                            "c=" + coverage + ",w=" + wsize, wsize - 1));
                }
            } catch (NullPointerException e) {
                //Ignore: cell value is null
                ;
            }
        }

        // Generate the graph
        JFreeChart chart = ChartFactory.createXYLineChart(trace.getName(),
                // Title
                "Time Point",
                // x-axis Labels
                "Value",
                // y-axis Label
                dataset,
                // Dataset
                PlotOrientation.VERTICAL, // Plot Orientation
                true,
                // Show Legend
                true,
                // Use tooltips
                false
        // Configure chart to generate URLs?
        );

        chart.setBackgroundPaint(Color.WHITE);
        chart.getXYPlot().setBackgroundPaint(ChartColor.VERY_LIGHT_YELLOW);
        chart.getXYPlot().setBackgroundAlpha(0.05f);
        chart.getXYPlot().setRangeGridlinePaint(Color.LIGHT_GRAY);
        chart.getXYPlot().setDomainGridlinePaint(Color.LIGHT_GRAY);

        chart.getTitle().setFont(new Font("Dialog", Font.BOLD, 14));

        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        renderer.setDrawSeriesLineAsPath(true);
        chart.getXYPlot().setRenderer(renderer);

        renderer.setSeriesPaint(0, Color.BLACK);
        renderer.setSeriesPaint(1, ChartColor.DARK_BLUE);
        renderer.setSeriesPaint(2, ChartColor.DARK_GRAY);
        renderer.setSeriesPaint(3, ChartColor.DARK_BLUE);
        renderer.setSeriesPaint(4, ChartColor.RED);

        int nSeries = chart.getXYPlot().getSeriesCount();
        for (int i = 0; i < nSeries; i++) {
            renderer.setSeriesShapesVisible(i, false);
        }
        if (posNeg != null) {
            renderer.setSeriesVisibleInLegend(5, false);
            renderer.setSeriesPaint(5, renderer.getSeriesPaint(4));
        }

        Stroke plainStroke = new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f);

        renderer.setSeriesStroke(0, plainStroke);
        renderer.setSeriesStroke(1, new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f,
                new float[] { 6.0f, 3.0f }, 0.0f));
        renderer.setSeriesStroke(2, new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f,
                new float[] { 3.0f, 0.5f, 3.0f }, 0.0f));
        renderer.setSeriesStroke(3, new BasicStroke(1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f,
                new float[] { 6.0f, 3.0f }, 0.0f));

        JPanel plotPanel = new ChartPanel(chart);
        JFrame plotFrame = new JFrame();
        plotFrame.add(plotPanel);
        plotFrame.setVisible(true);
        plotFrame.pack();
        plotFrame.setTitle(TracePanel.this.trace.getName());
        plotFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    private void plotCompare() {
        XYSeriesCollection dataset = new XYSeriesCollection();

        XYSeries xyBoundsPositive = null;
        XYSeries xyBoundsNegative = null;
        Trace[] posNeg = null;

        Component[] siblings = this.getParent().getComponents();
        Trace[] allTraces = new Trace[siblings.length];

        int rows = tableWindowSize.getRowCount();
        double coverage = 0.99;
        int wsize = 100;
        for (int i = 0; i < rows; i++) {
            try {
                wsize = (Integer) tableWindowSize.getValueAt(i, 0);
                coverage = (Double) tableWindowSize.getValueAt(i, 1);
            } catch (NullPointerException e) {
                //Ignore: cell value is null
                ;
            }
        }

        for (int i = 0; i < siblings.length; i++) {
            allTraces[i] = ((TracePanel) siblings[i]).getTrace();

            if (allTraces[i].hasNegativeValues()) {
                posNeg = allTraces[i].splitPositiveNegative();
                xyBoundsPositive = Plotter.arrayToSeries(posNeg[0].getDynamicBound(coverage, wsize),
                        allTraces[i].getName(), wsize - 1);
                xyBoundsNegative = Plotter.arrayToSeriesInvert(posNeg[1].getDynamicBound(coverage, wsize),
                        allTraces[i].getName() + "(neg)", wsize - 1);
                dataset.addSeries(xyBoundsPositive);
                dataset.addSeries(xyBoundsNegative);
            } else {
                dataset.addSeries(Plotter.arrayToSeries(allTraces[i].getDynamicBound(coverage, wsize),
                        allTraces[i].getName(), wsize - 1));
            }
        }

        // Generate the graph
        JFreeChart chart = ChartFactory.createXYLineChart("Comparative Plot (c=" + coverage + ",w=" + wsize + ")",
                // Title
                "Time Point",
                // x-axis Labels
                "Value",
                // y-axis Label
                dataset,
                // Dataset
                PlotOrientation.VERTICAL, // Plot Orientation
                true,
                // Show Legend
                true,
                // Use tooltips
                false
        // Configure chart to generate URLs?
        );

        chart.setBackgroundPaint(Color.WHITE);
        chart.getXYPlot().setBackgroundPaint(ChartColor.VERY_LIGHT_YELLOW);
        chart.getXYPlot().setBackgroundAlpha(0.05f);
        chart.getXYPlot().setRangeGridlinePaint(Color.LIGHT_GRAY);
        chart.getXYPlot().setDomainGridlinePaint(Color.LIGHT_GRAY);

        chart.getTitle().setFont(new Font("Dialog", Font.BOLD, 14));

        XYLineAndShapeRenderer renderer = new XYLineAndShapeRenderer();
        renderer.setDrawSeriesLineAsPath(true);
        chart.getXYPlot().setRenderer(renderer);

        renderer.setSeriesPaint(0, Color.BLACK);
        renderer.setSeriesPaint(1, ChartColor.DARK_GREEN);
        renderer.setSeriesPaint(2, ChartColor.DARK_BLUE);
        renderer.setSeriesPaint(3, ChartColor.RED);

        int nSeries = chart.getXYPlot().getSeriesCount();
        for (int i = 0; i < nSeries; i++) {
            renderer.setSeriesShapesVisible(i, false);
        }
        if (posNeg != null) {
            renderer.setSeriesVisibleInLegend(5, false);
            renderer.setSeriesPaint(5, renderer.getSeriesPaint(4));
        }

        //      Stroke plainStroke = new BasicStroke(
        //                    1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f
        //                );
        //      
        //      renderer.setSeriesStroke(0, plainStroke);
        //      renderer.setSeriesStroke(1, 
        //            new BasicStroke(
        //                 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[] { 6.0f, 3.0f }, 0.0f
        //             ));
        //      renderer.setSeriesStroke(2, 
        //            new BasicStroke(
        //                 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[] { 3.0f, 0.5f, 3.0f }, 0.0f
        //             ));
        //      renderer.setSeriesStroke(3, 
        //            new BasicStroke(
        //                 1.0f, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND, 1.0f, new float[] { 6.0f, 3.0f }, 0.0f
        //             ));

        JPanel plotPanel = new ChartPanel(chart);
        JFrame plotFrame = new JFrame();
        plotFrame.add(plotPanel);
        plotFrame.setVisible(true);
        plotFrame.pack();
        plotFrame.setTitle(TracePanel.this.trace.getName());
        plotFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    }

    private class ButtonAction extends AbstractAction {

        public ButtonAction(String name, Integer mnemonic) {
            super(name);
            putValue(MNEMONIC_KEY, mnemonic);
        }

        @Override
        public void actionPerformed(ActionEvent e) {

            Object src = e.getSource();

            if (src == btnReload) {
                loadTrace(new File(txtFile.getText()));
                refresh();
            } else if (src == btnClose) {
                dispose();
            } else if (src == btnUpdateBoundsTable) {
                tableBounds.updateValues();
            } else if (src == btnClearBoundsTable) {
                tableBounds.reset();
            } else if (src == btnPlot) {
                plotTrace();
            } else if (src == btnBoundExport) {
                exportBounds();
            } else if (src == btnCompareAll) {
                plotCompare();
            } else if (src == btnClearWSizeTable) {
                tableWindowSize.clear();
                tableWindowSize.setValueAt(100, 0, 0);
                tableWindowSize.setValueAt(0.99, 0, 1);
            } else if (src == btnPhaseDetection) {
                phaseDetection();
            }
        };
    }
}