JAL-2835 spike updated with latest
[jalview.git] / src / jalview / gui / FeatureColourChooser.java
index 3fc3116..da3819c 100644 (file)
@@ -47,9 +47,7 @@ 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;
@@ -59,8 +57,16 @@ import javax.swing.event.ChangeListener;
 
 public class FeatureColourChooser extends JalviewDialog
 {
+  private static final String COLON = ":";
+
   private static final int MAX_TOOLTIP_LENGTH = 50;
 
+  private static int NO_COLOUR_OPTION = 0;
+
+  private static int MIN_COLOUR_OPTION = 1;
+
+  private static int MAX_COLOUR_OPTION = 2;
+
   private FeatureRenderer fr;
 
   private FeatureColourI cs;
@@ -83,7 +89,7 @@ public class FeatureColourChooser extends JalviewDialog
 
   private JPanel maxColour = new JPanel();
 
-  private JPanel noColour = new JPanel();
+  private Color noColour;
 
   private JComboBox<String> threshold = new JComboBox<>();
 
@@ -117,6 +123,13 @@ public class FeatureColourChooser extends JalviewDialog
 
   private ActionListener changeColourAction;
 
+  private ActionListener changeMinMaxAction;
+
+  /*
+   * choice of option for 'colour for no value'
+   */
+  private JComboBox<String> noValueCombo;
+
   /*
    * choice of attribute (if any) for 'colour by text'
    */
@@ -152,10 +165,9 @@ public class FeatureColourChooser extends JalviewDialog
     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);
+    String title = MessageManager.formatMessage("label.variable_color_for",
+            new String[] { theType });
+    initDialogFrame(this, true, blocking, title, 470, 300);
 
     slider.addChangeListener(new ChangeListener()
     {
@@ -185,6 +197,7 @@ public class FeatureColourChooser extends JalviewDialog
       }
     });
 
+    // todo move all threshold setup inside a method
     float mm[] = fr.getMinMax().get(theType)[0];
     min = mm[0];
     max = mm[1];
@@ -226,7 +239,8 @@ public class FeatureColourChooser extends JalviewDialog
     }
     minColour.setBackground(oldminColour = cs.getMinColour());
     maxColour.setBackground(oldmaxColour = cs.getMaxColour());
-    noColour.setBackground(oldNoColour = cs.getNoColour());
+    noColour = cs.getNoColour();
+
     adjusting = true;
 
     try
