X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=src%2Fjalview%2Fgui%2FFeatureColourChooser.java;h=4172819a356e3708032ca4ebbf93e8e37baaefaf;hb=98f6651899fa88eed326ef6684b22e06e7a49c1a;hp=744f52ffe7d8891310b07c95a0cf29c6d2ae1073;hpb=b57a02c25e335d033c97f8a6bacd6b54f62bd2b6;p=jalview.git diff --git a/src/jalview/gui/FeatureColourChooser.java b/src/jalview/gui/FeatureColourChooser.java index 744f52f..4172819 100644 --- a/src/jalview/gui/FeatureColourChooser.java +++ b/src/jalview/gui/FeatureColourChooser.java @@ -1,139 +1,192 @@ /* - * Jalview - A Sequence Alignment Editor and Viewer (Version 2.7) - * Copyright (C) 2011 J Procter, AM Waterhouse, J Engelhardt, LM Lui, G Barton, M Clamp, S Searle + * 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. - * + * 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 . + * 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 java.util.*; - -import java.awt.*; -import java.awt.event.*; -import javax.swing.*; -import javax.swing.border.LineBorder; -import javax.swing.event.*; +import jalview.api.FeatureColourI; +import jalview.datamodel.GraphLine; +import jalview.schemes.FeatureColour; +import jalview.util.MessageManager; -import jalview.datamodel.*; -import jalview.schemes.*; +import java.awt.BorderLayout; +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.MouseAdapter; +import java.awt.event.MouseEvent; + +import javax.swing.BorderFactory; +import javax.swing.JCheckBox; +import javax.swing.JColorChooser; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JPanel; +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 { // FeatureSettings fs; - FeatureRenderer fr; + private FeatureRenderer fr; - private GraduatedColor cs; + private FeatureColourI cs; - private Object oldcs; + private FeatureColourI oldcs; - /** - * - * @return the last colour setting selected by user - either oldcs (which may - * be a java.awt.Color) or the new GraduatedColor - */ - public Object getLastColour() - { - if (cs == null) - { - return oldcs; - } - return cs; - } + private AlignmentPanel ap; - Hashtable oldgroupColours; + private boolean adjusting = false; - AlignmentPanel ap; + final private float min; - boolean adjusting = false; + final private float max; - private float min; + final private float scaleFactor; - private float max; + private String type = null; - String type = null; + private JPanel minColour = new JPanel(); - public FeatureColourChooser(FeatureRenderer frender, String type) + private JPanel maxColour = new JPanel(); + + private JComboBox threshold = new JComboBox<>(); + + private JSlider slider = new JSlider(); + + private JTextField thresholdValue = new JTextField(20); + + // TODO implement GUI for tolower flag + // JCheckBox toLower = new JCheckBox(); + + private JCheckBox thresholdIsMin = new JCheckBox(); + + private JCheckBox colourByLabel = new JCheckBox(); + + private GraphLine threshline; + + private Color oldmaxColour; + + private Color oldminColour; + + private ActionListener colourEditor = null; + + /** + * Constructor + * + * @param frender + * @param theType + */ + public FeatureColourChooser(FeatureRenderer frender, String theType) { - this(frender, false, type); + this(frender, false, theType); } - public FeatureColourChooser(FeatureRenderer frender, boolean block, - String type) + /** + * 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 = type; + this.type = theType; ap = fr.ap; - initDialogFrame(this, true, block, "Graduated Feature Colour for " - + type, 480, 185); - // frame.setLayer(JLayeredPane.PALETTE_LAYER); - // Desktop.addInternalFrame(frame, "Graduated Feature Colour for "+type, - // 480, 145); + String title = MessageManager.formatMessage( + "label.graduated_color_for_params", new String[] { theType }); + initDialogFrame(this, true, blocking, title, 480, 185); slider.addChangeListener(new ChangeListener() { + @Override public void stateChanged(ChangeEvent evt) { if (!adjusting) { - thresholdValue.setText(((float) slider.getValue() / 1000f) + ""); - valueChanged(); + 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); } - ; } }); - float mm[] = ((float[][]) fr.minmax.get(type))[0]; + float mm[] = fr.getMinMax().get(theType)[0]; min = mm[0]; max = mm[1]; - oldcs = fr.featureColours.get(type); - if (oldcs instanceof GraduatedColor) + + /* + * 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 (((GraduatedColor) oldcs).isAutoScale()) + if (oldcs.isAutoScaled()) { // update the scale - cs = new GraduatedColor((GraduatedColor) oldcs, min, max); + cs = new FeatureColour((FeatureColour) oldcs, min, max); } else { - cs = new GraduatedColor((GraduatedColor) oldcs); + cs = new FeatureColour((FeatureColour) oldcs); } } else { // promote original color to a graduated color - Color bl = Color.black; - if (oldcs instanceof Color) + Color bl = oldcs.getColour(); + if (bl == null) { - bl = (Color) oldcs; + bl = Color.BLACK; } // original colour becomes the maximum colour - cs = new GraduatedColor(Color.white, bl, mm[0], mm[1]); + cs = new FeatureColour(Color.white, bl, mm[0], mm[1]); cs.setColourByLabel(false); } - minColour.setBackground(oldminColour = cs.getMinColor()); - maxColour.setBackground(oldmaxColour = cs.getMaxColor()); + minColour.setBackground(oldminColour = cs.getMinColour()); + maxColour.setBackground(oldmaxColour = cs.getMaxColour()); adjusting = true; try @@ -143,47 +196,35 @@ public class FeatureColourChooser extends JalviewDialog { } // update the gui from threshold state - thresholdIsMin.setSelected(!cs.isAutoScale()); + thresholdIsMin.setSelected(!cs.isAutoScaled()); colourByLabel.setSelected(cs.isColourByLabel()); - if (cs.getThreshType() != AnnotationColourGradient.NO_THRESHOLD) + if (cs.hasThreshold()) { // initialise threshold slider and selector - threshold - .setSelectedIndex(cs.getThreshType() == AnnotationColourGradient.ABOVE_THRESHOLD ? 1 - : 2); + threshold.setSelectedIndex(cs.isAboveThreshold() ? 1 : 2); slider.setEnabled(true); + slider.setValue((int) (cs.getThreshold() * scaleFactor)); thresholdValue.setEnabled(true); - threshline = new jalview.datamodel.GraphLine((max - min) / 2f, - "Threshold", Color.black); - + threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black); + threshline.value = cs.getThreshold(); } adjusting = false; - changeColour(); + changeColour(false); waitForInput(); } - public FeatureColourChooser() - { - try - { - jbInit(); - } catch (Exception ex) - { - ex.printStackTrace(); - } - } - private void jbInit() throws Exception { minColour.setFont(JvSwingUtils.getLabelFont()); minColour.setBorder(BorderFactory.createLineBorder(Color.black)); minColour.setPreferredSize(new Dimension(40, 20)); - minColour.setToolTipText("Minimum Colour"); + minColour.setToolTipText(MessageManager.getString("label.min_colour")); minColour.addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent e) { if (minColour.isEnabled()) @@ -195,9 +236,10 @@ public class FeatureColourChooser extends JalviewDialog maxColour.setFont(JvSwingUtils.getLabelFont()); maxColour.setBorder(BorderFactory.createLineBorder(Color.black)); maxColour.setPreferredSize(new Dimension(40, 20)); - maxColour.setToolTipText("Maximum Colour"); + maxColour.setToolTipText(MessageManager.getString("label.max_colour")); maxColour.addMouseListener(new MouseAdapter() { + @Override public void mousePressed(MouseEvent e) { if (maxColour.isEnabled()) @@ -207,31 +249,41 @@ public class FeatureColourChooser extends JalviewDialog } }); maxColour.setBorder(new LineBorder(Color.black)); - minText.setText("Min:"); + JLabel minText = new JLabel(MessageManager.getString("label.min")); minText.setFont(JvSwingUtils.getLabelFont()); - maxText.setText("Max:"); + JLabel maxText = new JLabel(MessageManager.getString("label.max")); maxText.setFont(JvSwingUtils.getLabelFont()); - this.setLayout(borderLayout1); - jPanel2.setLayout(flowLayout1); + this.setLayout(new BorderLayout()); + JPanel jPanel1 = new JPanel(); jPanel1.setBackground(Color.white); + JPanel jPanel2 = new JPanel(); + jPanel2.setLayout(new FlowLayout()); jPanel2.setBackground(Color.white); threshold.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - threshold_actionPerformed(e); + threshold_actionPerformed(); } }); - threshold.setToolTipText("Threshold the feature display by score."); - threshold.addItem("No Threshold"); // index 0 - threshold.addItem("Above Threshold"); // index 1 - threshold.addItem("Below Threshold"); // index 2 - jPanel3.setLayout(flowLayout2); + 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 + + JPanel jPanel3 = new JPanel(); + jPanel3.setLayout(new FlowLayout()); thresholdValue.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent e) { - thresholdValue_actionPerformed(e); + thresholdValue_actionPerformed(); } }); slider.setPaintLabels(false); @@ -240,118 +292,102 @@ public class FeatureColourChooser extends JalviewDialog slider.setEnabled(false); slider.setOpaque(false); slider.setPreferredSize(new Dimension(100, 32)); - slider.setToolTipText("Adjust threshold"); + slider.setToolTipText(MessageManager + .getString("label.adjust_threshold")); thresholdValue.setEnabled(false); thresholdValue.setColumns(7); jPanel3.setBackground(Color.white); thresholdIsMin.setBackground(Color.white); - thresholdIsMin.setText("Threshold is Min/Max"); - thresholdIsMin - .setToolTipText("Toggle between absolute and relative display threshold."); + thresholdIsMin.setText(MessageManager + .getString("label.threshold_minmax")); + thresholdIsMin.setToolTipText(MessageManager + .getString("label.toggle_absolute_relative_display_threshold")); thresholdIsMin.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent actionEvent) { - thresholdIsMin_actionPerformed(actionEvent); + thresholdIsMin_actionPerformed(); } }); colourByLabel.setBackground(Color.white); - colourByLabel.setText("Colour by Label"); colourByLabel - .setToolTipText("Display features of the same type with a different label using a different colour. (e.g. domain features)"); + .setText(MessageManager.getString("label.colour_by_label")); + colourByLabel + .setToolTipText(MessageManager + .getString("label.display_features_same_type_different_label_using_different_colour")); colourByLabel.addActionListener(new ActionListener() { + @Override public void actionPerformed(ActionEvent actionEvent) { - colourByLabel_actionPerformed(actionEvent); + colourByLabel_actionPerformed(); } }); + + JPanel colourPanel = new JPanel(); colourPanel.setBackground(Color.white); jPanel1.add(ok); jPanel1.add(cancel); - jPanel2.add(colourByLabel, java.awt.BorderLayout.WEST); - jPanel2.add(colourPanel, java.awt.BorderLayout.EAST); + jPanel2.add(colourByLabel, BorderLayout.WEST); + jPanel2.add(colourPanel, BorderLayout.EAST); colourPanel.add(minText); colourPanel.add(minColour); colourPanel.add(maxText); colourPanel.add(maxColour); - this.add(jPanel3, java.awt.BorderLayout.CENTER); + this.add(jPanel3, BorderLayout.CENTER); jPanel3.add(threshold); jPanel3.add(slider); jPanel3.add(thresholdValue); jPanel3.add(thresholdIsMin); - this.add(jPanel1, java.awt.BorderLayout.SOUTH); - this.add(jPanel2, java.awt.BorderLayout.NORTH); + this.add(jPanel1, BorderLayout.SOUTH); + this.add(jPanel2, BorderLayout.NORTH); } - JLabel minText = new JLabel(); - - JLabel maxText = new JLabel(); - - JPanel minColour = new JPanel(); - - JPanel maxColour = new JPanel(); - - JPanel colourPanel = new JPanel(); - - JPanel jPanel1 = new JPanel(); - - JPanel jPanel2 = new JPanel(); - - BorderLayout borderLayout1 = new BorderLayout(); - - JComboBox threshold = new JComboBox(); - - FlowLayout flowLayout1 = new FlowLayout(); - - JPanel jPanel3 = new JPanel(); - - FlowLayout flowLayout2 = new FlowLayout(); - - JSlider slider = new JSlider(); - - JTextField thresholdValue = new JTextField(20); - - // TODO implement GUI for tolower flag - // JCheckBox toLower = new JCheckBox(); - - JCheckBox thresholdIsMin = new JCheckBox(); - - JCheckBox colourByLabel = new JCheckBox(); - - private GraphLine threshline; - - private Color oldmaxColour; - - private Color oldminColour; - - public void minColour_actionPerformed() + /** + * 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, - "Select Colour for Minimum Value", minColour.getBackground()); + MessageManager.getString("label.select_colour_minimum_value"), + minColour.getBackground()); if (col != null) { minColour.setBackground(col); minColour.setForeground(col); } minColour.repaint(); - changeColour(); + changeColour(true); } - public void maxColour_actionPerformed() + /** + * 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, - "Select Colour for Maximum Value", maxColour.getBackground()); + MessageManager.getString("label.select_colour_maximum_value"), + maxColour.getBackground()); if (col != null) { maxColour.setBackground(col); maxColour.setForeground(col); } maxColour.repaint(); - changeColour(); + changeColour(true); } - void changeColour() + /** + * 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 updateOverview + */ + void changeColour(boolean updateOverview) { // Check if combobox is still adjusting if (adjusting) @@ -359,56 +395,58 @@ public class FeatureColourChooser extends JalviewDialog return; } - int aboveThreshold = AnnotationColourGradient.NO_THRESHOLD; - if (threshold.getSelectedItem().equals("Above Threshold")) + boolean aboveThreshold = false; + boolean belowThreshold = false; + if (threshold.getSelectedIndex() == 1) { - aboveThreshold = AnnotationColourGradient.ABOVE_THRESHOLD; + aboveThreshold = true; } - else if (threshold.getSelectedItem().equals("Below Threshold")) + else if (threshold.getSelectedIndex() == 2) { - aboveThreshold = AnnotationColourGradient.BELOW_THRESHOLD; + belowThreshold = true; } + boolean hasThreshold = aboveThreshold || belowThreshold; slider.setEnabled(true); thresholdValue.setEnabled(true); - GraduatedColor acg; + FeatureColourI acg; if (cs.isColourByLabel()) { - acg = new GraduatedColor(oldminColour, oldmaxColour, min, max); + acg = new FeatureColour(oldminColour, oldmaxColour, min, max); } else { - acg = new GraduatedColor(oldminColour = minColour.getBackground(), + acg = new FeatureColour(oldminColour = minColour.getBackground(), oldmaxColour = maxColour.getBackground(), min, max); - } - if (aboveThreshold == AnnotationColourGradient.NO_THRESHOLD) + if (!hasThreshold) { slider.setEnabled(false); thresholdValue.setEnabled(false); thresholdValue.setText(""); thresholdIsMin.setEnabled(false); } - else if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD - && threshline == null) + else if (threshline == null) { - // todo visual indication of feature threshold - threshline = new jalview.datamodel.GraphLine((max - min) / 2f, - "Threshold", Color.black); + /* + * todo not yet implemented: visual indication of feature threshold + */ + threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black); } - if (aboveThreshold != AnnotationColourGradient.NO_THRESHOLD) + if (hasThreshold) { adjusting = true; - acg.setThresh(threshline.value); + acg.setThreshold(threshline.value); - float range = max * 1000f - min * 1000f; + float range = (max - min) * scaleFactor; - slider.setMinimum((int) (min * 1000)); - slider.setMaximum((int) (max * 1000)); - slider.setValue((int) (threshline.value * 1000)); + 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); @@ -417,18 +455,18 @@ public class FeatureColourChooser extends JalviewDialog adjusting = false; } - acg.setThreshType(aboveThreshold); - if (thresholdIsMin.isSelected() - && aboveThreshold != AnnotationColourGradient.NO_THRESHOLD) + acg.setAboveThreshold(aboveThreshold); + acg.setBelowThreshold(belowThreshold); + if (thresholdIsMin.isSelected() && hasThreshold) { acg.setAutoScaled(false); - if (aboveThreshold == AnnotationColourGradient.ABOVE_THRESHOLD) + if (aboveThreshold) { - acg = new GraduatedColor(acg, threshline.value, max); + acg = new FeatureColour((FeatureColour) acg, threshline.value, max); } else { - acg = new GraduatedColor(acg, min, threshline.value); + acg = new FeatureColour((FeatureColour) acg, min, threshline.value); } } else @@ -455,11 +493,12 @@ public class FeatureColourChooser extends JalviewDialog maxColour.setForeground(oldmaxColour); minColour.setForeground(oldminColour); } - fr.featureColours.put(type, acg); + fr.setColour(type, acg); cs = acg; - ap.paintAlignment(false); + ap.paintAlignment(updateOverview); } + @Override protected void raiseClosed() { if (this.colourEditor != null) @@ -468,71 +507,92 @@ public class FeatureColourChooser extends JalviewDialog } } + @Override public void okPressed() { - changeColour(); + 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.featureColours.put(type, oldcs); - ap.paintAlignment(false); + fr.setColour(type, oldcs); + ap.paintAlignment(true); cs = null; } - public void thresholdCheck_actionPerformed(ActionEvent e) - { - changeColour(); - } - - public void annotations_actionPerformed(ActionEvent e) - { - changeColour(); - } - - public void threshold_actionPerformed(ActionEvent e) + /** + * Action on change of choice of No / Above / Below Threshold + */ + protected void threshold_actionPerformed() { - changeColour(); + changeColour(true); } - public void thresholdValue_actionPerformed(ActionEvent e) + /** + * Action on text entry of a threshold value + */ + protected void thresholdValue_actionPerformed() { try { float f = Float.parseFloat(thresholdValue.getText()); - slider.setValue((int) (f * 1000)); + slider.setValue((int) (f * scaleFactor)); threshline.value = f; + + /* + * force repaint of any Overview window or structure + */ + ap.paintAlignment(true); } catch (NumberFormatException ex) { } } - public void valueChanged() + /** + * 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() { - threshline.value = (float) slider.getValue() / 1000f; - cs.setThresh(threshline.value); - changeColour(); - ap.paintAlignment(false); + /* + * 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); } - public void thresholdIsMin_actionPerformed(ActionEvent actionEvent) + protected void thresholdIsMin_actionPerformed() { - changeColour(); + changeColour(true); } - public void colourByLabel_actionPerformed(ActionEvent actionEvent) + protected void colourByLabel_actionPerformed() { - changeColour(); + changeColour(true); } - ActionListener colourEditor = null; - - public void addActionListener(ActionListener graduatedColorEditor) + void addActionListener(ActionListener graduatedColorEditor) { if (colourEditor != null) { @@ -542,4 +602,19 @@ public class FeatureColourChooser extends JalviewDialog 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; + } + }