JAL-2808 update spike to latest (filter range tooltip, Present condition)
[jalview.git] / src / jalview / gui / FeatureTypeSettings.java
index 1dd12aa..835f1fc 100644 (file)
@@ -25,14 +25,14 @@ import jalview.api.FeatureColourI;
 import jalview.datamodel.GraphLine;
 import jalview.datamodel.features.FeatureAttributes;
 import jalview.datamodel.features.FeatureAttributes.Datatype;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherI;
+import jalview.datamodel.features.FeatureMatcherSet;
+import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.schemes.FeatureColour;
 import jalview.util.ColorUtils;
 import jalview.util.MessageManager;
 import jalview.util.matcher.Condition;
-import jalview.util.matcher.KeyedMatcher;
-import jalview.util.matcher.KeyedMatcherI;
-import jalview.util.matcher.KeyedMatcherSet;
-import jalview.util.matcher.KeyedMatcherSetI;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -115,7 +115,7 @@ public class FeatureTypeSettings extends JalviewDialog
    */
   private final FeatureColourI originalColour;
 
-  private final KeyedMatcherSetI originalFilter;
+  private final FeatureMatcherSetI originalFilter;
 
   /*
    * set flag to true when setting values programmatically,
@@ -123,10 +123,20 @@ public class FeatureTypeSettings extends JalviewDialog
    */
   private boolean adjusting = false;
 
+  /*
+   * minimum of the value range for graduated colour
+   * (may be for feature score or for a numeric attribute)
+   */
   private float min;
 
+  /*
+   * maximum of the value range for graduated colour
+   */
   private float max;
 
+  /*
+   * scale factor for conversion between absolute min-max and slider
+   */
   private float scaleFactor;
 
   /*
@@ -181,7 +191,7 @@ public class FeatureTypeSettings extends JalviewDialog
   /*
    * filters for the currently selected feature type
    */
-  private List<KeyedMatcherI> filters;
+  private List<FeatureMatcherI> filters;
 
   // set white normally, black to debug layout
   private Color debugBorderColour = Color.white;
@@ -426,32 +436,48 @@ public class FeatureTypeSettings extends JalviewDialog
    * Updates the min-max range if Colour By selected item is Score, or an
    * attribute, with a min-max range
    */
-  protected void updateMinMax()
+  protected void updateColourMinMax()
   {
     if (!graduatedColour.isSelected())
     {
       return;
     }
 
-    float[] minMax = null;
     String colourBy = (String) colourByRangeCombo.getSelectedItem();
-    if (MessageManager.getString("label.score").equals(colourBy))
+    String[] attNames = fromAttributeDisplayName(colourBy);
+    float[] minMax = getMinMax(attNames);
+
+    if (minMax != null)
+    {
+      min = minMax[0];
+      max = minMax[1];
+    }
+  }
+
+  /**
+   * Retrieves the min-max range:
+   * <ul>
+   * <li>of feature score, if colour or filter is by Score</li>
+   * <li>else of the selected attribute</li>
+   * </ul>
+   * 
+   * @param attNames
+   * @return
+   */
+  private float[] getMinMax(String[] attNames)
+  {
+    float[] minMax = null;
+    if (MessageManager.getString("label.score").equals(attNames[0]))
     {
       minMax = fr.getMinMax().get(featureType)[0];
     }
     else
     {
       // colour by attribute range
-      String[] attNames = fromAttributeDisplayName(colourBy);
       minMax = FeatureAttributes.getInstance().getMinMax(featureType,
               attNames);
     }
-
-    if (minMax != null)
-    {
-      min = minMax[0];
-      max = minMax[1];
-    }
+    return minMax;
   }
 
   /**
@@ -839,7 +865,7 @@ public class FeatureTypeSettings extends JalviewDialog
      * ensure min-max range is for the latest choice of 
      * 'graduated colour by'
      */
-    updateMinMax();
+    updateColourMinMax();
 
     FeatureColourI acg = makeColourFromInputs();
 