@@ -241,15 +255,15 @@ public class FeatureColourChooser extends JalviewDialog
     /*
      * 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());
+        String[] attributeName = cs.getAttributeName();
+        textAttributeCombo
+                .setSelectedItem(String.join(COLON, attributeName));
       }
       else
       {
@@ -262,10 +276,11 @@ public class FeatureColourChooser extends JalviewDialog
       if (cs.isColourByAttribute())
       {
         byAttributeValue.setSelected(true);
-        String attributeName = cs.getAttributeName();
-        valueAttributeCombo.setSelectedItem(attributeName);
+        String[] attributeName = cs.getAttributeName();
+        valueAttributeCombo
+                .setSelectedItem(String.join(COLON, attributeName));
         valueAttributeCombo.setEnabled(true);
-        setAttributeMinMax(attributeName);
+        updateMinMax();
       }
       else
       {
@@ -274,6 +289,22 @@ public class FeatureColourChooser extends JalviewDialog
       }
     }
 
+    if (noColour == null)
+    {
+      noValueCombo.setSelectedIndex(NO_COLOUR_OPTION);
+    }
+    else if (noColour.equals(oldminColour))
+    {
+      noValueCombo.setSelectedIndex(MIN_COLOUR_OPTION);
+    }
+    else if (noColour.equals(oldmaxColour))
+    {
+      noValueCombo.setSelectedIndex(MAX_COLOUR_OPTION);
+    }
+
+    threshline = new GraphLine((max - min) / 2f, "Threshold", Color.black);
+    threshline.value = cs.getThreshold();
+
     if (cs.hasThreshold())
     {
       // initialise threshold slider and selector
@@ -281,9 +312,6 @@ public class FeatureColourChooser extends JalviewDialog
       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;
@@ -300,7 +328,8 @@ public class FeatureColourChooser extends JalviewDialog
     this.setLayout(new BoxLayout(this, BoxLayout.Y_AXIS));
     this.setBackground(Color.white);
 
-    changeColourAction = new ActionListener() {
+    changeColourAction = new ActionListener()
+    {
       @Override
       public void actionPerformed(ActionEvent e)
       {
@@ -308,6 +337,16 @@ public class FeatureColourChooser extends JalviewDialog
       }
     };
 
+    changeMinMaxAction = new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        updateMinMax();
+        changeColour(true);
+      }
+    };
+
     /*
      * this panel
      *     detailsPanel
@@ -341,6 +380,32 @@ public class FeatureColourChooser extends JalviewDialog
   }
 
   /**
+   * Updates the min-max range for a change in choice of Colour by Score, or
+   * Colour by Attribute (value)
+   */
+  protected void updateMinMax()
+  {
+    float[] minMax = null;
+    if (byScore.isSelected())
+    {
+      minMax = fr.getMinMax().get(type)[0];
+    }
+    else if (byAttributeValue.isSelected())
+    {
+      String attName = (String) valueAttributeCombo.getSelectedItem();
+      String[] attNames = attName.split(COLON);
+      minMax = FeatureAttributes.getInstance().getMinMax(type, attNames);
+    }
+    if (minMax != null)
+    {
+      min = minMax[0];
+      max = minMax[1];
+      scaleFactor = (max == min) ? 1f : 100f / (max - min);
+      slider.setValue((int) (min * scaleFactor));
+    }
+  }
+
+  /**
    * Lay out fields for graduated colour by value
    * 
    * @return
@@ -349,8 +414,8 @@ public class FeatureColourChooser extends JalviewDialog
   {
     JPanel byValuePanel = new JPanel();
     byValuePanel.setLayout(new BoxLayout(byValuePanel, BoxLayout.Y_AXIS));
-    byValuePanel.setBorder(BorderFactory.createTitledBorder(MessageManager
-            .getString("label.colour_by_value")));
+    JvSwingUtils.createItalicTitledBorder(byValuePanel,
+            MessageManager.getString("label.colour_by_value"), true);
     byValuePanel.setBackground(Color.white);
 
     /*
@@ -362,17 +427,15 @@ public class FeatureColourChooser extends JalviewDialog
 
     byScore.setText(MessageManager.getString("label.score"));
     byWhatPanel.add(byScore);
-    byScore.addActionListener(changeColourAction);
+    byScore.addActionListener(changeMinMaxAction);
 
-    byAttributeValue.setText(MessageManager
-.getString("label.attribute"));
-    byAttributeValue.addActionListener(changeColourAction);
+    byAttributeValue.setText(MessageManager.getString("label.attribute"));
+    byAttributeValue.addActionListener(changeMinMaxAction);
     byWhatPanel.add(byAttributeValue);
 
-    List<String> attNames = FeatureAttributes.getInstance().getAttributes(
-            type);
-    valueAttributeCombo = populateAttributesDropdown(type, attNames,
-            true);
+    List<String[]> attNames = FeatureAttributes.getInstance()
+            .getAttributes(type);
+    valueAttributeCombo = populateAttributesDropdown(type, attNames, true);
 
     /*
      * if no numeric atttibutes found, disable colour by attribute value
@@ -424,44 +487,24 @@ public class FeatureColourChooser extends JalviewDialog
     });
     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()
+    noValueCombo = new JComboBox<>();
+    noValueCombo.addItem(MessageManager.getString("label.no_colour"));
+    noValueCombo.addItem(MessageManager.getString("label.min_colour"));
+    noValueCombo.addItem(MessageManager.getString("label.max_colour"));
+    noValueCombo.addItemListener(new ItemListener()
     {
       @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)
+      public void itemStateChanged(ItemEvent e)
       {
-        if (e.isPopupTrigger()) // Windows: mouseReleased
-        {
-          showNoColourPopup(e);
-          e.consume();
-          return;
-        }
+        setNoValueColour();
       }
     });
-    noColour.setBorder(new LineBorder(Color.black));
 
-    JLabel minText = new JLabel(MessageManager.getString("label.min"));
+    JLabel minText = new JLabel(MessageManager.getString("label.min_value"));
     minText.setFont(JvSwingUtils.getLabelFont());
-    JLabel maxText = new JLabel(MessageManager.getString("label.max"));
+    JLabel maxText = new JLabel(MessageManager.getString("label.max_value"));
     maxText.setFont(JvSwingUtils.getLabelFont());
-    JLabel noText = new JLabel(MessageManager.getString("label.no_colour"));
+    JLabel noText = new JLabel(MessageManager.getString("label.no_value"));
     noText.setFont(JvSwingUtils.getLabelFont());
 
     colourRangePanel.add(minText);
@@ -469,7 +512,7 @@ public class FeatureColourChooser extends JalviewDialog
     colourRangePanel.add(maxText);
     colourRangePanel.add(maxColour);
     colourRangePanel.add(noText);
-    colourRangePanel.add(noColour);
+    colourRangePanel.add(noValueCombo);
 
     /*
      * third row - threshold options and value
@@ -510,8 +553,8 @@ public class FeatureColourChooser extends JalviewDialog
     slider.setEnabled(false);
     slider.setOpaque(false);
     slider.setPreferredSize(new Dimension(100, 32));
-    slider.setToolTipText(
-            MessageManager.getString("label.adjust_threshold"));
+    slider.setToolTipText(MessageManager
+            .getString("label.adjust_threshold"));
     thresholdValue.setEnabled(false);
     thresholdValue.setColumns(7);
 
@@ -526,8 +569,8 @@ public class FeatureColourChooser extends JalviewDialog
     isMinMaxPanel.setBackground(Color.white);
     byValuePanel.add(isMinMaxPanel);
     thresholdIsMin.setBackground(Color.white);
-    thresholdIsMin
-            .setText(MessageManager.getString("label.threshold_minmax"));
+    thresholdIsMin.setText(MessageManager
+            .getString("label.threshold_minmax"));
     thresholdIsMin.setToolTipText(MessageManager
             .getString("label.toggle_absolute_relative_display_threshold"));
     thresholdIsMin.addActionListener(changeColourAction);
@@ -537,42 +580,25 @@ public class FeatureColourChooser extends JalviewDialog
   }
 
   /**
-   * Show a popup menu with options to make 'no value colour' the same as Min
-   * Colour or Max Colour
-   * 
-   * @param evt
+   * Action on user choice of no / min / max colour to use when there is no
+   * value to colour by
    */
