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);
}
/**
* 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, min, max);
}
String attribute = null;
textAttributeCombo.setEnabled(false);
valueAttributeCombo.setEnabled(false);
if (byAttributeText.isSelected())
{
attribute = (String) textAttributeCombo.getSelectedItem();
textAttributeCombo.setEnabled(true);
acg.setAttributeName(attribute.split(COLON));
}
else if (byAttributeValue.isSelected())
{
attribute = (String) valueAttributeCombo.getSelectedItem();
valueAttributeCombo.setEnabled(true);
acg.setAttributeName(attribute.split(COLON));
}
else
{
acg.setAttributeName((String) null);
}
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);
noValueCombo.setEnabled(false);
maxColour.setBackground(this.getBackground());
maxColour.setForeground(this.getBackground());
minColour.setBackground(this.getBackground());
minColour.setForeground(this.getBackground());
}
else
{
maxColour.setEnabled(true);
minColour.setEnabled(true);
noValueCombo.setEnabled(true);
maxColour.setBackground(oldmaxColour);
maxColour.setForeground(oldmaxColour);
minColour.setBackground(oldminColour);
minColour.setForeground(oldminColour);
noColour = 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 optionally be restricted to attributes for
* which we hold a range of numerical values (so suitable candidates for a
* graduated colour scheme).
*
* Attribute names may be 'simple' e.g. "AC" or 'compound' e.g. {"CSQ",
* "Allele"}. Compound names are rendered for display as (e.g.) CSQ:Allele.
*
* @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(String.join(COLON, 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)
{
changeMinMaxAction.actionPerformed(null);
}
});
if (validAtts.isEmpty())
{
attCombo.setToolTipText(MessageManager
.getString(withNumericRange ? "label.no_numeric_attributes"
: "label.no_attributes"));
}
return attCombo;
}
}