anl.verdi.plot.anim.MultiPlotAnimation.java Source code

Java tutorial

Introduction

Here is the source code for anl.verdi.plot.anim.MultiPlotAnimation.java

Source

package anl.verdi.plot.anim;

import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashSet;
import java.util.Set;

import javax.swing.DefaultListCellRenderer;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.ListModel;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.filechooser.FileFilter;

import org.apache.logging.log4j.LogManager; // 2014
import org.apache.logging.log4j.Logger; // 2014 replacing System.out.println with logger messages

import anl.verdi.data.Axes;
import anl.verdi.data.DataFrame;
import anl.verdi.data.DataFrameAxis;
import anl.verdi.plot.gui.Plot;
import anl.verdi.plot.types.TimeAnimatablePlot;
import anl.verdi.plot.util.AnimationListener;
import anl.verdi.util.DateRange;
import anl.verdi.util.Utilities;

import com.jgoodies.forms.factories.DefaultComponentFactory;
import com.jgoodies.forms.factories.FormFactory;
import com.jgoodies.forms.layout.CellConstraints;
import com.jgoodies.forms.layout.ColumnSpec;
import com.jgoodies.forms.layout.FormLayout;
import com.jgoodies.forms.layout.FormSpec;
import com.jgoodies.forms.layout.RowSpec;
import com.jgoodies.forms.layout.Sizes;
import com.jidesoft.swing.CheckBoxList;

/**
 * @author User #2
 */
public class MultiPlotAnimation extends JPanel implements AnimationListener {
    static final Logger Logger = LogManager.getLogger(MultiPlotAnimation.class.getName());

    private static final long serialVersionUID = -6833233954013917115L;
    private DateRange currentRange = null;
    private int currentSteps = -1;
    private Set<Integer> badIndices = new HashSet<Integer>();
    private Set<Integer> currentSelections = new HashSet<Integer>();
    private JButton startButton;
    private DateModel dateModel = new DateModel();
    private MultiPlotAnimator animator;
    private File gifFile;

    private class DateModel {

        long start, end, interval;

        public Date getDate(int index) {
            long val = start + interval * index;
            if (val > end)
                val = end;
            return new Date(val);
        }

        boolean init(long start, long end, long interval) {
            boolean retVal = false;
            if (this.start != start) {
                this.start = start;
                retVal = true;
            }

            if (this.end != end) {
                this.end = end;
                retVal = true;
            }

            if (this.interval != interval) {
                this.interval = interval;
                retVal = true;
            }
            return retVal;
        }
    }

    private class ListRenderer extends DefaultListCellRenderer {

        /**
         * 
         */
        private static final long serialVersionUID = -7787305653195238102L;

