/**
* Copyright (C) 2001-2017 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;
import com.rapidminer.datatable.DataTable;
import com.rapidminer.gui.new_plotter.ChartConfigurationException;
import com.rapidminer.gui.new_plotter.PlotConfigurationError;
import com.rapidminer.gui.new_plotter.configuration.DataTableColumn.ValueType;
import com.rapidminer.gui.new_plotter.configuration.DimensionConfig;
import com.rapidminer.gui.new_plotter.configuration.DimensionConfig.PlotDimension;
import com.rapidminer.gui.new_plotter.configuration.DomainConfigManager;
import com.rapidminer.gui.new_plotter.configuration.DomainConfigManager.Sorting;
import com.rapidminer.gui.new_plotter.configuration.ValueGrouping;
import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.GroupingType;
import com.rapidminer.gui.new_plotter.configuration.ValueGrouping.ValueGroupingFactory;
import com.rapidminer.gui.new_plotter.data.PlotInstance;
import com.rapidminer.gui.new_plotter.gui.cellrenderer.EnumComboBoxCellRenderer;
import com.rapidminer.gui.new_plotter.gui.popup.PopupAction;
import com.rapidminer.gui.new_plotter.listener.events.PlotConfigurationChangeEvent;
import com.rapidminer.gui.tools.ResourceLabel;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.tools.I18N;
import java.awt.Dimension;
import java.awt.GridBagConstraints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Objects;
import java.util.Vector;
import javax.swing.AbstractButton;
import javax.swing.DefaultComboBoxModel;
import javax.swing.JCheckBox;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.JToggleButton;
import javax.swing.JTree;
import javax.swing.SpinnerNumberModel;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
/**
* @author Nils Woehler
*
*/
public class DimensionConfigPanel extends AbstractConfigurationPanel {
private static final long serialVersionUID = 1L;
private final PlotDimension dimension;
// label configuration components
private ResourceLabel dimensionLabelLabel;
private JTextField dimensionLabelTextField;
private JCheckBox automateLabelCheckBox;
// date format configuration components
private ResourceLabel dateFormatLabel;
private JTextField dateFormatTextField;
private JCheckBox useDefaultDateFormatCheckBox;
private JCheckBox logarithmicCheckBox;
private JLabel upperBoundLabel;
private JSpinner upperBoundSpinner;
private JLabel lowerBoundLabel;
private JSpinner lowerBoundSpinner;
private JLabel logarithmicLabel;
private JLabel groupingLabel;
private JComboBox<GroupingType> groupingComboBox;
private JToggleButton groupingConfigButton;
private GroupingConfigurationPanel groupingConfigurationPanel;
private JCheckBox lowerBoundCheckBox;
private JCheckBox upperBoundCheckBox;
private JLabel sortingLabel;
private AbstractButton sortedCheckBox;
// private JLabel automateLabel;
public DimensionConfigPanel(PlotDimension dimension, JTree plotConfigurationTree, PlotInstance plotInstance) {
super(plotInstance);
this.dimension = dimension;
groupingConfigurationPanel = new GroupingConfigurationPanel(plotConfigurationTree, plotInstance, dimension);
addPlotInstanceChangeListener(groupingConfigurationPanel);
createComponents();
registerAsPlotConfigurationListener();
adaptGUI();
}
private void createComponents() {
// // add automated dimension axis label check box
// {
// automateLabel = new ResourceLabel("plotter.configuration_dialog.automatic_axis_label");
//
// automateLabelCheckBox = new JCheckBox();
// automateLabel.setLabelFor(automateLabelCheckBox);
// automateLabelCheckBox.addActionListener(new ActionListener() {
//
// @Override
// public void actionPerformed(ActionEvent e) {
// DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
// if (dimensionConfig != null) {
// dimensionConfig.setAutoNaming(automateLabelCheckBox.isSelected());
// }
// }
//
// });
//
// addTwoComponentRow(this, automateLabel, automateLabelCheckBox);
// }
// create dimension axis label row
{
dimensionLabelLabel = new ResourceLabel("plotter.configuration_dialog.dimension_axis_title");
// create x-axis legend text field
dimensionLabelTextField = new JTextField();
dimensionLabelLabel.setLabelFor(dimensionLabelTextField);
dimensionLabelTextField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
return; // Nothing to be done here
}
@Override
public void keyReleased(KeyEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
String oldLabel = dimensionConfig.getLabel();
String newLabel = dimensionLabelTextField.getText();
if (oldLabel != null && !oldLabel.equals(newLabel) || oldLabel == null && newLabel.length() > 0) {
if (newLabel.length() > 0) {
dimensionConfig.setLabel(newLabel);
} else {
dimensionConfig.setLabel(null);
}
}
}
}
@Override
public void keyPressed(KeyEvent e) {
return; // Nothing to be done here
}
});
dimensionLabelTextField.setPreferredSize(new Dimension(100, 22));
automateLabelCheckBox = new JCheckBox(
I18N.getGUILabel("plotter.configuration_dialog.automatic_axis_label.label"));
// automateLabel.setLabelFor(automateLabelCheckBox);
automateLabelCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
dimensionConfig.setAutoNaming(automateLabelCheckBox.isSelected());
}
}
});
addThreeComponentRow(this, dimensionLabelLabel, dimensionLabelTextField, automateLabelCheckBox);
}
// setup date format configuration components
{
dateFormatLabel = new ResourceLabel("plotter.configuration_dialog.date_format");
// create x-axis legend text field
dateFormatTextField = new JTextField();
dateFormatLabel.setLabelFor(dateFormatTextField);
dateFormatTextField.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
// do nothing
}
@Override
public void keyPressed(KeyEvent e) {
// do nothing
}
@Override
public void keyReleased(KeyEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
String oldFormat = dimensionConfig.getUserDefinedDateFormatString();
String newFormat = dateFormatTextField.getText();
if (oldFormat != null && !oldFormat.equals(newFormat) || oldFormat == null && newFormat.length() > 0) {
if (newFormat.length() > 0) {
dimensionConfig.setUserDefinedDateFormatString(newFormat);
} else {
dimensionConfig.setLabel(null);
}
}
}
}
});
useDefaultDateFormatCheckBox = new JCheckBox(
I18N.getGUILabel("plotter.configuration_dialog.use_default_date_format.label"));
useDefaultDateFormatCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
dimensionConfig.setUseUserDefinedDateFormat(!useDefaultDateFormatCheckBox.isSelected());
}
}
});
addThreeComponentRow(this, dateFormatLabel, dateFormatTextField, useDefaultDateFormatCheckBox);
}
// if (dimension != PlotDimension.DOMAIN) {
// automateLabel.setVisible(false);
// automateLabelCheckBox.setVisible(false);
// dimensionLabelLabel.setVisible(false);
// dimensionLabelTextField.setVisible(false);
// }
// add grouping combo box
{
// create label
groupingLabel = new ResourceLabel("plotter.configuration_dialog.grouping");
groupingLabel.setPreferredSize(new Dimension(80, 15));
// create combo box
groupingComboBox = new JComboBox<>(GroupingType.values());
groupingLabel.setLabelFor(groupingComboBox);
groupingComboBox.setRenderer(new EnumComboBoxCellRenderer<>("plotter.grouping_type"));
groupingComboBox.addPopupMenuListener(new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
return;
}
@Override
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
GroupingType groupingType = (GroupingType) groupingComboBox.getSelectedItem();
ValueGrouping grouping = dimensionConfig.getGrouping();
boolean newGroupingNoneAndOldGroupingSet = groupingType == GroupingType.NONE && grouping != null;
boolean newGroupingAndNotGrouping = groupingType != GroupingType.NONE && grouping == null;
boolean groupingTypeChanged = grouping != null && groupingType != grouping.getGroupingType();
if ((newGroupingNoneAndOldGroupingSet || newGroupingAndNotGrouping || groupingTypeChanged)) {
ValueGrouping oldGrouping = grouping;
boolean categorical = true;
if (oldGrouping != null) {
categorical = oldGrouping.isCategorical();
}
ValueGrouping newGrouping = null;
try {
newGrouping = ValueGroupingFactory.getValueGrouping(groupingType,
dimensionConfig.getDataTableColumn(), categorical, dimensionConfig.getDateFormat());
dimensionConfig.setGrouping(newGrouping);
} catch (ChartConfigurationException e1) {
PlotConfigurationError plotConfigurationError = e1.getResponse().getErrors().get(0);
SwingTools.showVerySimpleErrorMessage(plotConfigurationError.getErrorId(),
plotConfigurationError.getMessageParameters());
if (oldGrouping == null) {
groupingComboBox.setSelectedItem(GroupingType.NONE);
} else {
groupingComboBox.setSelectedItem(oldGrouping.getGroupingType());
}
adaptGUI();
return;
}
}
}
}
@Override
public void popupMenuCanceled(PopupMenuEvent e) {
return;
}
});
groupingConfigButton = new JToggleButton(new PopupAction(true,
"plotter.configuration_dialog.configure_grouping", groupingConfigurationPanel,
PopupAction.PopupPosition.HORIZONTAL));
addThreeComponentRow(this, groupingLabel, groupingComboBox, groupingConfigButton);
}
// // add value source selection if dimension is domain dimension
// {
//
// JTable valueSourceGroupingSelectionTable = new JTable(new
// GroupingSelectionTableModel(getPlotConfiguration()));
// valueSourceGroupingSelectionTable.setBackground(Color.red);
// valueSourceGroupingSelectionTable.setTableHeader(null);
//
// JScrollPane valueSourceGroupingPane = new JScrollPane(valueSourceGroupingSelectionTable);
// valueSourceGroupingPane.setPreferredSize(new Dimension(100,50));
//
// GridBagConstraints itemConstraint = new GridBagConstraints();
// itemConstraint.fill = GridBagConstraints.HORIZONTAL;
// itemConstraint.gridwidth = GridBagConstraints.REMAINDER;
//
// this.add(valueSourceGroupingPane, itemConstraint);
//
// if (dimension != PlotDimension.DOMAIN) {
// // set visible false
// valueSourceGroupingPane.setVisible(false);
// }
//
// }
{
logarithmicLabel = new ResourceLabel("plotter.configuration_dialog.logarithmic");
logarithmicCheckBox = new JCheckBox();
logarithmicLabel.setLabelFor(logarithmicCheckBox);
logarithmicCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
dimensionConfig.setLogarithmic(logarithmicCheckBox.isSelected());
}
}
});
addTwoComponentRow(this, logarithmicLabel, logarithmicCheckBox);
}
// add sorting row
if (dimension == PlotDimension.DOMAIN) {
{
sortingLabel = new ResourceLabel("plotter.configuration_dialog.sorting");
// create checkbox
sortedCheckBox = new JCheckBox();
sortingLabel.setLabelFor(sortedCheckBox);
sortedCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DomainConfigManager domainMngr = getPlotConfiguration().getDomainConfigManager();
if (sortedCheckBox.isSelected()) {
domainMngr.setSortingMode(DomainConfigManager.Sorting.ASCENDING);
} else {
domainMngr.setSortingMode(DomainConfigManager.Sorting.NONE);
}
}
});
addTwoComponentRow(this, sortingLabel, sortedCheckBox);
}
}
// add upper bound spinner
{
upperBoundLabel = new ResourceLabel("plotter.configuration_dialog.upper_filter");
// create spinner
upperBoundSpinner = new JSpinner(new SpinnerNumberModel(1.0, null, null, 0.1));
upperBoundLabel.setLabelFor(upperBoundSpinner);
upperBoundSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
Double oldUpperBound = dimensionConfig.getUserDefinedUpperBound();
Double newUpperBound = (Double) upperBoundSpinner.getValue();
if (!Objects.equals(oldUpperBound, newUpperBound)) {
// Double currentLowerBound =
// dimensionConfig.getUserDefinedLowerBound();
// if (oldUpperBound != null && currentLowerBound != null) {
// if (Math.abs(newUpperBound - currentLowerBound) < 1E-5 ||
// newUpperBound <= currentLowerBound) {
// upperBoundSpinner.setValue(oldUpperBound);
// return;
// }
dimensionConfig.setUpperBound(newUpperBound);
//
// }
}
}
}
});
// create checkbox
upperBoundCheckBox = new JCheckBox(I18N.getGUILabel("plotter.configuration_dialog.use_filter.label"));
upperBoundCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
dimensionConfig.setUseUserDefinedUpperBound(upperBoundCheckBox.isSelected());
}
}
});
addThreeComponentRow(this, upperBoundLabel, upperBoundSpinner, upperBoundCheckBox);
}
// add lower bound spinner
{
lowerBoundLabel = new ResourceLabel("plotter.configuration_dialog.lower_filter");
// create spinner
lowerBoundSpinner = new JSpinner(new SpinnerNumberModel(0.0, null, null, 0.1));
lowerBoundLabel.setLabelFor(lowerBoundSpinner);
lowerBoundSpinner.addChangeListener(new ChangeListener() {
@Override
public void stateChanged(ChangeEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
Double oldLowerBound = dimensionConfig.getUserDefinedLowerBound();
Double newLowerBound = (Double) lowerBoundSpinner.getValue();
if (!Objects.equals(oldLowerBound, newLowerBound)) {
dimensionConfig.setLowerBound(newLowerBound);
}
}
}
});
// create checkbox
lowerBoundCheckBox = new JCheckBox(I18N.getGUILabel("plotter.configuration_dialog.use_filter.label"));
lowerBoundCheckBox.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
if (dimensionConfig != null) {
dimensionConfig.setUseUserDefinedLowerBound(lowerBoundCheckBox.isSelected());
}
}
});
addThreeComponentRow(this, lowerBoundLabel, lowerBoundSpinner, lowerBoundCheckBox);
}
// add spacer panel
{
JPanel spacerPanel = new JPanel();
GridBagConstraints itemConstraint = new GridBagConstraints();
itemConstraint.fill = GridBagConstraints.BOTH;
itemConstraint.weightx = 1;
itemConstraint.weighty = 1;
itemConstraint.gridwidth = GridBagConstraints.REMAINDER;
this.add(spacerPanel, itemConstraint);
}
}
private void upperBoundChanged(Double upperBound) {
upperBoundSpinner.setValue(upperBound);
}
private void lowerBoundChanged(Double lowerBound) {
lowerBoundSpinner.setValue(lowerBound);
}
private void useLowerBoundChanged(boolean useLowerBound, boolean nominalAxis) {
lowerBoundCheckBox.setSelected(useLowerBound);
lowerBoundSpinner.setEnabled(useLowerBound && !nominalAxis);
lowerBoundCheckBox.setEnabled(!nominalAxis);
lowerBoundLabel.setEnabled(!nominalAxis);
}
private void useUpperBoundChanged(boolean useUpperBound, boolean nominalAxis) {
upperBoundCheckBox.setSelected(useUpperBound);
upperBoundSpinner.setEnabled(useUpperBound && !nominalAxis);
upperBoundCheckBox.setEnabled(!nominalAxis);
upperBoundLabel.setEnabled(!nominalAxis);
}
private void logarithmicChanged(boolean logarithmic) {
logarithmicCheckBox.setSelected(logarithmic);
}
private void dimensionLabelChanged(String label) {
if (!dimensionLabelTextField.getText().equals(label)) {
if (label != null) {
dimensionLabelTextField.setText(label);
} else {
dimensionLabelTextField.setText("");
}
}
}
private void autoNamingChanged(boolean autoNaming) {
automateLabelCheckBox.setSelected(autoNaming);
dimensionLabelTextField.setEnabled(!autoNaming);
}
@Override
protected void adaptGUI() {
DimensionConfig dimensionConfig = getPlotConfiguration().getDimensionConfig(dimension);
DataTable dataTable = getCurrentPlotInstance().getPlotData().getOriginalDataTable();
if (dimensionConfig != null && dimensionConfig.getDataTableColumn().isValidForDataTable(dataTable)) {
enableAllComponents();
boolean enableOptions = !dimensionConfig.getDataTableColumn().isNominal()
&& !dimensionConfig.getDataTableColumn().isDate();
if (dimension == PlotDimension.DOMAIN) {
DomainConfigManager domCnfMngr = (DomainConfigManager) dimensionConfig;
sortedCheckBox.setSelected(domCnfMngr.getSortingMode() != Sorting.NONE);
sortedCheckBox.setVisible(enableOptions);
sortingLabel.setVisible(enableOptions);
// boolean groupingVisible = dimensionConfig.getDataTableColumn().getValueType() !=
// ValueType.NOMINAL;
// groupingLabel.setVisible(groupingVisible);
// groupingComboBox.setVisible(groupingVisible);
// groupingConfigButton.setVisible(groupingVisible);
}
// configure date format (if original data (not aggregated data) is date)
boolean dateFormatConfigVisible = dimensionConfig.getDataTableColumn().isDate();
dateFormatTextField.setVisible(dateFormatConfigVisible);
dateFormatLabel.setVisible(dateFormatConfigVisible);
useDefaultDateFormatCheckBox.setVisible(dateFormatConfigVisible);
String userDefinedDateFormatString = dimensionConfig.getUserDefinedDateFormatString();
String text = dateFormatTextField.getText();
if (!text.equals(userDefinedDateFormatString)) {
dateFormatTextField.setText(userDefinedDateFormatString);
}
dateFormatTextField.setEnabled(dimensionConfig.isUsingUserDefinedDateFormat());
useDefaultDateFormatCheckBox.setSelected(!dimensionConfig.isUsingUserDefinedDateFormat());
lowerBoundCheckBox.setVisible(enableOptions);
lowerBoundLabel.setVisible(enableOptions);
lowerBoundSpinner.setVisible(enableOptions);
upperBoundCheckBox.setVisible(enableOptions);
upperBoundLabel.setVisible(enableOptions);
upperBoundSpinner.setVisible(enableOptions);
logarithmicLabel.setVisible(enableOptions);
logarithmicCheckBox.setVisible(enableOptions);
// fill grouping combo box
Vector<GroupingType> validGroupings = dimensionConfig.getValidGroupingTypes();
DefaultComboBoxModel<GroupingType> model = new DefaultComboBoxModel<>(validGroupings);
groupingComboBox.setModel(model);
autoNamingChanged(dimensionConfig.isAutoNaming());
dimensionLabelChanged(dimensionConfig.getLabel());
boolean groupingEnabled = false;
ValueGrouping grouping = dimensionConfig.getGrouping();
GroupingType groupingType = null;
if (grouping != null) {
groupingType = grouping.getGroupingType();
// normally DISTINCT_VALUES grouping cannot be configured,
// only if the values to be grouped are non-nominal, it can
// be configured to create a nominal grouping
if ((groupingType != GroupingType.DISTINCT_VALUES || dimensionConfig.getDataTableColumn().getValueType() != ValueType.NOMINAL)) {
groupingEnabled = true;
}
groupingComboBox.setSelectedItem(groupingType);
} else {
groupingComboBox.setSelectedItem(GroupingType.NONE);
}
groupingConfigButton.setEnabled(groupingEnabled);
logarithmicChanged(dimensionConfig.isLogarithmic());
boolean nominal = (dimensionConfig.getDataTableColumn().getValueType() == ValueType.NOMINAL)
&& dimensionConfig.isNominal();
lowerBoundChanged(dimensionConfig.getUserDefinedLowerBound());
useLowerBoundChanged(dimensionConfig.isUsingUserDefinedLowerBound(), nominal);
upperBoundChanged(dimensionConfig.getUserDefinedUpperBound());
useUpperBoundChanged(dimensionConfig.isUsingUserDefinedUpperBound(), nominal);
} else {
disableAllComponents();
}
}
@Override
public boolean plotConfigurationChanged(PlotConfigurationChangeEvent change) {
adaptGUI();
return true;
}
}