com.rapidminer.gui.new_plotter.gui.dialog.AddParallelLineDialog.java Source code

Java tutorial

Introduction

Here is the source code for com.rapidminer.gui.new_plotter.gui.dialog.AddParallelLineDialog.java

Source

/**
 * Copyright (C) 2001-2015 by RapidMiner and the contributors
 *
 * Complete list of developers available at our web site:
 *
 *      http://rapidminer.com
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero 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 Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 */
package com.rapidminer.gui.new_plotter.gui.dialog;

import com.rapidminer.gui.new_plotter.configuration.AxisParallelLineConfiguration;
import com.rapidminer.gui.new_plotter.configuration.LineFormat.LineStyle;
import com.rapidminer.gui.new_plotter.configuration.PlotConfiguration;
import com.rapidminer.gui.new_plotter.configuration.RangeAxisConfig;
import com.rapidminer.gui.new_plotter.engine.jfreechart.JFreeChartPlotEngine;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.tools.I18N;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.geom.Rectangle2D;
import java.util.Vector;

import javax.swing.ButtonGroup;
import javax.swing.DefaultComboBoxModel;
import javax.swing.InputVerifier;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.JSeparator;
import javax.swing.JTextField;
import javax.swing.WindowConstants;

import org.jfree.chart.axis.ValueAxis;
import org.jfree.chart.plot.XYPlot;

/**
 * This dialog allows the user to configure the addition of a crosshair line in the new charts.
 * 
 * @author Marco Boeck
 * 
 */
public class AddParallelLineDialog extends JDialog {

    /** the ok {@link JButton} */
    private JButton okButton;

    /** the cancel {@link JButton} */
    private JButton cancelButton;

    /** the {@link JTextField} for the x value */
    private JTextField xField;

    /** the {@link JTextField} for the y value */
    private JTextField yField;

    /** the x value the user specified */
    private double x;

    /** the y value the user specified */
    private double y;

    /** if selected, the line will be horizontal */
    private JRadioButton horizontalLineRadiobutton;

    /** if selected, the line will be vertical */
    private JRadioButton verticalLineRadiobutton;

    /**
     * the {@link JComboBox} where the {@link RangeAxisConfig} will be selected if horizontal line
     * is selected
     */
    private JComboBox rangeAxisSelectionCombobox;

    /** this button modifies the line */
    private JButton modifyLineButton;

    /** the current {@link JFreeChartPlotEngine} */
    private JFreeChartPlotEngine engine;

    /** the current {@link PlotConfiguration} */
    private PlotConfiguration plotConfig;

    /** the position of the mouse, determines preselected x/y values */
    private Point mousePosition;

    /** the {@link EditParallelLineDialog} instance */
    private EditParallelLineDialog dialog;

    /** the current line to add */
    private AxisParallelLineConfiguration line;

    private static final long serialVersionUID = 1932257219370926682L;

    /**
     * Creates a new {@link AddParallelLineDialog}.
     */
    public AddParallelLineDialog() {
        x = 1.0;
        y = 1.0;

        setupGUI();
    }

