/**
* 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.cellrenderer;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.datatransfer.Transferable;
import javax.swing.BorderFactory;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.SwingConstants;
import javax.swing.UIManager;
import javax.swing.border.Border;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeCellRenderer;
import com.rapidminer.gui.RapidMinerGUI;
import com.rapidminer.gui.RapidMinerGUI.DragHighlightMode;
import com.rapidminer.gui.dnd.DragListener;
import com.rapidminer.gui.flow.processrendering.draw.ProcessDrawer;
import com.rapidminer.gui.look.Colors;
import com.rapidminer.gui.new_plotter.configuration.DataTableColumn;
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.PlotConfiguration;
import com.rapidminer.gui.new_plotter.configuration.RangeAxisConfig;
import com.rapidminer.gui.new_plotter.configuration.SeriesFormat.VisualizationType;
import com.rapidminer.gui.new_plotter.configuration.ValueSource;
import com.rapidminer.gui.new_plotter.gui.dnd.DataTableColumnListTransferHandler;
import com.rapidminer.gui.new_plotter.gui.treenodes.DimensionConfigTreeNode;
import com.rapidminer.gui.new_plotter.gui.treenodes.PlotConfigurationTreeNode;
import com.rapidminer.gui.new_plotter.gui.treenodes.RangeAxisConfigTreeNode;
import com.rapidminer.gui.new_plotter.gui.treenodes.ValueSourceTreeNode;
import com.rapidminer.gui.tools.SwingTools;
import com.rapidminer.tools.I18N;
/**
* A renderer for plot configuration tree cells that displays the configuration's icon and name.
*
* @author Nils Woehler
*
*/
public class PlotConfigurationTreeCellRenderer extends DefaultTreeCellRenderer implements DragListener {
private final Font TREE_FONT = UIManager.getFont("Tree.font");
private final Color SELECTED_COLOR = UIManager.getColor("Tree.selectionBackground");
private final Color NOT_SELECTED_COLOR = Colors.WHITE;
private final Color TEXT_SELECTED_COLOR = UIManager.getColor("Tree.selectionForeground");
private final Color TEXT_NON_SELECTED_COLOR = UIManager.getColor("Tree.textForeground");
private final Color BORDER_SELECTION_COLOR = UIManager.getColor("Tree.selectionBorderColor").darker();
private Icon ERROR_ICON;
private Icon WARNING_ICON;
private Border focusBorder, nonFocusBorder;
/**
* The panel which will be used for the actual rendering of {@link DimensionConfigTreeNode}s and
* {@link RangeAxisConfigTreeNode}s.
*/
private class DimensionAndRangeAxisTreeCellPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JLabel nameLabel;
private JLabel attributeLabel;
private JLabel errorIconLabel;
private final int CELL_WIDTH = 355;
private final int CELL_HEIGTH = 18;
public DimensionAndRangeAxisTreeCellPanel() {
this.setLayout(new BorderLayout());
this.setPreferredSize(new Dimension(CELL_WIDTH, CELL_HEIGTH));
nameLabel = new JLabel("");
nameLabel.setFont(TREE_FONT);
nameLabel.setPreferredSize(new Dimension(140, CELL_HEIGTH));
this.add(nameLabel, BorderLayout.WEST);
attributeLabel = new JLabel("");
attributeLabel.setFont(TREE_FONT);
attributeLabel.setHorizontalAlignment(SwingConstants.LEFT);
attributeLabel.setPreferredSize(new Dimension(155, CELL_HEIGTH));
this.add(attributeLabel, BorderLayout.CENTER);
errorIconLabel = new JLabel("");
this.add(errorIconLabel, BorderLayout.EAST);
}
public void updateTreeCell(JTree tree, RangeAxisConfigTreeNode value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
adaptRangeAxisCell(tree, value, selected, expanded, leaf, row, hasFocus, dragging);
}
public void updateTreeCell(JTree tree, DimensionConfigTreeNode value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
adaptDimensionCell(tree, value, selected, expanded, leaf, row, hasFocus, dragging);
}
private void adaptContainerStyle(JTree tree, Object node, boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus, boolean dragging, boolean setForeground) {
SwingTools.setEnabledRecursive(this, tree.isEnabled());
Color fg = null;
Color bg = null;
boolean highlightingEnabled = RapidMinerGUI.getDragHighlighteMode().equals(DragHighlightMode.FULL);
JTree.DropLocation dropLocation = tree.getDropLocation();
if (dropLocation != null && dropLocation.getChildIndex() == -1
&& tree.getRowForPath(dropLocation.getPath()) == row) {
fg = TEXT_SELECTED_COLOR;
bg = SELECTED_COLOR;
} else if (selected && !dragging) {
fg = TEXT_SELECTED_COLOR;
bg = SELECTED_COLOR;
} else {
fg = TEXT_NON_SELECTED_COLOR;
if (highlightingEnabled && dragging) {
bg = ProcessDrawer.INNER_DRAG_COLOR;
} else {
bg = NOT_SELECTED_COLOR;
}
}
if (setForeground) {
nameLabel.setForeground(fg);
attributeLabel.setForeground(fg);
}
this.setBackground(bg);
if (hasFocus) {
this.setBorder(focusBorder);
} else {
if (highlightingEnabled && dragging) {
this.setBorder(draggingNotFocusedBorder);
} else {
this.setBorder(nonFocusBorder);
}
}
}
private void adaptRangeAxisCell(JTree tree, RangeAxisConfigTreeNode node, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
String i18nKey = "plotter.configuration_dialog.plot_dimension.range_axis";
// set label font
Font fontValue = TREE_FONT;
if (fontValue == null) {
fontValue = nameLabel.getFont();
}
fontValue = new Font(fontValue.getFamily(), Font.PLAIN, fontValue.getSize());
nameLabel.setFont(fontValue);
// set label icon
String icon = I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label." + i18nKey + ".icon");
if (icon != null) {
ImageIcon iicon = SwingTools.createIcon("16/" + icon);
nameLabel.setIcon(iicon);
}
// set label text
RangeAxisConfig rangeAxis = node.getUserObject();
ValueType type = rangeAxis.getValueType();
Color foregroundColor = getValueTypeColor(type);
String valueText = "";
switch (type) {
case DATE_TIME:
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.date_range_axis.label") + " ";
break;
case INVALID:
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.invalid_range_axis.label")
+ " ";
break;
case NOMINAL:
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.nominal_range_axis.label")
+ " ";
break;
case NUMERICAL:
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.numerical_range_axis.label")
+ " ";
break;
case UNKNOWN:
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.empty_range_axis.label") + " ";
break;
}
Icon errorLabelIcon = null;
if (foregroundColor != null && foregroundColor.equals(TreeNodeColors.getWarningColor())) {
errorLabelIcon = WARNING_ICON;
}
if (!rangeAxis.getWarnings().isEmpty()) {
foregroundColor = TreeNodeColors.getWarningColor();
errorLabelIcon = WARNING_ICON;
}
if (!rangeAxis.getErrors().isEmpty()) {
foregroundColor = TreeNodeColors.getInvalidColor();
valueText = I18N.getGUILabel("plotter.configuration_dialog.plot_dimension.invalid_range_axis.label") + " ";
errorLabelIcon = ERROR_ICON;
}
errorIconLabel.setIcon(errorLabelIcon);
valueText += I18N.getMessage(I18N.getGUIBundle(), "gui.label." + i18nKey + ".label") + ":";
nameLabel.setText(valueText);
// set attribute label text
String label = rangeAxis.getLabel();
if (label == null) {
label = I18N.getGUILabel("plotter.unnamed_value_label");
}
attributeLabel.setText(label);
// show attribute label
attributeLabel.setVisible(true);
boolean foregroundSet = foregroundColor != null;
if (foregroundSet) {
nameLabel.setForeground(foregroundColor);
attributeLabel.setForeground(foregroundColor);
}
adaptContainerStyle(tree, node, selected, expanded, leaf, row, hasFocus, dragging, !foregroundSet);
}
private void adaptDimensionCell(JTree tree, DimensionConfigTreeNode node, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
String i18nKey = null;
switch (node.getDimension()) {
case COLOR:
i18nKey = "plotter.configuration_dialog.plot_dimension.color";
break;
case DOMAIN:
i18nKey = "plotter.configuration_dialog.plot_dimension.domain";
break;
case SHAPE:
i18nKey = "plotter.configuration_dialog.plot_dimension.shape";
break;
case SIZE:
i18nKey = "plotter.configuration_dialog.plot_dimension.size";
break;
default:
}
// set label font
Font fontValue = TREE_FONT;
if (fontValue == null) {
fontValue = nameLabel.getFont();
}
fontValue = new Font(fontValue.getFamily(), Font.PLAIN, fontValue.getSize());
nameLabel.setFont(fontValue);
// set label icon
String icon = I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label." + i18nKey + ".icon");
if (icon != null) {
ImageIcon iicon = SwingTools.createIcon("16/" + icon);
nameLabel.setIcon(iicon);
}
// get name label text
PlotDimension dimension = node.getDimension();
String valueText = dimension.getName() + ": ";
// set name label
nameLabel.setText(valueText);
DimensionConfig dimensionConfig = node.getUserObject();
// set attribute text and icons
String emptyLabel = I18N.getMessage(I18N.getGUIBundle(),
"gui.label.plotter.configuration_dialog.empty_dimension.label");
if (dimensionConfig != null) {
valueText = dimensionConfig.getLabel();
DataTableColumn dataTableColumn = dimensionConfig.getDataTableColumn();
String name = dataTableColumn.getName();
if (valueText == null) {
if (dimensionConfig.getDimension() == PlotDimension.DOMAIN && (name == null || name.isEmpty())) {
valueText = emptyLabel;
} else {
valueText = I18N.getGUILabel("plotter.unnamed_value_label");
if (!dimensionConfig.isAutoNaming()) {
valueText += " [";
valueText += name;
valueText += "]";
}
}
} else {
if (!dimensionConfig.isAutoNaming()) {
valueText += " [";
valueText += name;
valueText += "]";
}
}
} else {
valueText = emptyLabel;
}
attributeLabel.setIcon(null);
attributeLabel.setText(valueText);
// show attribute label
attributeLabel.setVisible(true);
Color foregroundColor = null;
Icon errorLabelIcon = null;
if (dimensionConfig != null) {
ValueType valueType = dimensionConfig.getValueType();
if (!(valueType == ValueType.UNKNOWN && dimensionConfig.getDimension() == PlotDimension.DOMAIN)) {
foregroundColor = getValueTypeColor(valueType);
}
PlotConfiguration plotConfig = (PlotConfiguration) ((DefaultMutableTreeNode) tree.getModel().getRoot())
.getUserObject();
if (!dimensionConfig.getWarnings().isEmpty() || !plotConfig.isDimensionUsed(dimension)) {
foregroundColor = TreeNodeColors.getWarningColor();
errorLabelIcon = WARNING_ICON;
}
if (!dimensionConfig.getErrors().isEmpty() || foregroundColor != null
&& foregroundColor.equals(TreeNodeColors.getInvalidColor())) {
foregroundColor = TreeNodeColors.getInvalidColor();
errorLabelIcon = ERROR_ICON;
}
}
errorIconLabel.setIcon(errorLabelIcon);
boolean foregroundSet = foregroundColor != null;
if (foregroundSet) {
nameLabel.setForeground(foregroundColor);
attributeLabel.setForeground(foregroundColor);
}
adaptContainerStyle(tree, node, selected, expanded, leaf, row, hasFocus, dragging, !foregroundSet);
}
/**
* This is a workaround to fix a Swing bug with causes the drag cursor to flicker. See
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6700748 TODO: Occasionally check
* whether this bug was resolved by Sun.
*/
@Override
public boolean isVisible() {
return false;
}
/**
* Overrides <code>JComponent.getPreferredSize</code> to return slightly wider preferred
* size value.
*/
@Override
public Dimension getPreferredSize() {
Dimension retDimension = super.getPreferredSize();
if (retDimension != null) {
retDimension = new Dimension(retDimension.width + 3, retDimension.height + 3);
}
return retDimension;
}
}
/**
* The panel which will be used for the actual rendering of {@link PlotConfigurationTreeNode}s
* and {@link ValueSourceTreeNode}s.
*/
private class GlobalAndValueSourceTreeCellPanel extends JPanel {
private static final long serialVersionUID = 1L;
private JLabel nameLabel;
private JLabel errorIconLabel;
public GlobalAndValueSourceTreeCellPanel() {
this.setLayout(new BorderLayout());
nameLabel = new JLabel("");
nameLabel.setFont(TREE_FONT);
nameLabel.setHorizontalAlignment(SwingConstants.LEFT);
// nameLabel.setPreferredSize(new Dimension(CELL_WIDTH, CELL_HEIGTH));
this.add(nameLabel, BorderLayout.CENTER);
errorIconLabel = new JLabel("");
this.add(errorIconLabel, BorderLayout.EAST);
}
public void updateTreeCell(JTree tree, PlotConfigurationTreeNode value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
adaptPlotConfigurationCell(tree, value, selected, expanded, leaf, row, hasFocus);
adaptContainerStyle(tree, value, selected, expanded, leaf, row, hasFocus, dragging, true);
}
public void updateTreeCell(JTree tree, ValueSourceTreeNode value, boolean selected, boolean expanded, boolean leaf,
int row, boolean hasFocus, boolean dragging) {
adaptValueSource(tree, value, selected, expanded, leaf, row, hasFocus, dragging);
}
private void adaptContainerStyle(JTree tree, Object node, boolean selected, boolean expanded, boolean leaf, int row,
boolean hasFocus, boolean dragging, boolean setForeGround) {
SwingTools.setEnabledRecursive(this, tree.isEnabled());
Color fg = null;
Color bg = null;
boolean highlightingEnabled = RapidMinerGUI.getDragHighlighteMode().equals(DragHighlightMode.FULL);
JTree.DropLocation dropLocation = tree.getDropLocation();
if (dropLocation != null && dropLocation.getChildIndex() == -1
&& tree.getRowForPath(dropLocation.getPath()) == row) {
fg = TEXT_SELECTED_COLOR;
bg = SELECTED_COLOR;
} else if (selected && !dragging) {
fg = TEXT_SELECTED_COLOR;
bg = SELECTED_COLOR;
} else {
fg = TEXT_NON_SELECTED_COLOR;
if (highlightingEnabled && dragging) {
bg = ProcessDrawer.INNER_DRAG_COLOR;
} else {
bg = NOT_SELECTED_COLOR;
}
}
if (setForeGround) {
nameLabel.setForeground(fg);
}
this.setBackground(bg);
if (hasFocus) {
this.setBorder(focusBorder);
} else {
if (highlightingEnabled && dragging) {
this.setBorder(draggingNotFocusedBorder);
} else {
this.setBorder(nonFocusBorder);
}
}
}
private void adaptPlotConfigurationCell(JTree tree, PlotConfigurationTreeNode node, boolean selected,
boolean expanded, boolean leaf, int row, boolean hasFocus) {
String i18nKey = "plotter.configuration_dialog.global_configuration";
// set label font
Font fontValue = TREE_FONT;
if (fontValue == null) {
fontValue = nameLabel.getFont();
}
// fontValue = new Font(fontValue.getFamily(), Font.BOLD, fontValue.getSize());
// nameLabel.setFont(fontValue);
// set label icon
String icon = I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label." + i18nKey + ".icon");
if (icon != null) {
ImageIcon iicon = SwingTools.createIcon("16/" + icon);
nameLabel.setIcon(iicon);
}
// set label text
nameLabel.setText(I18N.getMessage(I18N.getGUIBundle(), "gui.label." + i18nKey + ".label"));
errorIconLabel.setIcon(null);
}
private void adaptValueSource(JTree tree, ValueSourceTreeNode node, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus, boolean dragging) {
// set label font
Font fontValue = TREE_FONT;
if (fontValue == null) {
fontValue = nameLabel.getFont();
}
fontValue = new Font(fontValue.getFamily(), Font.PLAIN, fontValue.getSize());
nameLabel.setFont(fontValue);
ValueSource valueSource = node.getUserObject();
String i18nKey = null;
if (valueSource.getSeriesFormat().getSeriesType() == VisualizationType.LINES_AND_SHAPES) {
i18nKey = "plotter.configuration_dialog.line_value_source";
} else if (valueSource.getSeriesFormat().getSeriesType() == VisualizationType.AREA) {
i18nKey = "plotter.configuration_dialog.area_value_source";
} else {
i18nKey = "plotter.configuration_dialog.bar_value_source";
}
// set label icon
String icon = I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label." + i18nKey + ".icon");
if (icon != null) {
ImageIcon iicon = SwingTools.createIcon("16/" + icon);
nameLabel.setIcon(iicon);
}
// set label text
String valueText = valueSource.getLabel();
if (valueText == null) {
valueText = I18N.getGUILabel("plotter.unnamed_value_label");
}
if (!valueSource.isAutoNaming()) {
valueText += " [";
valueText += valueSource.getAutoLabel();
valueText += "]";
}
valueText = I18N.getGUILabel("plotter.series_label.label") + valueText;
nameLabel.setText(valueText);
Icon errorLabelIcon = null;
Color foregroundColor = getValueTypeColor(valueSource.getValueType());
if (foregroundColor != null && foregroundColor.equals(TreeNodeColors.getWarningColor())) {
errorLabelIcon = WARNING_ICON;
}
if (!valueSource.getErrors().isEmpty()) {
foregroundColor = TreeNodeColors.getInvalidColor();
errorLabelIcon = ERROR_ICON;
}
errorIconLabel.setIcon(errorLabelIcon);
boolean foregroundSet = foregroundColor != null;
if (foregroundSet) {
nameLabel.setForeground(foregroundColor);
}
adaptContainerStyle(tree, node, selected, expanded, leaf, row, hasFocus, dragging, !foregroundSet);
}
/**
* This is a workaround to fix a Swing bug with causes the drag cursor to flicker. See
* http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6700748 TODO: Occasionally check
* whether this bug was resolved by Sun.
*/
@Override
public boolean isVisible() {
return false;
}
/**
* Overrides <code>JComponent.getPreferredSize</code> to return slightly wider preferred
* size value.
*/
@Override
public Dimension getPreferredSize() {
Dimension retDimension = super.getPreferredSize();
if (retDimension != null) {
retDimension = new Dimension(retDimension.width + 3, retDimension.height + 3);
}
return retDimension;
}
}
private static final long serialVersionUID = 1L;
private final DimensionAndRangeAxisTreeCellPanel dimensionAndRangeAxisRenderPanel;
private final GlobalAndValueSourceTreeCellPanel globalAndValueSourceRenderPanel;
private boolean dragging;
private Border draggingNotFocusedBorder;
public PlotConfigurationTreeCellRenderer(DataTableColumnListTransferHandler aTH) {
aTH.addDragListener(this);
ERROR_ICON = SwingTools.createIcon("16/"
+ I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label.plotter.configuratiom_dialog.error_icon"));
WARNING_ICON = SwingTools.createIcon("16/"
+ I18N.getMessageOrNull(I18N.getGUIBundle(), "gui.label.plotter.configuratiom_dialog.warning_icon"));
focusBorder = BorderFactory.createLineBorder(BORDER_SELECTION_COLOR);
nonFocusBorder = BorderFactory.createLineBorder(Color.white);
draggingNotFocusedBorder = BorderFactory.createLineBorder(ProcessDrawer.INNER_DRAG_COLOR);
dimensionAndRangeAxisRenderPanel = new DimensionAndRangeAxisTreeCellPanel();
globalAndValueSourceRenderPanel = new GlobalAndValueSourceTreeCellPanel();
}
@Override
public Component getTreeCellRendererComponent(JTree tree, Object value, boolean selected, boolean expanded,
boolean leaf, int row, boolean hasFocus) {
if (value instanceof PlotConfigurationTreeNode) {
globalAndValueSourceRenderPanel.updateTreeCell(tree, (PlotConfigurationTreeNode) value, selected, expanded,
leaf, row, hasFocus, dragging);
return globalAndValueSourceRenderPanel;
} else if (value instanceof ValueSourceTreeNode) {
globalAndValueSourceRenderPanel.updateTreeCell(tree, (ValueSourceTreeNode) value, selected, expanded, leaf, row,
hasFocus, dragging);
return globalAndValueSourceRenderPanel;
} else if (value instanceof RangeAxisConfigTreeNode) {
dimensionAndRangeAxisRenderPanel.updateTreeCell(tree, (RangeAxisConfigTreeNode) value, selected, expanded, leaf,
row, hasFocus, dragging);
return dimensionAndRangeAxisRenderPanel;
} else if (value instanceof DimensionConfigTreeNode) {
dimensionAndRangeAxisRenderPanel.updateTreeCell(tree, (DimensionConfigTreeNode) value, selected, expanded, leaf,
row, hasFocus, dragging);
return dimensionAndRangeAxisRenderPanel;
} else {
return super.getTreeCellRendererComponent(tree, value, selected, expanded, leaf, row, hasFocus);
}
}
protected Color getValueTypeColor(ValueType type) {
switch (type) {
case DATE_TIME:
return TreeNodeColors.getDateColor();
case INVALID:
return TreeNodeColors.getInvalidColor();
case NOMINAL:
return TreeNodeColors.getNominalColor();
case NUMERICAL:
return TreeNodeColors.getNumericalColor();
default:
return TreeNodeColors.getWarningColor();
}
}
@Override
public void dragStarted(Transferable t) {
dragging = true;
}
@Override
public void dragEnded() {
dragging = false;
}
}