@@ -1228,7 +1254,7 @@ public class FeatureTypeSettings extends JalviewDialog
     /*
      * if this feature type has filters set, load them first
      */
-    KeyedMatcherSetI featureFilters = fr.getFeatureFilter(featureType);
+    FeatureMatcherSetI featureFilters = fr.getFeatureFilter(featureType);
     if (featureFilters != null)
     {
       if (!featureFilters.isAnded())
@@ -1241,15 +1267,15 @@ public class FeatureTypeSettings extends JalviewDialog
     /*
      * and an empty filter for the user to populate (add)
      */
-    KeyedMatcherI noFilter = new KeyedMatcher(Condition.values()[0], "",
-            (String[]) null);
+    FeatureMatcherI noFilter = FeatureMatcher.byLabel(Condition.values()[0],
+            "");
     filters.add(noFilter);
 
     /*
      * render the conditions in rows, each in its own JPanel
      */
     int filterIndex = 0;
-    for (KeyedMatcherI filter : filters)
+    for (FeatureMatcherI filter : filters)
     {
       String[] attName = filter.getKey();
       Condition condition = filter.getMatcher().getCondition();
@@ -1307,11 +1333,10 @@ public class FeatureTypeSettings extends JalviewDialog
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        if (attCombo.getSelectedItem() != null)
+        if (validateFilter(patternField, condCombo))
         {
-          if (validateFilter(patternField, condCombo))
+          if (updateFilter(attCombo, condCombo, patternField, filterIndex))
           {
-            updateFilter(attCombo, condCombo, patternField, filterIndex);
             filtersChanged();
           }
         }
@@ -1379,8 +1404,7 @@ public class FeatureTypeSettings extends JalviewDialog
      * disable pattern field for condition 'Present / NotPresent'
      */
     Condition selectedCondition = (Condition) condCombo.getSelectedItem();
-    if (selectedCondition == Condition.Present
-            || selectedCondition == Condition.NotPresent)
+    if (!selectedCondition.needsAPattern())
     {
       patternField.setEnabled(false);
     }
@@ -1389,22 +1413,13 @@ public class FeatureTypeSettings extends JalviewDialog
      * if a numeric condition is selected, show the value range
      * as a tooltip on the value input field
      */
-    if (selectedCondition.isNumeric())
-    {
-      float[] minMax = FeatureAttributes.getInstance()
-              .getMinMax(featureType, attName);
-      if (minMax != null)
-      {
-        String tip = String.format("(%s - %s)",
-                DECFMT_2_2.format(minMax[0]), DECFMT_2_2.format(minMax[1]));
-        patternField.setToolTipText(tip);
-      }
-    }
+    updatePatternTooltip(attName, selectedCondition, patternField);
 
     /*
      * add remove button if filter is populated (non-empty pattern)
      */
-    if (pattern != null && pattern.trim().length() > 0)
+    if (!patternField.isEnabled()
+            || (pattern != null && pattern.trim().length() > 0))
     {
       // todo: gif for button drawing '-' or 'x'
       JButton removeCondition = new BasicArrowButton(SwingConstants.WEST);
@@ -1426,6 +1441,31 @@ public class FeatureTypeSettings extends JalviewDialog
   }
 
   /**
+   * If a numeric comparison condition is selected, retrieve the min-max range for
+   * the value (score or attribute), and set it as a tooltip on the value file
+   * 
+   * @param attName
+   * @param selectedCondition
+   * @param patternField
+   */
+  private void updatePatternTooltip(String[] attName,
+          Condition selectedCondition, JTextField patternField)
+  {
+    patternField.setToolTipText("");
+
+    if (selectedCondition.isNumeric())
+    {
+      float[] minMax = getMinMax(attName);
+      if (minMax != null)
+      {
+        String tip = String.format("(%s - %s)",
+                DECFMT_2_2.format(minMax[0]), DECFMT_2_2.format(minMax[1]));
+        patternField.setToolTipText(tip);
+      }
+    }
+  }
+
+  /**
    * Populates the drop-down list of comparison conditions for the given attribute
    * name. The conditions added depend on the datatype of the attribute values.
    * The supplied condition is set as the selected item in the list, provided it
@@ -1504,7 +1544,7 @@ public class FeatureTypeSettings extends JalviewDialog
     }
 
     Condition cond = (Condition) condCombo.getSelectedItem();
-    if (cond == Condition.Present || cond == Condition.NotPresent)
+    if (cond.needsAPattern())
     {
       return true;
     }
@@ -1514,10 +1554,10 @@ public class FeatureTypeSettings extends JalviewDialog
     String v1 = value.getText().trim();
     if (v1.length() == 0)
     {
-      return false;
+      // return false;
     }
 
-    if (cond.isNumeric())
+    if (cond.isNumeric() && v1.length() > 0)
     {
       try
       {
@@ -1536,24 +1576,58 @@ public class FeatureTypeSettings extends JalviewDialog
 
   /**
    * Constructs a filter condition from the given input fields, and replaces the
-   * condition at filterIndex with the new one
+   * condition at filterIndex with the new one. Does nothing if the pattern field
+   * is blank (unless the match condition is one that doesn't require a pattern,
+   * e.g. 'Is present'). Answers true if the filter was updated, else false.
+   * <p>
+   * This method may update the tooltip on the filter value field to show the
+   * value range, if a numeric condition is selected. This ensures the tooltip is
+   * updated when a numeric valued attribute is chosen on the last 'add a filter'
+   * row.
    * 
    * @param attCombo
    * @param condCombo
    * @param valueField
    * @param filterIndex
    */
-  protected void updateFilter(JComboBox<String> attCombo,
+  protected boolean updateFilter(JComboBox<String> attCombo,
           JComboBox<Condition> condCombo, JTextField valueField,
           int filterIndex)
   {
     String attName = (String) attCombo.getSelectedItem();
     Condition cond = (Condition) condCombo.getSelectedItem();
-    String pattern = valueField.getText();
-    KeyedMatcherI km = new KeyedMatcher(cond, pattern,
-            fromAttributeDisplayName(attName));
+    String pattern = valueField.getText().trim();
+
+    updatePatternTooltip(fromAttributeDisplayName(attName), cond,
+            valueField);
+
+    if (pattern.length() == 0 && cond.needsAPattern())
+    {
+      return false;
+    }
+
+    /*
+     * Construct a matcher that operates on Label, Score, 
+     * or named attribute
+     */
+    FeatureMatcherI km = null;
+    if (MessageManager.getString("label.label").equals(attName))
+    {
+      km = FeatureMatcher.byLabel(cond, pattern);
+    }
+    else if (MessageManager.getString("label.score").equals(attName))
+    {
+      km = FeatureMatcher.byScore(cond, pattern);
+    }
+    else
+    {
+      km = FeatureMatcher.byAttribute(cond, pattern,
+              fromAttributeDisplayName(attName));
+    }
 
     filters.set(filterIndex, km);
+
+    return true;
   }
 
   /**
@@ -1584,14 +1658,13 @@ public class FeatureTypeSettings extends JalviewDialog
      * update the filter conditions for the feature type
      */
     boolean anded = andFilters.isSelected();
-    KeyedMatcherSetI combined = new KeyedMatcherSet();
+    FeatureMatcherSetI combined = new FeatureMatcherSet();
 
-    for (KeyedMatcherI filter : filters)
+    for (FeatureMatcherI filter : filters)
     {
       String pattern = filter.getMatcher().getPattern();
       Condition condition = filter.getMatcher().getCondition();
-      if (pattern.trim().length() > 0 || condition == Condition.Present
-              || condition == Condition.NotPresent)
+      if (pattern.trim().length() > 0 || !condition.needsAPattern())
       {
         if (anded)
         {