-  protected void showNoColourPopup(MouseEvent evt)
+  protected void setNoValueColour()
   {
-    JPopupMenu pop = new JPopupMenu();
-
-    JMenuItem copyMin = new JMenuItem(
-            MessageManager.getString("label.min_colour"));
-    copyMin.addActionListener((new ActionListener()
+    int i = noValueCombo.getSelectedIndex();
+    if (i == NO_COLOUR_OPTION)
     {
-      @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()
+      noColour = null;
+    }
+    else if (i == MIN_COLOUR_OPTION)
     {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        noColour.setBackground(maxColour.getBackground());
-        changeColour(true);
-      }
-    }));
-    pop.add(copyMax);
-
-    pop.show(noColour, evt.getX(), evt.getY());
+      noColour = minColour.getBackground();
+    }
+    else if (i == MAX_COLOUR_OPTION)
+    {
+      noColour = maxColour.getBackground();
+    }
+    changeColour(true);
   }
 
   /**
@@ -598,8 +624,8 @@ public class FeatureColourChooser extends JalviewDialog
   {
     JPanel byTextPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
     byTextPanel.setBackground(Color.white);
-    byTextPanel.setBorder(BorderFactory.createTitledBorder(MessageManager
-            .getString("label.colour_by_text")));
+    JvSwingUtils.createItalicTitledBorder(byTextPanel,
+            MessageManager.getString("label.colour_by_text"), true);
 
     byDescription.setText(MessageManager.getString("label.label"));
     byDescription.setToolTipText(MessageManager
@@ -611,8 +637,8 @@ public class FeatureColourChooser extends JalviewDialog
     byAttributeText.addActionListener(changeColourAction);
     byTextPanel.add(byAttributeText);
 
-    List<String> attNames = FeatureAttributes.getInstance().getAttributes(
-            type);
+    List<String[]> attNames = FeatureAttributes.getInstance()
+            .getAttributes(type);
     textAttributeCombo = populateAttributesDropdown(type, attNames, false);
     byTextPanel.add(textAttributeCombo);
 
@@ -664,24 +690,6 @@ public class FeatureColourChooser extends JalviewDialog
   }
 
   /**
-   * 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
@@ -723,7 +731,7 @@ public class FeatureColourChooser extends JalviewDialog
     {
       acg = new FeatureColour(oldminColour = minColour.getBackground(),
               oldmaxColour = maxColour.getBackground(),
-              oldNoColour = noColour.getBackground(), min, max);
+              oldNoColour = noColour, min, max);
     }
     String attribute = null;
     textAttributeCombo.setEnabled(false);
@@ -732,13 +740,18 @@ public class FeatureColourChooser extends JalviewDialog
     {
       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);
     }
-    acg.setAttributeName(attribute);
 
     if (!hasThreshold)
     {
@@ -800,25 +813,22 @@ public class FeatureColourChooser extends JalviewDialog
     {
       maxColour.setEnabled(false);
       minColour.setEnabled(false);
-      noColour.setEnabled(false);
+      noValueCombo.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);
+      noValueCombo.setEnabled(true);
       maxColour.setBackground(oldmaxColour);
       maxColour.setForeground(oldmaxColour);
       minColour.setBackground(oldminColour);
       minColour.setForeground(oldminColour);
-      noColour.setBackground(oldNoColour);
-      noColour.setForeground(oldNoColour);
+      noColour = oldNoColour;
     }
 
     /*
@@ -933,23 +943,26 @@ public class FeatureColourChooser extends JalviewDialog
   /**
    * 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).
+   * 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).
+   * <p>
+   * 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<String> populateAttributesDropdown(
-          String featureType, List<String> attNames,
+          String featureType, List<String[]> attNames,
           boolean withNumericRange)
   {
     List<String> validAtts = new ArrayList<>();
     List<String> tooltips = new ArrayList<>();
 
     FeatureAttributes fa = FeatureAttributes.getInstance();
-    for (String attName : attNames)
+    for (String[] attName : attNames)
     {
       if (withNumericRange)
       {
@@ -959,7 +972,7 @@ public class FeatureColourChooser extends JalviewDialog
           continue;
         }
       }
-      validAtts.add(attName);
+      validAtts.add(String.join(COLON, attName));
       String desc = fa.getDescription(featureType, attName);
       if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
       {
@@ -976,8 +989,7 @@ public class FeatureColourChooser extends JalviewDialog
       @Override
       public void itemStateChanged(ItemEvent e)
       {
-        setAttributeMinMax(attCombo.getSelectedItem().toString());
-        changeColour(true);
+        changeMinMaxAction.actionPerformed(null);
       }
     });
 
@@ -991,21 +1003,4 @@ public class FeatureColourChooser extends JalviewDialog
     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);
-    }
-  }
-
 }