        public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected,
                boolean cellHasFocus) {
            Component comp = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
            if (badIndices.contains(index)) {
                comp.setForeground(Color.RED);
            } else {
                comp.setForeground(Color.BLACK);
            }
            return comp;
        }
    }

    private static class PlotData {
        private Plot plot;
        private String label;
        private DateRange range;

        PlotData(Plot plot) {
            this.plot = plot;
            DataFrame frame = plot.getData().get(0);
            Axes<DataFrameAxis> axes = frame.getAxes();
            int origin = axes.getTimeAxis().getOrigin();
            GregorianCalendar start = axes.getDate(origin);
            GregorianCalendar end = axes.getDate(origin + axes.getTimeAxis().getExtent() - 1);
            Logger.debug("in MultiPlotAnimation just computed start and end GregorianCalendar");
            range = new DateRange(start, end);

            StringBuffer buf = new StringBuffer();
            DataFrame dataFrame = plot.getData().get(0);
            buf.append(dataFrame.getVariable().getName());
            buf.append(" (");
            buf.append(Utilities.formatShortDate(start));
            buf.append(" - ");
            buf.append(Utilities.formatShortDate(end));
            buf.append(", ");
            buf.append(axes.getTimeAxis().getExtent() - 1);
            buf.append(" Steps)");
            label = buf.toString();
        }

        public String toString() {
            return label;
        }

        public DateRange getRange() {
            return range;
        }

        public Plot getPlot() {
            return plot;
        }

        /**
         * Gets the number of timesteps in the specified range, or -1
         * if the range is invalid for this plto.
         *
         * @param range the date range
         * @return the number of timesteps in the specified range, or -1
         *         if the range is invalid for this plto.
         */
        public int getStepCount(DateRange range) {
            Axes<DataFrameAxis> axes = plot.getData().get(0).getAxes();
            int start = axes.getTimeStep(new Date(range.getStart()));
            if (start == Axes.TIME_STEP_NOT_FOUND)
                return -1;
            int end = axes.getTimeStep(new Date(range.getEnd()));
            if (end == Axes.TIME_STEP_NOT_FOUND)
                return -1;
            return end - start;
        }
    }

    public MultiPlotAnimation() {
        Logger.debug("in constructor for MultiPlotAnimation.java");
        initComponents();

        ((SpinnerNumberModel) startSpinner.getModel()).setMinimum(0);
        ((SpinnerNumberModel) startSpinner.getModel()).setMaximum(0);
        ((SpinnerNumberModel) endSpinner.getModel()).setMaximum(0);
        ((SpinnerNumberModel) endSpinner.getModel()).setMaximum(0);

        addListeners();
    }

    private void addListeners() {
        startSpinner.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                Integer val = (Integer) startSpinner.getValue();
                startLbl.setText(Utilities.formatShortDate(dateModel.getDate(val.intValue())));
            }
        });

        endSpinner.addChangeListener(new ChangeListener() {
            public void stateChanged(ChangeEvent e) {
                Integer val = (Integer) endSpinner.getValue();
                endLbl.setText(Utilities.formatShortDate(dateModel.getDate(val.intValue())));
            }
        });

        plotList.getCheckBoxListSelectionModel().addListSelectionListener(new ListSelectionListener() {
            public void valueChanged(ListSelectionEvent e) {
                if (!e.getValueIsAdjusting()) {
                    processListSelection();
                }
            }
        });
        plotList.setCellRenderer(new ListRenderer());

        gifChk.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                gifFileBtn.setEnabled(gifChk.isSelected());
                gifFileLbl.setEnabled(gifChk.isSelected());
                if (gifChk.isSelected() && gifFile == null) {
                    getGifFile();
                }
            }
        });

        gifFileBtn.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                getGifFile();
            }
        });
    }

    private void processListSelection() {
        badIndices.clear();
        int[] vals = plotList.getCheckBoxListSelectedIndices();
        Set<Integer> selectedSet = new HashSet<Integer>();
        for (int val : vals) {
            selectedSet.add(val);
        }
        if (!selectedSet.containsAll(currentSelections))
            currentRange = null;
        currentSelections = selectedSet;
        if (vals.length == 0)
            currentRange = null;
        else {
            ListModel listModel = plotList.getModel();
            if (currentRange == null || vals.length == 1) {
                PlotData plotData = (PlotData) listModel.getElementAt(vals[0]);
                currentRange = plotData.getRange();
                currentSteps = plotData.getStepCount(currentRange);
            }
            for (int val : vals) {
                PlotData plotData = (PlotData) listModel.getElementAt(val);
                DateRange range = plotData.getRange();
                DateRange newRange = currentRange.overlap(range);
                if (newRange == null) {
                    badIndices.add(val);
                } else {
                    int steps = plotData.getStepCount(newRange);
                    if (steps == -1 || steps != currentSteps) {
                        badIndices.add(val);
                    } else {
                        currentRange = newRange;
                    }
                }
            }
        }
        boolean enabled = badIndices.isEmpty() && vals.length > 0;
        startButton.setEnabled(enabled);
        startSpinner.setEnabled(enabled);
        startLbl.setEnabled(enabled);
        endSpinner.setEnabled(enabled);
        endLbl.setEnabled(enabled);

        if (enabled) {
            setSpinners();
        }
    }

    private void getGifFile() {
        JFileChooser chooser = new JFileChooser();
        if (gifFile != null)
            chooser.setSelectedFile(gifFile);
        chooser.setAcceptAllFileFilterUsed(false);
        chooser.setFileFilter(new FileFilter() {

            public boolean accept(File f) {
                if (f.isDirectory())
                    return true;
                return f.getName().toLowerCase().endsWith(".gif");
            }

            public String getDescription() {
                return "GIF (*.gif)";
            }
        });

        File f = null;
        if (chooser.showSaveDialog(this) == JFileChooser.APPROVE_OPTION) {
            f = chooser.getSelectedFile();
            if (f != null) {
                if (!f.getName().toLowerCase().endsWith(".gif")) {
                    f = new File(f.getAbsolutePath() + ".gif");
                }
                gifFile = f;
                gifFileLbl.setText(gifFile.getName());
            }
        }
        if (f == null && gifFile == null) {
            gifFileBtn.setSelected(false);
        }
    }

    private void start() {
        animator = new MultiPlotAnimator();
        Object[] objs = plotList.getCheckBoxListSelectedValues();
        File file = null;
        if (gifChk.isSelected() && gifFile != null)
            file = gifFile;

        for (Object obj : objs) {
            PlotData data = (PlotData) obj;
            Axes<DataFrameAxis> axes = data.getPlot().getData().get(0).getAxes();
            int val = ((Integer) startSpinner.getValue()).intValue();
            int val2 = ((Integer) endSpinner.getValue()).intValue();
            int startIndex = Math.min(val, val2);
            int endIndex = Math.max(val, val2);
            int start = axes.getTimeStep(dateModel.getDate(startIndex));
            int end = axes.getTimeStep(dateModel.getDate(endIndex));
            animator.addPlotToAnimate((TimeAnimatablePlot) data.getPlot(), start, end, gifFile);
        }
        animator.addAnimationListener(this);
        startButton.setText("Stop");
        animator.start();
    }

    public void animationStopped() {
        startButton.setText("Start");
    }

    private void setSpinners() {
        if (currentRange == null) {
            startLbl.setText("");
            endLbl.setText("");
            startSpinner.setValue(0);
            startSpinner.setEnabled(false);
            startLbl.setEnabled(false);
            endSpinner.setEnabled(false);
            endSpinner.setValue(0);
            endLbl.setEnabled(false);
        } else {
            long start = currentRange.getStart();
            long end = currentRange.getEnd();
            boolean changed = dateModel.init(start, end, (end - start) / currentSteps);
            if (changed) {
                ((SpinnerNumberModel) startSpinner.getModel()).setMinimum(0);
                ((SpinnerNumberModel) startSpinner.getModel()).setMaximum(currentSteps);
                ((SpinnerNumberModel) endSpinner.getModel()).setMaximum(0);
                ((SpinnerNumberModel) endSpinner.getModel()).setMaximum(currentSteps);
                startSpinner.setValue(0);
                endSpinner.setValue(currentSteps);
                startLbl.setText(Utilities.formatShortDate(dateModel.getDate(0)));
                endLbl.setText(Utilities.formatShortDate(dateModel.getDate(currentSteps)));
            }
        }
    }

    public void init(JButton startButton, java.util.List<Plot> plots) {
        this.startButton = startButton;

        this.startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent evt) {
                if (MultiPlotAnimation.this.startButton.getText().equals("Start")) {
                    start();
                } else {
                    if (animator != null)
                        animator.stop();
                    MultiPlotAnimation.this.startButton.setText("Start");
                }
            }
        });

        this.startButton.setEnabled(false);
        startSpinner.setEnabled(false);
        startLbl.setEnabled(false);
        endSpinner.setEnabled(false);
        endLbl.setEnabled(false);

        Collections.sort(plots, new Comparator<Plot>() {
            public int compare(Plot o1, Plot o2) { // 2014 added in .tlLowerCase() to remove case-sensitivity
                return o1.getData().get(0).getVariable().getName().toLowerCase()
                        .compareTo(o2.getData().get(0).getVariable().getName().toLowerCase());
            }
        });
        DefaultListModel model = new DefaultListModel();
        plotList.setModel(model);
        for (Plot plot : plots) {
            model.addElement(new PlotData(plot));
        }
    }

    private void initComponents() {
        // JFormDesigner - Component initialization - DO NOT MODIFY  //GEN-BEGIN:initComponents
        // Generated using JFormDesigner non-commercial license
        DefaultComponentFactory compFactory = DefaultComponentFactory.getInstance();
        separator1 = compFactory.createSeparator("Select Plots");
        scrollPane1 = new JScrollPane();
        plotList = new CheckBoxList();
        panel1 = new JPanel();
        label1 = new JLabel();
        startSpinner = new JSpinner();
        startLbl = new JLabel();
        label2 = new JLabel();
        endSpinner = new JSpinner();
        endLbl = new JLabel();
        panel2 = new JPanel();
        gifChk = new JCheckBox();
        gifFileLbl = new JLabel();
        gifFileBtn = new JButton();
        separator2 = compFactory.createSeparator("");
        CellConstraints cc = new CellConstraints();

        //======== this ========
        // 2014
        ColumnSpec[] aColumnSpec = ColumnSpec.decodeSpecs("default:grow");
        RowSpec aRowSpec = new RowSpec(RowSpec.TOP, Sizes.dluY(84), 0.5);
        RowSpec bRowSpec = new RowSpec(RowSpec.FILL, Sizes.PREFERRED, 0.5);
        setLayout(new FormLayout(aColumnSpec,
                new RowSpec[] { FormFactory.DEFAULT_ROWSPEC, FormFactory.RELATED_GAP_ROWSPEC, aRowSpec,
                        FormFactory.RELATED_GAP_ROWSPEC, bRowSpec, FormFactory.RELATED_GAP_ROWSPEC,
                        FormFactory.DEFAULT_ROWSPEC, FormFactory.LINE_GAP_ROWSPEC, FormFactory.DEFAULT_ROWSPEC }));
        //      setLayout(new FormLayout(
        //            ColumnSpec.decodeSpecs("default:grow"),
        //            new RowSpec[] {
        //               FormFactory.DEFAULT_ROWSPEC,
        //               FormFactory.RELATED_GAP_ROWSPEC,
        //               new RowSpec(RowSpec.TOP, Sizes.dluY(84), 0.5),
        //               FormFactory.RELATED_GAP_ROWSPEC,
        //               new RowSpec(RowSpec.FILL, Sizes.PREFERRED, 0.5),
        //               FormFactory.RELATED_GAP_ROWSPEC,
        //               FormFactory.DEFAULT_ROWSPEC,
        //               FormFactory.LINE_GAP_ROWSPEC,
        //               FormFactory.DEFAULT_ROWSPEC
        //            }));
        add(separator1, cc.xy(1, 1));

        //======== scrollPane1 ========
        {
            scrollPane1.setViewportView(plotList);
        }
        add(scrollPane1, cc.xy(1, 3));

        //======== panel1 ========
        {
            // 2014
            ColumnSpec[] dColumnSpec = ColumnSpec.decodeSpecs("max(pref;40dlu)");
            ColumnSpec[] eColumnSpec = ColumnSpec.decodeSpecs("max(pref;40dlu):grow");
            panel1.setLayout(new FormLayout(
                    new ColumnSpec[] { new ColumnSpec(Sizes.dluX(71)), FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
                            dColumnSpec[0], FormFactory.UNRELATED_GAP_COLSPEC, eColumnSpec[0] },
                    new RowSpec[] { FormFactory.DEFAULT_ROWSPEC, FormFactory.LINE_GAP_ROWSPEC,
                            FormFactory.DEFAULT_ROWSPEC }));
            //         panel1.setLayout(new FormLayout(
            //               new ColumnSpec[] {
            //                  new ColumnSpec(Sizes.dluX(71)),
            //                  FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            //                  new ColumnSpec("max(pref;40dlu)"),
            //                  FormFactory.UNRELATED_GAP_COLSPEC,
            //                  new ColumnSpec("max(pref;40dlu):grow")
            //               },
            //               new RowSpec[] {
            //                  FormFactory.DEFAULT_ROWSPEC,
            //                  FormFactory.LINE_GAP_ROWSPEC,
            //                  FormFactory.DEFAULT_ROWSPEC
            //               }));

            //---- label1 ----
            label1.setText("Starting Time Step:");
            panel1.add(label1, cc.xy(1, 1));
            panel1.add(startSpinner, cc.xy(3, 1));

            //---- startLbl ----
            startLbl.setFont(new Font("Tahoma", Font.BOLD, 11));
            panel1.add(startLbl, cc.xy(5, 1));

            //---- label2 ----
            label2.setText("Ending Time Step:");
            panel1.add(label2, cc.xy(1, 3));
            panel1.add(endSpinner, cc.xy(3, 3));

            //---- endLbl ----
            endLbl.setFont(new Font("Tahoma", Font.BOLD, 11));
            panel1.add(endLbl, cc.xy(5, 3));
        }
        add(panel1, cc.xywh(1, 5, 1, 1, CellConstraints.DEFAULT, CellConstraints.TOP));

        //======== panel2 ========
        {
            // 2014
            ColumnSpec fColumnSpec = new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW);
            RowSpec[] fRowSpec = RowSpec.decodeSpecs("default");
            panel2.setLayout(new FormLayout(
                    new ColumnSpec[] { FormFactory.DEFAULT_COLSPEC, FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
                            fColumnSpec, FormFactory.LABEL_COMPONENT_GAP_COLSPEC, FormFactory.DEFAULT_COLSPEC },
                    fRowSpec));
            //         panel2.setLayout(new FormLayout(
            //               new ColumnSpec[] {
            //                  FormFactory.DEFAULT_COLSPEC,
            //                  FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            //                  new ColumnSpec(ColumnSpec.FILL, Sizes.DEFAULT, FormSpec.DEFAULT_GROW),
            //                  FormFactory.LABEL_COMPONENT_GAP_COLSPEC,
            //                  FormFactory.DEFAULT_COLSPEC
            //               },
            //               RowSpec.decodeSpecs("default")));

            //---- gifChk ----
            gifChk.setText("Make Animated GIF(s)");
            panel2.add(gifChk, cc.xy(1, 1));
            panel2.add(gifFileLbl, cc.xy(3, 1));

            //---- gifFileBtn ----
            gifFileBtn.setText("...");
            gifFileBtn.setMaximumSize(new Dimension(23, 23));
            gifFileBtn.setMinimumSize(new Dimension(23, 23));
            gifFileBtn.setPreferredSize(new Dimension(23, 23));
            gifFileBtn.setEnabled(false);
            panel2.add(gifFileBtn, cc.xy(5, 1));
        }
        add(panel2, cc.xy(1, 7));
        add(separator2, cc.xy(1, 9));
        // JFormDesigner - End of component initialization  //GEN-END:initComponents
    }

    // JFormDesigner - Variables declaration - DO NOT MODIFY  //GEN-BEGIN:variables
    // Generated using JFormDesigner non-commercial license
    private JComponent separator1;
    private JScrollPane scrollPane1;
    private CheckBoxList plotList;
    private JPanel panel1;
    private JLabel label1;
    private JSpinner startSpinner;
    private JLabel startLbl;
    private JLabel label2;
    private JSpinner endSpinner;
    private JLabel endLbl;
    private JPanel panel2;
    private JCheckBox gifChk;
    private JLabel gifFileLbl;
    private JButton gifFileBtn;
    private JComponent separator2;
    // JFormDesigner - End of variables declaration  //GEN-END:variables
}