SiLeBAT/FSK-Lab

View on GitHub
de.bund.bfr.knime.pmm.common/src/de/bund/bfr/knime/pmm/common/chart/ChartSamplePanel.java

Summary

Maintainability
D
2 days
Test Coverage
/*******************************************************************************
 * Copyright (c) 2015 Federal Institute for Risk Assessment (BfR), Germany
 *
 * 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/>.
 *
 * Contributors:
 *     Department Biological Safety - BfR
 *******************************************************************************/
package de.bund.bfr.knime.pmm.common.chart;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridLayout;
import java.awt.TextArea;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ScrollPaneConstants;
import javax.swing.SwingUtilities;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;

import de.bund.bfr.knime.pmm.common.ui.DoubleTextField;
import de.bund.bfr.knime.pmm.common.ui.IntTextField;
import de.bund.bfr.knime.pmm.common.ui.TextListener;
import de.bund.bfr.knime.pmm.common.ui.TimeSeriesTable;
import de.bund.bfr.knime.pmm.common.ui.UI;

public class ChartSamplePanel extends JPanel implements ActionListener,
        CellEditorListener {

    private static final long serialVersionUID = 1L;

    private static final int ROW_COUNT = 100;
    private static final int DEFAULT_TIMESTEPCOUNT = 10;
    private static final double DEFAULT_TIMESTEPSIZE = 10.0;

    private JScrollPane tablePane;
    private TimeSeriesTable table;
    private TextArea warningArea;
    private JButton clearButton;
    private JButton stepsButton;
    private JCheckBox inverseButton;

    private List<EditListener> listeners;

    public ChartSamplePanel() {
        listeners = new ArrayList<>();

        table = new TimeSeriesTable(ROW_COUNT, 1, true, false);
        table.getTimeColumn().getCellEditor().addCellEditorListener(this);
        tablePane = new JScrollPane(table,
                ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
        warningArea = new TextArea(3, 10);
        warningArea.setEditable(false);
        stepsButton = new JButton("Set equidistant steps");
        stepsButton.addActionListener(this);
        clearButton = new JButton("Clear");
        clearButton.addActionListener(this);
        inverseButton = new JCheckBox("Inverse");
        inverseButton.addActionListener(this);

        JPanel buttonPanel = new JPanel();

        buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
        buttonPanel.add(stepsButton);
        buttonPanel.add(clearButton);
        buttonPanel.add(inverseButton);

        JPanel buttomPanel = new JPanel();

        buttomPanel.setLayout(new BorderLayout());
        buttomPanel.add(warningArea, BorderLayout.CENTER);
        buttomPanel.add(buttonPanel, BorderLayout.SOUTH);

        setLayout(new BorderLayout());
        add(tablePane, BorderLayout.CENTER);
        add(buttomPanel, BorderLayout.SOUTH);
    }

    public void setWarnings(List<String> warnings) {
        String s = "";

        for (String w : warnings) {
            s += w + "\n";
        }

        if (!s.isEmpty()) {
            s = s.substring(0, s.length() - 1);
        }

        warningArea.setText(s);

        if (warnings.isEmpty()) {
            warningArea.setBackground(Color.WHITE);
        } else {
            warningArea.setBackground(Color.YELLOW);
        }
    }

    public TimeSeriesTable getTimeSeriesTable() {
        return table;
    }

    public void addEditListener(EditListener listener) {
        listeners.add(listener);
    }

    public void removeEditListener(EditListener listener) {
        listeners.remove(listener);
    }

    public boolean isInverse() {
        return inverseButton.isSelected();
    }

    public void setInverse(boolean inverse) {
        inverseButton.setSelected(inverse);
    }

    public List<Double> getTimeValues() {
        List<Double> timeValues = new ArrayList<>();

        for (int i = 0; i < ROW_COUNT; i++) {
            timeValues.add(table.getTime(i));
        }

        return timeValues;
    }

    public void setTimeValues(List<Double> timeValues) {
        for (int i = 0; i < ROW_COUNT; i++) {
            if (i >= timeValues.size()) {
                table.setTime(i, null);
            } else {
                table.setTime(i, timeValues.get(i));
            }
        }
    }

    public void setSampleName(String name) {
        table.setTimeColumnName(name);
    }

    public void setDataPoints(Map<String, double[][]> points) {
        String timeColumnName = table.getTimeColumnName();
        List<Double> timeValues = getTimeValues();

        Map<String, Map<Double, Double>> cValues = new LinkedHashMap<>();

        for (String id : points.keySet()) {
            Map<Double, Double> values = new LinkedHashMap<>();
            double[][] ps = points.get(id);

            if (ps != null && ps.length == 2) {
                for (int i = 0; i < ps[0].length; i++) {
                    if (!Double.isNaN(ps[0][i]) && !Double.isNaN(ps[1][i])) {
                        values.put(ps[0][i], ps[1][i]);
                    }
                }
            }

            cValues.put(id, values);
        }

        if (table.getCColumns().size() != cValues.size()) {
            remove(tablePane);
            table = new TimeSeriesTable(ROW_COUNT, cValues.size(), true, false);
            table.getTimeColumn().getCellEditor().addCellEditorListener(this);
            tablePane = new JScrollPane(table,
                    ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
                    ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
            add(tablePane, BorderLayout.CENTER);
            revalidate();
            table.setTimeColumnName(timeColumnName);
            setTimeValues(timeValues);
        }

        int count = 0;

        for (String id : cValues.keySet()) {
            table.setCColumnName(count, id);

            for (int i = 0; i < ROW_COUNT; i++) {
                Double logc = cValues.get(id).get(table.getTime(i));

                if (logc != null) {
                    table.setLogc(i, count, logc);
                } else {
                    table.setLogc(i, count, null);
                }
            }

            count++;
        }

        table.repaint();
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == clearButton) {
            for (int i = 0; i < ROW_COUNT; i++) {
                table.setTime(i, null);
                table.setLogc(i, null);
            }

            table.repaint();
            fireTimeValuesChanged();
        } else if (e.getSource() == stepsButton) {
            TimeStepDialog dialog = new TimeStepDialog(this);

            dialog.setVisible(true);

            if (dialog.isApproved()) {
                int stepNumber = dialog.getNumberOfSteps();
                double stepSize = dialog.getStepSize();

                for (int i = 0; i < ROW_COUNT; i++) {
                    Double time = null;

                    if (i < stepNumber) {
                        time = i * stepSize;
                    }

                    table.setTime(i, time);
                    table.setLogc(i, null);
                }

                table.repaint();
                fireTimeValuesChanged();
            }
        } else if (e.getSource() == inverseButton) {
            fireTimeValuesChanged();
        }
    }

    @Override
    public void editingStopped(ChangeEvent e) {
        fireTimeValuesChanged();
    }

    @Override
    public void editingCanceled(ChangeEvent e) {
    }

    public void fireTimeValuesChanged() {
        for (EditListener listener : listeners) {
            listener.timeValuesChanged();
        }
    }

    public static interface EditListener {

        public void timeValuesChanged();

    }

    private class TimeStepDialog extends JDialog implements ActionListener,
            TextListener {

        private static final long serialVersionUID = 1L;

        private boolean approved;
        private int numberOfSteps;
        private double stepSize;

        private IntTextField numberField;
        private DoubleTextField sizeField;

        private JButton okButton;
        private JButton cancelButton;

        public TimeStepDialog(Component owner) {
            super(SwingUtilities.getWindowAncestor(owner), "Steps",
                    DEFAULT_MODALITY_TYPE);

            approved = false;
            numberOfSteps = 0;
            stepSize = 0.0;

            numberField = new IntTextField(1, ROW_COUNT);
            numberField.setValue(DEFAULT_TIMESTEPCOUNT);
            numberField.setPreferredSize(new Dimension(150, numberField
                    .getPreferredSize().height));
            numberField.addTextListener(this);
            sizeField = new DoubleTextField(0.0, Double.POSITIVE_INFINITY);
            sizeField.setPreferredSize(new Dimension(150, sizeField
                    .getPreferredSize().height));
            sizeField.setValue(DEFAULT_TIMESTEPSIZE);
            sizeField.addTextListener(this);
            okButton = new JButton("OK");
            okButton.addActionListener(this);
            cancelButton = new JButton("Cancel");
            cancelButton.addActionListener(this);

            JPanel centerPanel = new JPanel();
            JPanel leftPanel = new JPanel();
            JPanel rightPanel = new JPanel();
            JPanel bottomPanel = new JPanel();

            leftPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            leftPanel.setLayout(new GridLayout(2, 1, 5, 5));
            leftPanel.add(new JLabel("Number of Steps:"));
            leftPanel.add(new JLabel("Step Size:"));

            rightPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            rightPanel.setLayout(new GridLayout(2, 1, 5, 5));
            rightPanel.add(numberField);
            rightPanel.add(sizeField);

            centerPanel.setLayout(new BorderLayout());
            centerPanel.add(leftPanel, BorderLayout.WEST);
            centerPanel.add(rightPanel, BorderLayout.CENTER);

            bottomPanel.setLayout(new FlowLayout(FlowLayout.CENTER));
            bottomPanel.add(okButton);
            bottomPanel.add(cancelButton);

            setLayout(new BorderLayout());
            add(centerPanel, BorderLayout.CENTER);
            add(bottomPanel, BorderLayout.SOUTH);
            pack();

            setResizable(false);
            setLocationRelativeTo(owner);
            UI.adjustDialog(this);
        }

        public boolean isApproved() {
            return approved;
        }

        public int getNumberOfSteps() {
            return numberOfSteps;
        }

        public double getStepSize() {
            return stepSize;
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource() == okButton) {
                approved = true;
                numberOfSteps = numberField.getValue();
                stepSize = sizeField.getValue();
                dispose();
            } else if (e.getSource() == cancelButton) {
                dispose();
            }
        }

        @Override
        public void textChanged(Object source) {
            if (numberField.isValueValid() && sizeField.isValueValid()) {
                okButton.setEnabled(true);
            } else {
                okButton.setEnabled(false);
            }
        }
    }

}