    /**
     * Setup the GUI.
     */
    private void setupGUI() {
        JPanel mainPanel = new JPanel();
        this.setContentPane(mainPanel);

        // start layout
        mainPanel.setLayout(new GridBagLayout());
        GridBagConstraints gbc = new GridBagConstraints();

        gbc.gridx = 0;
        gbc.gridy = 0;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 2, 5);
        horizontalLineRadiobutton = new JRadioButton(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.horizontal.label"));
        horizontalLineRadiobutton.setToolTipText(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.horizontal.tip"));
        horizontalLineRadiobutton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                setHorizontalLineSelected();
            }
        });
        horizontalLineRadiobutton.setSelected(true);
        this.add(horizontalLineRadiobutton, gbc);

        gbc.gridx = 1;
        gbc.gridy = 0;
        gbc.anchor = GridBagConstraints.EAST;
        verticalLineRadiobutton = new JRadioButton(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.vertical.label"));
        verticalLineRadiobutton
                .setToolTipText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.vertical.tip"));
        verticalLineRadiobutton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                setVerticalLineSelected();
            }
        });
        this.add(verticalLineRadiobutton, gbc);

        ButtonGroup group = new ButtonGroup();
        group.add(horizontalLineRadiobutton);
        group.add(verticalLineRadiobutton);

        gbc.gridx = 0;
        gbc.gridy = 1;
        gbc.fill = GridBagConstraints.BOTH;
        gbc.weightx = 1;
        gbc.gridwidth = 2;
        gbc.anchor = GridBagConstraints.CENTER;
        rangeAxisSelectionCombobox = new JComboBox();
        rangeAxisSelectionCombobox.setToolTipText(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.range_axis_combobox.tip"));
        rangeAxisSelectionCombobox.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                updateYFieldValue();
            }
        });
        this.add(rangeAxisSelectionCombobox, gbc);

        gbc.gridx = 0;
        gbc.gridy = 2;
        gbc.fill = GridBagConstraints.NONE;
        gbc.weightx = 1;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 2, 5);
        JLabel xLabel = new JLabel(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.width.label"));
        this.add(xLabel, gbc);

        gbc.gridx = 1;
        gbc.gridy = 2;
        gbc.insets = new Insets(2, 5, 2, 5);
        gbc.fill = GridBagConstraints.HORIZONTAL;
        xField = new JTextField();
        xField.setText(String.valueOf(x));
        xField.setInputVerifier(new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                return verifyYInput(input);
            }
        });
        xField.setToolTipText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.width.tip"));
        xField.setEnabled(false);
        this.add(xField, gbc);

        gbc.gridx = 0;
        gbc.gridy = 3;
        gbc.fill = GridBagConstraints.NONE;
        JLabel yLabel = new JLabel(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.height.label"));
        this.add(yLabel, gbc);

        gbc.gridx = 1;
        gbc.gridy = 3;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        yField = new JTextField();
        yField.setToolTipText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.height.tip"));
        yField.setText(String.valueOf(y));
        yField.setInputVerifier(new InputVerifier() {

            @Override
            public boolean verify(JComponent input) {
                return verifyXInput(input);
            }
        });
        this.add(yField, gbc);

        gbc.gridx = 0;
        gbc.gridy = 4;
        gbc.fill = GridBagConstraints.NONE;
        gbc.insets = new Insets(10, 5, 0, 5);
        modifyLineButton = new JButton();
        modifyLineButton.setToolTipText(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.modify_line.tip"));
        modifyLineButton.setIcon(SwingTools.createIcon(
                "16/" + I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.modify_line.icon")));
        modifyLineButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                modifyLine();
            }
        });
        this.add(modifyLineButton, gbc);

        gbc.gridx = 0;
        gbc.gridy = 5;
        gbc.gridwidth = 2;
        gbc.fill = GridBagConstraints.HORIZONTAL;
        gbc.anchor = GridBagConstraints.CENTER;
        gbc.insets = new Insets(15, 5, 5, 5);
        this.add(new JSeparator(), gbc);

        gbc.gridx = 0;
        gbc.gridy = 6;
        gbc.gridwidth = 1;
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.WEST;
        gbc.insets = new Insets(5, 5, 5, 5);
        okButton = new JButton(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.ok.label"));
        okButton.setToolTipText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.ok.tip"));
        okButton.setIcon(SwingTools
                .createIcon("24/" + I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.ok.icon")));
        okButton.setMnemonic(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.ok.mne").toCharArray()[0]);
        okButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                boolean successful = addSpecifiedLine();
                // don't dispose dialog if not successful
                if (!successful) {
                    return;
                }

                AddParallelLineDialog.this.dispose();
            }
        });
        okButton.addKeyListener(new KeyAdapter() {

            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_ENTER) {
                    okButton.doClick();
                }
            }
        });
        this.add(okButton, gbc);

        gbc.gridx = 1;
        gbc.gridy = 6;
        gbc.fill = GridBagConstraints.NONE;
        gbc.anchor = GridBagConstraints.EAST;
        cancelButton = new JButton(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.cancel.label"));
        cancelButton
                .setToolTipText(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.cancel.tip"));
        cancelButton.setIcon(SwingTools.createIcon(
                "24/" + I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.cancel.icon")));
        cancelButton.setMnemonic(
                I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.cancel.mne").toCharArray()[0]);
        cancelButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // cancel requested, close dialog
                AddParallelLineDialog.this.dispose();
            }
        });
        this.add(cancelButton, gbc);

        // misc settings
        this.setMinimumSize(new Dimension(300, 250));
        // center dialog
        this.setLocationRelativeTo(null);
        this.setTitle(I18N.getMessage(I18N.getGUIBundle(), "gui.action.add_parallel_line.title.label"));
        this.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
        this.setModal(true);

        this.addWindowListener(new WindowAdapter() {

            @Override
            public void windowActivated(WindowEvent e) {
                okButton.requestFocusInWindow();
            }
        });
    }

    /**
     * Sets the mouse position (defines preselected x/y values).
     * 
     * @param mousePosition
     */
    public void setMousePosition(Point mousePosition) {
        if (mousePosition == null) {
            throw new IllegalArgumentException("mousePosition must not be null!");
        }

        this.mousePosition = mousePosition;
    }

    /**
     * Sets the current {@link JFreeChartPlotEngine} for this dialog.
     * 
     * @param engine
     */
    public void setChartEngine(JFreeChartPlotEngine engine) {
        if (engine == null) {
            throw new IllegalArgumentException("engine must not be null!");
        }

        this.engine = engine;
        setPlotConfiguration(engine.getPlotInstance().getMasterPlotConfiguration());
    }

    /**
     * Shows the dialog.
     */
    public void showDialog() {
        if (line == null) {
            line = createLine(1.0);
        } else {
            line = line.clone();
        }
        if (horizontalLineRadiobutton.isSelected()) {
            line.setValue(Double.parseDouble(yField.getText()));
        } else {
            line.setValue(Double.parseDouble(xField.getText()));
        }
        setVisible(true);
    }

    /**
     * Sets the current {@link PlotConfiguration} for this dialog.
     * 
     * @param plotConfig
     */
    private void setPlotConfiguration(PlotConfiguration plotConfig) {
        if (plotConfig == null) {
            throw new IllegalArgumentException("plotConfig must not be null!");
        }

        this.plotConfig = plotConfig;
        Vector<RangeAxisConfig> rangeConfigsVector = new Vector<RangeAxisConfig>();
        String selectedItem = String.valueOf(rangeAxisSelectionCombobox.getSelectedItem());
        for (RangeAxisConfig config : this.plotConfig.getRangeAxisConfigs()) {
            rangeConfigsVector.add(config);
        }
        rangeAxisSelectionCombobox.setModel(new DefaultComboBoxModel(rangeConfigsVector));

        // reselect the previously selected RangeAxisConfig (if it is still there)
        if (selectedItem != null) {
            for (int i = 0; i < rangeAxisSelectionCombobox.getItemCount(); i++) {
                if (String.valueOf(rangeAxisSelectionCombobox.getItemAt(i)).equals(selectedItem)) {
                    rangeAxisSelectionCombobox.setSelectedIndex(i);
                    break;
                }
            }
        }

        // calculate preselected x/y values
        if (mousePosition != null) {
            Rectangle2D plotArea = engine.getChartPanel().getScreenDataArea();
            if (engine.getChartPanel().getChart().getPlot() instanceof XYPlot) {
                XYPlot plot = (XYPlot) engine.getChartPanel().getChart().getPlot();

                // calculate x value
                double chartX = plot.getDomainAxis().java2DToValue(mousePosition.getX(), plotArea,
                        plot.getDomainAxisEdge());
                xField.setText(String.valueOf(chartX));

                // calculate y value
                for (int i = 0; i < plot.getRangeAxisCount(); i++) {
                    ValueAxis config = plot.getRangeAxis(i);
                    if (config != null && config.getLabel() != null) {
                        if (config.getLabel()
                                .equals(String.valueOf(rangeAxisSelectionCombobox.getSelectedItem()))) {
                            double chartY = config.java2DToValue(mousePosition.getY(), plotArea,
                                    plot.getRangeAxisEdge());
                            yField.setText(String.valueOf(chartY));
                        }
                    }
                }
            }
        }
    }

    /**
     * Horizontal line selected.
     */
    private void setHorizontalLineSelected() {
        // horizontal line, so only y-value and rangeAxis is of interest, disable other fields
        rangeAxisSelectionCombobox.setEnabled(true);
        xField.setEnabled(false);
        yField.setEnabled(true);
        okButton.requestFocusInWindow();
    }

    /**
     * Vertical line selected.
     */
    private void setVerticalLineSelected() {
        // vertical line, so only x-value is of interest, disable other fields
        rangeAxisSelectionCombobox.setEnabled(false);
        xField.setEnabled(true);
        yField.setEnabled(false);
        okButton.requestFocusInWindow();
    }

    /**
     * Updates the preselected y-value.
     */
    private void updateYFieldValue() {
        // update preselected y value because range axis has been changed
        if (mousePosition != null) {
            Rectangle2D plotArea = engine.getChartPanel().getScreenDataArea();
            if (engine.getChartPanel().getChart().getPlot() instanceof XYPlot) {
                XYPlot plot = (XYPlot) engine.getChartPanel().getChart().getPlot();

                // calculate y value
                for (int i = 0; i < plot.getRangeAxisCount(); i++) {
                    ValueAxis config = plot.getRangeAxis(i);
                    if (config != null && config.getLabel() != null) {
                        if (config.getLabel()
                                .equals(String.valueOf(rangeAxisSelectionCombobox.getSelectedItem()))) {
                            double chartY = config.java2DToValue(mousePosition.getY(), plotArea,
                                    plot.getRangeAxisEdge());
                            yField.setText(String.valueOf(chartY));
                        }
                    }
                }
            }
        }
    }

    /**
     * Verify that the y-value is correct.
     * 
     * @param input
     * @return true if the value is valid; false otherwise
     */
    private boolean verifyYInput(JComponent input) {
        JTextField textField = (JTextField) input;
        String inputString = textField.getText();
        try {
            Double.parseDouble(inputString);
        } catch (NumberFormatException e) {
            textField.setForeground(Color.RED);
            return false;
        }

        textField.setForeground(Color.BLACK);
        return true;
    }

    /**
     * Verify that the x-value is correct.
     * 
     * @param input
     * @return true if the value is valid; false otherwise
     */
    private boolean verifyXInput(JComponent input) {
        JTextField textField = (JTextField) input;
        String inputString = textField.getText();
        try {
            Double.parseDouble(inputString);
        } catch (NumberFormatException e) {
            textField.setForeground(Color.RED);
            return false;
        }

        textField.setForeground(Color.BLACK);
        return true;
    }

    /**
     * Creates the specified line.
     * 
     * @return true if the line has been created; false otherwise
     */
    private boolean addSpecifiedLine() {
        if (horizontalLineRadiobutton.isSelected()) {
            Object selectedItem = rangeAxisSelectionCombobox.getSelectedItem();
            if (selectedItem != null && selectedItem instanceof RangeAxisConfig) {
                // make sure y value is valid, otherwise don't do anything!
                if (!yField.getInputVerifier().verify(yField)) {
                    yField.requestFocusInWindow();
                    return false;
                }
                RangeAxisConfig config = (RangeAxisConfig) selectedItem;
                if (line == null) {
                    line = createLine(Double.parseDouble(yField.getText()));
                }
                line.setValue(Double.parseDouble(yField.getText()));
                config.getCrossHairLines().addLine(line);
            }
        } else if (verticalLineRadiobutton.isSelected()) {
            // make sure x value is valid, otherwise don't do anything!
            if (!xField.getInputVerifier().verify(xField)) {
                xField.requestFocusInWindow();
                return false;
            }
            if (line == null) {
                line = createLine(Double.parseDouble(xField.getText()));
            }
            line.setValue(Double.parseDouble(xField.getText()));
            plotConfig.getDomainConfigManager().getCrosshairLines().addLine(line);
        }

        return true;
    }

    /**
     * Modifes the line.
     */
    private void modifyLine() {
        if (line == null) {
            line = createLine(1.0);
        }
        if (dialog == null) {
            dialog = new EditParallelLineDialog();
        }

        if (horizontalLineRadiobutton.isSelected()) {
            // make sure y value is valid, otherwise don't do anything!
            if (!yField.getInputVerifier().verify(yField)) {
                yField.requestFocusInWindow();
                return;
            }
            line.setValue(Double.parseDouble(yField.getText()));
        } else {
            // make sure x value is valid, otherwise don't do anything!
            if (!xField.getInputVerifier().verify(xField)) {
                xField.requestFocusInWindow();
                return;
            }
            line.setValue(Double.parseDouble(xField.getText()));
        }
        dialog.setLine(line, false);
        dialog.showDialog();
    }

    /**
     * Creates a new {@link AxisParallelLineConfiguration} with solid {@link LineStyle}.
     * 
     * @param value
     * @return
     */
    private AxisParallelLineConfiguration createLine(double value) {
        AxisParallelLineConfiguration line = new AxisParallelLineConfiguration(value, false);
        line.getFormat().setStyle(LineStyle.SOLID);
        return line;
    }
}