/*
* Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
* Copyright (C) $$Year-Rel$$ The Jalview Authors
*
* This file is part of Jalview.
*
* Jalview 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.
*
* Jalview 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 Jalview. If not, see .
* The Jalview Authors are detailed in the 'AUTHORS' file.
*/
package jalview.gui;
import jalview.api.FeatureColourI;
import jalview.datamodel.GraphLine;
import jalview.datamodel.features.FeatureAttributes;
import jalview.schemes.FeatureColour;
import jalview.util.MessageManager;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.FocusAdapter;
import java.awt.event.FocusEvent;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
import javax.swing.BorderFactory;
import javax.swing.BoxLayout;
import javax.swing.ButtonGroup;
import javax.swing.JCheckBox;
import javax.swing.JColorChooser;
import javax.swing.JComboBox;
import javax.swing.JLabel;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JPopupMenu;
import javax.swing.JRadioButton;
import javax.swing.JSlider;
import javax.swing.JTextField;
import javax.swing.border.LineBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
public class FeatureColourChooser extends JalviewDialog
{
private static final int MAX_TOOLTIP_LENGTH = 50;
private FeatureRenderer fr;
private FeatureColourI cs;
private FeatureColourI oldcs;
private AlignmentPanel ap;
private boolean adjusting = false;
private float min;
private float max;
private float scaleFactor;
private String type = null;
private JPanel minColour = new JPanel();
private JPanel maxColour = new JPanel();
private JPanel noColour = new JPanel();
private JComboBox threshold = new JComboBox<>();
private JSlider slider = new JSlider();
private JTextField thresholdValue = new JTextField(20);
private JCheckBox thresholdIsMin = new JCheckBox();
private GraphLine threshline;
private Color oldmaxColour;
private Color oldminColour;
private Color oldNoColour;
private ActionListener colourEditor = null;
/*
* radio buttons to select what to colour by
* label, attribute text, score, attribute value
*/
private JRadioButton byDescription = new JRadioButton();
private JRadioButton byAttributeText = new JRadioButton();
private JRadioButton byScore = new JRadioButton();
private JRadioButton byAttributeValue = new JRadioButton();
private ActionListener changeColourAction;
/*
* choice of attribute (if any) for 'colour by text'
*/
private JComboBox textAttributeCombo;
/*
* choice of attribute (if any) for 'colour by value'
*/
private JComboBox valueAttributeCombo;
/**
* Constructor
*
* @param frender
* @param theType
*/
public FeatureColourChooser(FeatureRenderer frender, String theType)
{
this(frender, false, theType);
}
/**
* Constructor, with option to make a blocking dialog (has to complete in the
* AWT event queue thread). Currently this option is always set to false.
*
* @param frender
* @param blocking
* @param theType
*/
FeatureColourChooser(FeatureRenderer frender, boolean blocking,
String theType)
{
this.fr = frender;
this.type = theType;
ap = fr.ap;
String title = MessageManager
.formatMessage("label.graduated_color_for_params", new String[]
{ theType });
initDialogFrame(this, true, blocking, title, 450, 300);
slider.addChangeListener(new ChangeListener()
{
@Override
public void stateChanged(ChangeEvent evt)
{
if (!adjusting)
{
thresholdValue.setText((slider.getValue() / scaleFactor) + "");
sliderValueChanged();
}
}
});
slider.addMouseListener(new MouseAdapter()
{
@Override
public void mouseReleased(MouseEvent evt)
{
/*
* only update Overview and/or structure colouring
* when threshold slider drag ends (mouse up)
*/
if (ap != null)
{
ap.paintAlignment(true, true);
}
}
});
float mm[] = fr.getMinMax().get(theType)[0];
min = mm[0];
max = mm[1];
/*
* ensure scale factor allows a scaled range with
* 10 integer divisions ('ticks'); if we have got here,
* we should expect that max != min
*/
scaleFactor = (max == min) ? 1f : 100f / (max - min);
oldcs = fr.getFeatureColours().get(theType);
if (!oldcs.isSimpleColour())
{
if (oldcs.isAutoScaled())
{
// update the scale
cs = new FeatureColour((FeatureColour) oldcs, min, max);
}
else
{
cs = new FeatureColour((FeatureColour) oldcs);
}
}
else
{
/*
* promote original simple color to a graduated color
* - by score if there is a score range, else by label
*/
Color bl = oldcs.getColour();
if (bl == null)
{
bl = Color.BLACK;
}
// original colour becomes the maximum colour
cs = new FeatureColour(Color.white, bl, mm[0], mm[1]);
cs.setColourByLabel(mm[0] == mm[1]);
}
minColour.setBackground(oldminColour = cs.getMinColour());
maxColour.setBackground(oldmaxColour = cs.getMaxColour());
noColour.setBackground(oldNoColour = cs.getNoColour());
adjusting = true;
try
{
jbInit();
} catch (Exception ex)
{
ex.printStackTrace();
return;
}
/*
* set the initial state of options on screen
*/
thresholdIsMin.setSelected(!cs.isAutoScaled());
if (cs.isColourByLabel())
{
if (cs.isColourByAttribute())
{
byAttributeText.setSelected(true);
textAttributeCombo.setEnabled(true);
textAttributeCombo.setSelectedItem(cs.getAttributeName());
}
else
{
byDescription.setSelected(true);
textAttributeCombo.setEnabled(false);
}
}
else
{
if (cs.isColourByAttribute())
{
byAttributeValue.setSelected(true);
String attributeName = cs.getAttributeName();
valueAttributeCombo.setSelectedItem(attributeName);
valueAttributeCombo.setEnabled(true);
setAttributeMinMax(attributeName);
}
else
{
byScore.setSelected(true);
valueAttributeCombo.setEnabled(false);
}
}
if (cs.hasThreshold())
{
// initialise threshold slider and selector
threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2);
slider.setEnabled(true);
slider.setValue((int) (cs.getThreshold() * scaleFactor));
thresholdValue.setEnabled(true);
threshline = new GraphLine((max - min) / 2f, "Threshold",
Color.black);
threshline.value = cs.getThreshold();
}
adjusting = false;
changeColour(false);
waitForInput();
}
/**
* Configures the initial layout
*/
private void jbInit()
{
this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
this.setBackground(Color.white);
changeColourAction = new ActionListener() {
@Override
public void actionPerformed(ActionEvent e)
{
changeColour(true);
}
};
/*
* this panel
* detailsPanel
* colourByTextPanel
* colourByScorePanel
* okCancelPanel
*/
JPanel detailsPanel = new JPanel();
detailsPanel.setLayout(new BoxLayout(detailsPanel, BoxLayout.Y_AXIS));
JPanel colourByTextPanel = initColourByTextPanel();
detailsPanel.add(colourByTextPanel);
JPanel colourByValuePanel = initColourByValuePanel();
detailsPanel.add(colourByValuePanel);
/*
* 4 radio buttons select between colour by description, by
* attribute text, by score, or by attribute value
*/
ButtonGroup bg = new ButtonGroup();
bg.add(byDescription);
bg.add(byAttributeText);
bg.add(byScore);
bg.add(byAttributeValue);
JPanel okCancelPanel = initOkCancelPanel();
this.add(detailsPanel);
this.add(okCancelPanel);
}
/**
* Lay out fields for graduated colour by value
*
* @return
*/
protected JPanel initColourByValuePanel()
{
JPanel byValuePanel = new JPanel();
byValuePanel.setLayout(new BoxLayout(byValuePanel, BoxLayout.Y_AXIS));
byValuePanel.setBorder(BorderFactory.createTitledBorder(MessageManager
.getString("label.colour_by_value")));
byValuePanel.setBackground(Color.white);
/*
* first row - choose colour by score or by attribute, choose attribute
*/
JPanel byWhatPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
byWhatPanel.setBackground(Color.white);
byValuePanel.add(byWhatPanel);
byScore.setText(MessageManager.getString("label.score"));
byWhatPanel.add(byScore);
byScore.addActionListener(changeColourAction);
byAttributeValue.setText(MessageManager
.getString("label.attribute"));
byAttributeValue.addActionListener(changeColourAction);
byWhatPanel.add(byAttributeValue);
List attNames = FeatureAttributes.getInstance().getAttributes(
type);
valueAttributeCombo = populateAttributesDropdown(type, attNames,
true);
/*
* if no numeric atttibutes found, disable colour by attribute value
*/
if (valueAttributeCombo.getItemCount() == 0)
{
byAttributeValue.setEnabled(false);
}
byWhatPanel.add(valueAttributeCombo);
/*
* second row - min/max/no colours
*/
JPanel colourRangePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
colourRangePanel.setBackground(Color.white);
byValuePanel.add(colourRangePanel);
minColour.setFont(JvSwingUtils.getLabelFont());
minColour.setBorder(BorderFactory.createLineBorder(Color.black));
minColour.setPreferredSize(new Dimension(40, 20));
minColour.setToolTipText(MessageManager.getString("label.min_colour"));
minColour.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
if (minColour.isEnabled())
{
minColour_actionPerformed();
}
}
});
maxColour.setFont(JvSwingUtils.getLabelFont());
maxColour.setBorder(BorderFactory.createLineBorder(Color.black));
maxColour.setPreferredSize(new Dimension(40, 20));
maxColour.setToolTipText(MessageManager.getString("label.max_colour"));
maxColour.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
if (maxColour.isEnabled())
{
maxColour_actionPerformed();
}
}
});
maxColour.setBorder(new LineBorder(Color.black));
noColour.setFont(JvSwingUtils.getLabelFont());
noColour.setBorder(BorderFactory.createLineBorder(Color.black));
noColour.setPreferredSize(new Dimension(40, 20));
noColour.setToolTipText("Colour if feature has no attribute value");
noColour.addMouseListener(new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent e)
{
if (e.isPopupTrigger()) // Mac: mouseReleased
{
showNoColourPopup(e);
return;
}
if (noColour.isEnabled())
{
noColour_actionPerformed();
}
}
@Override
public void mouseReleased(MouseEvent e)
{
if (e.isPopupTrigger()) // Windows: mouseReleased
{
showNoColourPopup(e);
e.consume();
return;
}
}
});
noColour.setBorder(new LineBorder(Color.black));
JLabel minText = new JLabel(MessageManager.getString("label.min"));
minText.setFont(JvSwingUtils.getLabelFont());
JLabel maxText = new JLabel(MessageManager.getString("label.max"));
maxText.setFont(JvSwingUtils.getLabelFont());
JLabel noText = new JLabel(MessageManager.getString("label.no_colour"));
noText.setFont(JvSwingUtils.getLabelFont());
colourRangePanel.add(minText);
colourRangePanel.add(minColour);
colourRangePanel.add(maxText);
colourRangePanel.add(maxColour);
colourRangePanel.add(noText);
colourRangePanel.add(noColour);
/*
* third row - threshold options and value
*/
JPanel thresholdPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
thresholdPanel.setBackground(Color.white);
byValuePanel.add(thresholdPanel);
threshold.addActionListener(changeColourAction);
threshold.setToolTipText(MessageManager
.getString("label.threshold_feature_display_by_score"));
threshold.addItem(MessageManager
.getString("label.threshold_feature_no_threshold")); // index 0
threshold.addItem(MessageManager
.getString("label.threshold_feature_above_threshold")); // index 1
threshold.addItem(MessageManager
.getString("label.threshold_feature_below_threshold")); // index 2
thresholdValue.addActionListener(new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
thresholdValue_actionPerformed();
}
});
thresholdValue.addFocusListener(new FocusAdapter()
{
@Override
public void focusLost(FocusEvent e)
{
thresholdValue_actionPerformed();
}
});
slider.setPaintLabels(false);
slider.setPaintTicks(true);
slider.setBackground(Color.white);
slider.setEnabled(false);
slider.setOpaque(false);
slider.setPreferredSize(new Dimension(100, 32));
slider.setToolTipText(
MessageManager.getString("label.adjust_threshold"));
thresholdValue.setEnabled(false);
thresholdValue.setColumns(7);
thresholdPanel.add(threshold);
thresholdPanel.add(slider);
thresholdPanel.add(thresholdValue);
/*
* 4th row - threshold is min / max
*/
JPanel isMinMaxPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
isMinMaxPanel.setBackground(Color.white);
byValuePanel.add(isMinMaxPanel);
thresholdIsMin.setBackground(Color.white);
thresholdIsMin
.setText(MessageManager.getString("label.threshold_minmax"));
thresholdIsMin.setToolTipText(MessageManager
.getString("label.toggle_absolute_relative_display_threshold"));
thresholdIsMin.addActionListener(changeColourAction);
isMinMaxPanel.add(thresholdIsMin);
return byValuePanel;
}
/**
* Show a popup menu with options to make 'no value colour' the same as Min
* Colour or Max Colour
*
* @param evt
*/
protected void showNoColourPopup(MouseEvent evt)
{
JPopupMenu pop = new JPopupMenu();
JMenuItem copyMin = new JMenuItem(
MessageManager.getString("label.min_colour"));
copyMin.addActionListener((new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
noColour.setBackground(minColour.getBackground());
changeColour(true);
}
}));
pop.add(copyMin);
JMenuItem copyMax = new JMenuItem(
MessageManager.getString("label.max_colour"));
copyMax.addActionListener((new ActionListener()
{
@Override
public void actionPerformed(ActionEvent e)
{
noColour.setBackground(maxColour.getBackground());
changeColour(true);
}
}));
pop.add(copyMax);
pop.show(noColour, evt.getX(), evt.getY());
}
/**
* Lay out OK and Cancel buttons
*
* @return
*/
protected JPanel initOkCancelPanel()
{
JPanel okCancelPanel = new JPanel();
okCancelPanel.setBackground(Color.white);
okCancelPanel.add(ok);
okCancelPanel.add(cancel);
return okCancelPanel;
}
/**
* Lay out Colour by Label and attribute choice elements
*
* @return
*/
protected JPanel initColourByTextPanel()
{
JPanel byTextPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
byTextPanel.setBackground(Color.white);
byTextPanel.setBorder(BorderFactory.createTitledBorder(MessageManager
.getString("label.colour_by_text")));
byDescription.setText(MessageManager.getString("label.label"));
byDescription.setToolTipText(MessageManager
.getString("label.colour_by_label_tip"));
byDescription.addActionListener(changeColourAction);
byTextPanel.add(byDescription);
byAttributeText.setText(MessageManager.getString("label.attribute"));
byAttributeText.addActionListener(changeColourAction);
byTextPanel.add(byAttributeText);
List attNames = FeatureAttributes.getInstance().getAttributes(
type);
textAttributeCombo = populateAttributesDropdown(type, attNames, false);
byTextPanel.add(textAttributeCombo);
/*
* disable colour by attribute if no attributes
*/
if (attNames.isEmpty())
{
byAttributeText.setEnabled(false);
}
return byTextPanel;
}
/**
* Action on clicking the 'minimum colour' - open a colour chooser dialog, and
* set the selected colour (if the user does not cancel out of the dialog)
*/
protected void minColour_actionPerformed()
{
Color col = JColorChooser.showDialog(this,
MessageManager.getString("label.select_colour_minimum_value"),
minColour.getBackground());
if (col != null)
{
minColour.setBackground(col);
minColour.setForeground(col);
}
minColour.repaint();
changeColour(true);
}
/**
* Action on clicking the 'maximum colour' - open a colour chooser dialog, and
* set the selected colour (if the user does not cancel out of the dialog)
*/
protected void maxColour_actionPerformed()
{
Color col = JColorChooser.showDialog(this,
MessageManager.getString("label.select_colour_maximum_value"),
maxColour.getBackground());
if (col != null)
{
maxColour.setBackground(col);
maxColour.setForeground(col);
}
maxColour.repaint();
changeColour(true);
}
/**
* Action on clicking the 'no colour' - open a colour chooser dialog, and set
* the selected colour (if the user does not cancel out of the dialog)
*/
protected void noColour_actionPerformed()
{
Color col = JColorChooser.showDialog(this,
MessageManager.getString("label.select_no_value_colour"),
noColour.getBackground());
if (col != null)
{
noColour.setBackground(col);
noColour.setForeground(col);
}
noColour.repaint();
changeColour(true);
}
/**
* Constructs and sets the selected colour options as the colour for the
* feature type, and repaints the alignment, and optionally the Overview
* and/or structure viewer if open
*
* @param updateStructsAndOverview
*/
void changeColour(boolean updateStructsAndOverview)
{
// Check if combobox is still adjusting
if (adjusting)
{
return;
}
boolean aboveThreshold = false;
boolean belowThreshold = false;
if (threshold.getSelectedIndex() == 1)
{
aboveThreshold = true;
}
else if (threshold.getSelectedIndex() == 2)
{
belowThreshold = true;
}
boolean hasThreshold = aboveThreshold || belowThreshold;
slider.setEnabled(true);
thresholdValue.setEnabled(true);
/*
* make the feature colour
*/
FeatureColourI acg;
if (cs.isColourByLabel())
{
acg = new FeatureColour(oldminColour, oldmaxColour, min, max);
}
else
{
acg = new FeatureColour(oldminColour = minColour.getBackground(),
oldmaxColour = maxColour.getBackground(),
oldNoColour = noColour.getBackground(), min, max);
}
String attribute = null;
textAttributeCombo.setEnabled(false);
valueAttributeCombo.setEnabled(false);
if (byAttributeText.isSelected())
{
attribute = (String) textAttributeCombo.getSelectedItem();
textAttributeCombo.setEnabled(true);
}
else if (byAttributeValue.isSelected())
{
attribute = (String) valueAttributeCombo.getSelectedItem();
valueAttributeCombo.setEnabled(true);
}
acg.setAttributeName(attribute);
if (!hasThreshold)
{
slider.setEnabled(false);
thresholdValue.setEnabled(false);
thresholdValue.setText("");
thresholdIsMin.setEnabled(false);
}
else if (threshline == null)
{
/*
* todo not yet implemented: visual indication of feature threshold
*/
threshline = new GraphLine((max - min) / 2f, "Threshold",
Color.black);
}
if (hasThreshold)
{
adjusting = true;
acg.setThreshold(threshline.value);
float range = (max - min) * scaleFactor;
slider.setMinimum((int) (min * scaleFactor));
slider.setMaximum((int) (max * scaleFactor));
// slider.setValue((int) (threshline.value * scaleFactor));
slider.setValue(Math.round(threshline.value * scaleFactor));
thresholdValue.setText(threshline.value + "");
slider.setMajorTickSpacing((int) (range / 10f));
slider.setEnabled(true);
thresholdValue.setEnabled(true);
thresholdIsMin.setEnabled(!byDescription.isSelected());
adjusting = false;
}
acg.setAboveThreshold(aboveThreshold);
acg.setBelowThreshold(belowThreshold);
if (thresholdIsMin.isSelected() && hasThreshold)
{
acg.setAutoScaled(false);
if (aboveThreshold)
{
acg = new FeatureColour((FeatureColour) acg, threshline.value, max);
}
else
{
acg = new FeatureColour((FeatureColour) acg, min, threshline.value);
}
}
else
{
acg.setAutoScaled(true);
}
acg.setColourByLabel(byDescription.isSelected()
|| byAttributeText.isSelected());
if (acg.isColourByLabel())
{
maxColour.setEnabled(false);
minColour.setEnabled(false);
noColour.setEnabled(false);
maxColour.setBackground(this.getBackground());
maxColour.setForeground(this.getBackground());
minColour.setBackground(this.getBackground());
minColour.setForeground(this.getBackground());
noColour.setBackground(this.getBackground());
noColour.setForeground(this.getBackground());
}
else
{
maxColour.setEnabled(true);
minColour.setEnabled(true);
noColour.setEnabled(true);
maxColour.setBackground(oldmaxColour);
maxColour.setForeground(oldmaxColour);
minColour.setBackground(oldminColour);
minColour.setForeground(oldminColour);
noColour.setBackground(oldNoColour);
noColour.setForeground(oldNoColour);
}
/*
* save the colour, and repaint stuff
*/
fr.setColour(type, acg);
cs = acg;
ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
}
@Override
protected void raiseClosed()
{
if (this.colourEditor != null)
{
colourEditor.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
}
}
@Override
public void okPressed()
{
changeColour(false);
}
@Override
public void cancelPressed()
{
reset();
}
/**
* Action when the user cancels the dialog. All previous settings should be
* restored and rendered on the alignment, and any linked Overview window or
* structure.
*/
void reset()
{
fr.setColour(type, oldcs);
ap.paintAlignment(true, true);
cs = null;
}
/**
* Action on text entry of a threshold value
*/
protected void thresholdValue_actionPerformed()
{
try
{
float f = Float.parseFloat(thresholdValue.getText());
slider.setValue((int) (f * scaleFactor));
threshline.value = f;
/*
* force repaint of any Overview window or structure
*/
ap.paintAlignment(true, true);
} catch (NumberFormatException ex)
{
}
}
/**
* Action on change of threshold slider value. This may be done interactively
* (by moving the slider), or programmatically (to update the slider after
* manual input of a threshold value).
*/
protected void sliderValueChanged()
{
/*
* squash rounding errors by forcing min/max of slider to
* actual min/max of feature score range
*/
int value = slider.getValue();
threshline.value = value == slider.getMaximum() ? max
: (value == slider.getMinimum() ? min : value / scaleFactor);
cs.setThreshold(threshline.value);
/*
* repaint alignment, but not Overview or structure,
* to avoid overload while dragging the slider
*/
changeColour(false);
}
void addActionListener(ActionListener graduatedColorEditor)
{
if (colourEditor != null)
{
System.err.println(
"IMPLEMENTATION ISSUE: overwriting action listener for FeatureColourChooser");
}
colourEditor = graduatedColorEditor;
}
/**
* Answers the last colour setting selected by user - either oldcs (which may
* be a java.awt.Color) or the new GraduatedColor
*
* @return
*/
FeatureColourI getLastColour()
{
if (cs == null)
{
return oldcs;
}
return cs;
}
/**
* A helper method to build the drop-down choice of attributes for a feature.
* Where metadata is available with a description for an attribute, that is
* added as a tooltip. The list may be restricted to attributes for which we
* hold a range of numerical values (so suitable candidates for a graduated
* colour scheme).
*
* @param featureType
* @param attNames
* @param withNumericRange
*/
protected JComboBox populateAttributesDropdown(
String featureType, List attNames,
boolean withNumericRange)
{
List validAtts = new ArrayList<>();
List tooltips = new ArrayList<>();
FeatureAttributes fa = FeatureAttributes.getInstance();
for (String attName : attNames)
{
if (withNumericRange)
{
float[] minMax = fa.getMinMax(featureType, attName);
if (minMax == null)
{
continue;
}
}
validAtts.add(attName);
String desc = fa.getDescription(featureType, attName);
if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
{
desc = desc.substring(0, MAX_TOOLTIP_LENGTH) + "...";
}
tooltips.add(desc == null ? "" : desc);
}
JComboBox attCombo = JvSwingUtils.buildComboWithTooltips(
validAtts, tooltips);
attCombo.addItemListener(new ItemListener()
{
@Override
public void itemStateChanged(ItemEvent e)
{
setAttributeMinMax(attCombo.getSelectedItem().toString());
changeColour(true);
}
});
if (validAtts.isEmpty())
{
attCombo.setToolTipText(MessageManager
.getString(withNumericRange ? "label.no_numeric_attributes"
: "label.no_attributes"));
}
return attCombo;
}
/**
* Updates the min-max range and scale to be that for the given attribute name
*
* @param attributeName
*/
protected void setAttributeMinMax(String attributeName)
{
float[] minMax = FeatureAttributes.getInstance().getMinMax(type,
attributeName);
if (minMax != null)
{
min = minMax[0];
max = minMax[1];
scaleFactor = (max == min) ? 1f : 100f / (max - min);
}
}
}