Merge branch 'develop' into features/JAL-3010ontologyFeatureSettings
[jalview.git] / src / jalview / gui / FeatureTypeSettings.java
index 5480f5d..9609996 100644 (file)
@@ -29,6 +29,7 @@ import jalview.datamodel.features.FeatureMatcher;
 import jalview.datamodel.features.FeatureMatcherI;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
+import jalview.io.gff.SequenceOntologyFactory;
 import jalview.schemes.FeatureColour;
 import jalview.util.ColorUtils;
 import jalview.util.MessageManager;
@@ -49,7 +50,11 @@ import java.awt.event.MouseAdapter;
 import java.awt.event.MouseEvent;
 import java.text.DecimalFormat;
 import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -62,7 +67,6 @@ import javax.swing.JLabel;
 import javax.swing.JPanel;
 import javax.swing.JRadioButton;
 import javax.swing.JSlider;
-import javax.swing.JTabbedPane;
 import javax.swing.JTextField;
 import javax.swing.SwingConstants;
 import javax.swing.border.LineBorder;
@@ -107,7 +111,8 @@ public class FeatureTypeSettings extends JalviewDialog
   /*
    * FeatureRenderer holds colour scheme and filters for feature types
    */
-  private final FeatureRenderer fr; // todo refactor to allow interface type here
+  private final FeatureRenderer fr; // todo refactor to allow interface type
+                                    // here
 
   /*
    * the view panel to update when settings change
@@ -118,10 +123,11 @@ public class FeatureTypeSettings extends JalviewDialog
 
   /*
    * the colour and filters to reset to on Cancel
+   * (including feature sub-types if modified)
    */
-  private final FeatureColourI originalColour;
+  private Map<String, FeatureColourI> originalColours;
 
-  private final FeatureMatcherSetI originalFilter;
+  private Map<String, FeatureMatcherSetI> originalFilters;
 
   /*
    * set flag to true when setting values programmatically,
@@ -155,7 +161,12 @@ public class FeatureTypeSettings extends JalviewDialog
 
   private JRadioButton graduatedColour = new JRadioButton();
 
-  private JPanel singleColour = new JPanel();
+  /**
+   * colours and filters are shown in tabbed view or single content pane
+   */
+  JPanel coloursPanel, filtersPanel;
+
+  JPanel singleColour = new JPanel();
 
   private JPanel minColour = new JPanel();
 
@@ -199,43 +210,58 @@ public class FeatureTypeSettings extends JalviewDialog
    */
   private List<FeatureMatcherI> filters;
 
-  // set white normally, black to debug layout
-  private Color debugBorderColour = Color.white;
-
   private JPanel chooseFiltersPanel;
 
-  private JTabbedPane tabbedPane;
+  /*
+   * feature types present in Feature Renderer which are
+   * sub-types of the one this editor is acting on
+   */
+  private final List<String> subTypes;
 
-  /**
-   * Constructor
-   * 
-   * @param frender
-   * @param theType
+  /*
+   * if true, filter or colour settings are also applied to 
+   * any feature sub-types in the Sequence Ontology
    */
-  public FeatureTypeSettings(FeatureRenderer frender, String theType)
-  {
-    this(frender, false, theType);
-  }
+  private boolean applyFiltersToSubtypes;
+
+  private boolean applyColourToSubtypes;
 
   /**
-   * 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.
+   * Constructor
    * 
    * @param frender
-   * @param blocking
    * @param theType
    */
-  FeatureTypeSettings(FeatureRenderer frender, boolean blocking,
-          String theType)
+  public FeatureTypeSettings(FeatureRenderer frender, String theType)
   {
     this.fr = frender;
     this.featureType = theType;
     ap = fr.ap;
-    originalFilter = fr.getFeatureFilter(theType);
-    originalColour = fr.getFeatureColours().get(theType);
 
-    adjusting = true;
+    /*
+     * determine sub-types (if any) of this feature type
+     */
+    List<String> types = fr.getRenderOrder();
+    subTypes = SequenceOntologyFactory.getInstance()
+            .getChildTerms(this.featureType, types);
+    Collections.sort(subTypes); // sort for ease of reading in tooltip
 
+    /*
+     * save original colours and filters for this feature type
+     * and any sub-types, to restore on Cancel
+     */
+    originalFilters = new HashMap<>();
+    originalFilters.put(theType, fr.getFeatureFilter(theType));
+    originalColours = new HashMap<>();
+    originalColours.put(theType, fr.getFeatureColours().get(theType));
+    for (String child : subTypes)
+    {
+      originalFilters.put(child, fr.getFeatureFilter(child));
+      originalColours.put(child, fr.getFeatureColours().get(child));
+    }
+
+    adjusting = true;
+    
     try
     {
       initialise();
@@ -244,20 +270,20 @@ public class FeatureTypeSettings extends JalviewDialog
       ex.printStackTrace();
       return;
     }
-
+    
     updateColoursTab();
-
+    
     updateFiltersTab();
-
+    
     adjusting = false;
-
+    
     colourChanged(false);
-
+    
     String title = MessageManager
             .formatMessage("label.display_settings_for", new String[]
             { theType });
-    initDialogFrame(this, true, blocking, title, 600, 360);
-
+    initDialogFrame(this, true, false, title, 500, 500);
+    
     waitForInput();
   }
 
@@ -280,9 +306,9 @@ public class FeatureTypeSettings extends JalviewDialog
        */
       if (fc.isSimpleColour())
       {
-        simpleColour.setSelected(true);
         singleColour.setBackground(fc.getColour());
         singleColour.setForeground(fc.getColour());
+        simpleColour.setSelected(true);
       }
 
       /*
@@ -403,8 +429,6 @@ public class FeatureTypeSettings extends JalviewDialog
   private void initialise()
   {
     this.setLayout(new BorderLayout());
-    tabbedPane = new JTabbedPane();
-    this.add(tabbedPane, BorderLayout.CENTER);
 
     /*
      * an ActionListener that applies colour changes
@@ -419,18 +443,16 @@ public class FeatureTypeSettings extends JalviewDialog
     };
 
     /*
-     * first tab: colour options
+     * first panel/tab: colour options
      */
     JPanel coloursPanel = initialiseColoursPanel();
-    tabbedPane.addTab(MessageManager.getString("action.colour"),
-            coloursPanel);
+    this.add(coloursPanel, BorderLayout.NORTH);
 
     /*
-     * second tab: filter options
+     * second panel/tab: filter options
      */
     JPanel filtersPanel = initialiseFiltersPanel();
-    tabbedPane.addTab(MessageManager.getString("label.filters"),
-            filtersPanel);
+    this.add(filtersPanel, BorderLayout.CENTER);
 
     JPanel okCancelPanel = initialiseOkCancelPanel();
 
@@ -581,12 +603,11 @@ public class FeatureTypeSettings extends JalviewDialog
     maxColour.setBorder(new LineBorder(Color.black));
 
     /*
-     * default max colour to current colour (if a plain colour),
-     * or to Black if colour by label;  make min colour a pale
-     * version of max colour
+     * default max colour to last plain colour;
+     * make min colour a pale version of max colour
      */
     FeatureColourI fc = fr.getFeatureColours().get(featureType);
-    Color bg = fc.isSimpleColour() ? fc.getColour() : Color.BLACK;
+    Color bg = fc.getColour() == null ? Color.BLACK : fc.getColour();
     maxColour.setBackground(bg);
     minColour.setBackground(ColorUtils.bleachColour(bg, 0.9f));
 
@@ -736,15 +757,25 @@ public class FeatureTypeSettings extends JalviewDialog
   private JPanel initialiseColoursPanel()
   {
     JPanel colourByPanel = new JPanel();
+    colourByPanel.setBackground(Color.white);
     colourByPanel.setLayout(new BoxLayout(colourByPanel, BoxLayout.Y_AXIS));
+    JvSwingUtils.createTitledBorder(colourByPanel,
+            MessageManager.getString("action.colour"), true);
+
+    /*
+     * option to apply colour to sub-types as well (if there are any)
+     */
+    if (!subTypes.isEmpty())
+    {
+      applyColourToSubtypes = false;
+      colourByPanel.add(initSubtypesPanel(false));
+    }
 
     /*
      * simple colour radio button and colour picker
      */
     JPanel simpleColourPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
     simpleColourPanel.setBackground(Color.white);
-    JvSwingUtils.createTitledBorder(simpleColourPanel,
-            MessageManager.getString("label.simple"), true);
     colourByPanel.add(simpleColourPanel);
 
     simpleColour = new JRadioButton(
@@ -757,15 +788,24 @@ public class FeatureTypeSettings extends JalviewDialog
       {
         if (simpleColour.isSelected() && !adjusting)
         {
-          showColourChooser(singleColour, "label.select_colour");
+          colourChanged(true);
         }
       }
-
     });
-    
+
     singleColour.setFont(JvSwingUtils.getLabelFont());
     singleColour.setBorder(BorderFactory.createLineBorder(Color.black));
     singleColour.setPreferredSize(new Dimension(40, 20));
+    if (originalColour.isGraduatedColour())
+    {
+      singleColour.setBackground(originalColour.getMaxColour());
+      singleColour.setForeground(originalColour.getMaxColour());
+    }
+    else
+    {
+      singleColour.setBackground(originalColour.getColour());
+      singleColour.setForeground(originalColour.getColour());
+    }
     singleColour.addMouseListener(new MouseAdapter()
     {
       @Override
@@ -835,6 +875,46 @@ public class FeatureTypeSettings extends JalviewDialog
     return colourByPanel;
   }
 
+  /**
+   * Constructs and returns a panel with a checkbox for the option to apply any
+   * changes also to sub-types of the feature type
+   * 
+   * @return
+   */
+  protected JPanel initSubtypesPanel(final boolean forFilters)
+  {
+    JPanel toSubtypes = new JPanel(new FlowLayout(FlowLayout.LEFT));
+    toSubtypes.setBackground(Color.WHITE);
+    JCheckBox applyToSubtypesCB = new JCheckBox(MessageManager
+            .formatMessage("label.apply_to_subtypes", featureType));
+    applyToSubtypesCB.setToolTipText(getSubtypesTooltip());
+    applyToSubtypesCB.addActionListener(new ActionListener()
+    {
+      /*
+       * reset and reapply settings on toggle of checkbox
+       */
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        if (forFilters)
+        {
+          applyFiltersToSubtypes = applyToSubtypesCB.isSelected();
+          restoreOriginalFilters();
+          filtersChanged();
+        }
+        else
+        {
+          applyColourToSubtypes = applyToSubtypesCB.isSelected();
+          restoreOriginalColours();
+          colourChanged(true);
+        }
+      }
+    });
+    toSubtypes.add(applyToSubtypesCB);
+
+    return toSubtypes;
+  }
+
   private void showColourChooser(JPanel colourPanel, String key)
   {
     Color col = JColorChooser.showDialog(this,
@@ -849,9 +929,9 @@ public class FeatureTypeSettings extends JalviewDialog
   }
 
   /**
-   * 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
+   * 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
    */
@@ -874,9 +954,17 @@ public class FeatureTypeSettings extends JalviewDialog
     FeatureColourI acg = makeColourFromInputs();
 
     /*
-     * save the colour, and repaint stuff
+     * save the colour, and set on subtypes if selected
      */
     fr.setColour(featureType, acg);
+    if (applyColourToSubtypes)
+    {
+      for (String child : subTypes)
+      {
+        fr.setColour(child, acg);
+      }
+    }
+    refreshFeatureSettings();
     ap.paintAlignment(updateStructsAndOverview, updateStructsAndOverview);
 
     updateColoursTab();
@@ -902,8 +990,8 @@ public class FeatureTypeSettings extends JalviewDialog
      */
     if (byCategory.isSelected())
     {
-      Color c = this.getBackground();
-      FeatureColourI fc = new FeatureColour(c, c, null, 0f, 0f);
+      Color c = singleColour.getBackground();
+      FeatureColourI fc = new FeatureColour(c);
       fc.setColourByLabel(true);
       String byWhat = (String) colourByTextCombo.getSelectedItem();
       if (!LABEL_18N.equals(byWhat))
@@ -994,9 +1082,14 @@ public class FeatureTypeSettings extends JalviewDialog
   @Override
   protected void raiseClosed()
   {
+    refreshFeatureSettings();
+  }
+
+  protected void refreshFeatureSettings()
+  {
     if (this.featureSettings != null)
     {
-      featureSettings.actionPerformed(new ActionEvent(this, 0, "CLOSED"));
+      featureSettings.actionPerformed(new ActionEvent(this, 0, "REFRESH"));
     }
   }
 
@@ -1011,16 +1104,34 @@ public class FeatureTypeSettings extends JalviewDialog
 
   /**
    * Action on Cancel is to restore colour scheme and filters as they were when
-   * the dialog was opened
+   * the dialog was opened (including any feature sub-types that may have been
+   * changed)
    */
   @Override
   public void cancelPressed()
   {
-    fr.setColour(featureType, originalColour);
-    fr.setFeatureFilter(featureType, originalFilter);
+    restoreOriginalColours();
+    restoreOriginalFilters();
     ap.paintAlignment(true, true);
   }
 
+  protected void restoreOriginalFilters()
+  {
+    for (Entry<String, FeatureMatcherSetI> entry : originalFilters
+            .entrySet())
+    {
+      fr.setFeatureFilter(entry.getKey(), entry.getValue());
+    }
+  }
+
+  protected void restoreOriginalColours()
+  {
+    for (Entry<String, FeatureColourI> entry : originalColours.entrySet())
+    {
+      fr.setColour(entry.getKey(), entry.getValue());
+    }
+  }
+
   /**
    * Action on text entry of a threshold value
    */
@@ -1065,8 +1176,8 @@ public class FeatureTypeSettings extends JalviewDialog
 
   /**
    * Converts the slider value to its absolute value by dividing by the
-   * scaleFactor. Rounding errors are squashed by forcing min/max of slider range
-   * to the actual min/max of feature score range
+   * scaleFactor. Rounding errors are squashed by forcing min/max of slider
+   * range to the actual min/max of feature score range
    * 
    * @return
    */
@@ -1089,11 +1200,11 @@ public class FeatureTypeSettings extends JalviewDialog
   }
 
   /**
-   * A helper method to build the drop-down choice of attributes for a feature. If
-   * 'withRange' is true, then Score, and any attributes with a min-max range, are
-   * added. If 'withText' is true, Label and any known attributes are added. This
-   * allows 'categorical numerical' attributes e.g. codon position to be coloured
-   * by text.
+   * A helper method to build the drop-down choice of attributes for a feature.
+   * If 'withRange' is true, then Score, and any attributes with a min-max
+   * range, are added. If 'withText' is true, Label and any known attributes are
+   * added. This allows 'categorical numerical' attributes e.g. codon position
+   * to be coloured by text.
    * <p>
    * Where metadata is available with a description for an attribute, that is
    * added as a tooltip.
@@ -1159,11 +1270,25 @@ public class FeatureTypeSettings extends JalviewDialog
   {
     filters = new ArrayList<>();
 
+    JPanel outerPanel = new JPanel();
+    outerPanel.setLayout(new BoxLayout(outerPanel, BoxLayout.Y_AXIS));
+    outerPanel.setBackground(Color.white);
+
+    /*
+     * option to apply colour to sub-types as well (if there are any)
+     */
+    if (!subTypes.isEmpty())
+    {
+      applyFiltersToSubtypes = false;
+      outerPanel.add(initSubtypesPanel(true));
+    }
+
     JPanel filtersPanel = new JPanel();
     filtersPanel.setLayout(new BoxLayout(filtersPanel, BoxLayout.Y_AXIS));
     filtersPanel.setBackground(Color.white);
     JvSwingUtils.createTitledBorder(filtersPanel,
             MessageManager.getString("label.filters"), true);
+    outerPanel.add(filtersPanel);
 
     JPanel andOrPanel = initialiseAndOrPanel();
     filtersPanel.add(andOrPanel);
@@ -1176,7 +1301,7 @@ public class FeatureTypeSettings extends JalviewDialog
     chooseFiltersPanel.setBackground(Color.white);
     filtersPanel.add(chooseFiltersPanel);
 
-    return filtersPanel;
+    return outerPanel;
   }
 
   /**
@@ -1186,9 +1311,13 @@ public class FeatureTypeSettings extends JalviewDialog
    */
   private JPanel initialiseAndOrPanel()
   {
-    JPanel andOrPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
+    JPanel andOrPanel = new JPanel(new BorderLayout());
     andOrPanel.setBackground(Color.white);
-    andOrPanel.setBorder(BorderFactory.createLineBorder(debugBorderColour));
+
+//    JPanel panel1 = new JPanel(new FlowLayout(FlowLayout.LEFT));
+//    andOrPanel.add(panel1, BorderLayout.WEST);
+//    panel1.setBackground(Color.white);
+//    panel1.setBorder(BorderFactory.createLineBorder(debugBorderColour));
     andFilters = new JRadioButton(MessageManager.getString("label.and"));
     orFilters = new JRadioButton(MessageManager.getString("label.or"));
     ActionListener actionListener = new ActionListener()
@@ -1209,10 +1338,29 @@ public class FeatureTypeSettings extends JalviewDialog
             new JLabel(MessageManager.getString("label.join_conditions")));
     andOrPanel.add(andFilters);
     andOrPanel.add(orFilters);
+
     return andOrPanel;
   }
 
   /**
+   * Builds a tooltip for the 'Apply to subtypes' checkbox with a list of
+   * subtypes of this feature type
+   * 
+   * @return
+   */
+  protected String getSubtypesTooltip()
+  {
+    StringBuilder sb = new StringBuilder(20 * subTypes.size());
+    sb.append(MessageManager.getString("label.apply_also_to"));
+    for (String child : subTypes)
+    {
+      sb.append("<br>").append(child);
+    }
+    String tooltip = JvSwingUtils.wrapTooltip(true, sb.toString());
+    return tooltip;
+  }
+
+  /**
    * Refreshes the display to show any filters currently configured for the
    * selected feature type (editable, with 'remove' option), plus one extra row
    * for adding a condition. This should be called after a filter has been
@@ -1271,7 +1419,6 @@ public class FeatureTypeSettings extends JalviewDialog
     for (FeatureMatcherI filter : filters)
     {
       JPanel row = addFilter(filter, attNames, filterIndex);
-      row.setBorder(BorderFactory.createLineBorder(debugBorderColour));
       chooseFiltersPanel.add(row);
       filterIndex++;
     }
@@ -1283,7 +1430,8 @@ public class FeatureTypeSettings extends JalviewDialog
   /**
    * A helper method that constructs a row (panel) with one filter condition:
    * <ul>
-   * <li>a drop-down list of Label, Score and attribute names to choose from</li>
+   * <li>a drop-down list of Label, Score and attribute names to choose
+   * from</li>
    * <li>a drop-down list of conditions to choose from</li>
    * <li>a text field for input of a match pattern</li>
    * <li>optionally, a 'remove' button</li>
@@ -1408,16 +1556,13 @@ public class FeatureTypeSettings extends JalviewDialog
      * disable pattern field for condition 'Present / NotPresent'
      */
     Condition selectedCondition = (Condition) condCombo.getSelectedItem();
-    if (!selectedCondition.needsAPattern())
-    {
-      patternField.setEnabled(false);
-    }
+    patternField.setEnabled(selectedCondition.needsAPattern());
 
     /*
      * if a numeric condition is selected, show the value range
      * as a tooltip on the value input field
      */
-    setPatternTooltip(filterBy, selectedCondition, patternField);
+    setNumericHints(filterBy, selectedCondition, patternField);
 
     /*
      * add remove button if filter is populated (non-empty pattern)
@@ -1472,15 +1617,20 @@ 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
+   * If a numeric comparison condition is selected, retrieves the min-max range
+   * for the value (score or attribute), and sets it as a tooltip on the value
+   * field. If the field is currently empty, then pre-populates it with
+   * <ul>
+   * <li>the minimum value, if condition is > or >=</li>
+   * <li>the maximum value, if condition is < or <=</li>
+   * </ul>
    * 
    * @param attName
    * @param selectedCondition
    * @param patternField
    */
-  private void setPatternTooltip(String attName,
-          Condition selectedCondition, JTextField patternField)
+  private void setNumericHints(String attName, Condition selectedCondition,
+          JTextField patternField)
   {
     patternField.setToolTipText("");
 
@@ -1489,19 +1639,36 @@ public class FeatureTypeSettings extends JalviewDialog
       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]));
+        String minFormatted = DECFMT_2_2.format(minMax[0]);
+        String maxFormatted = DECFMT_2_2.format(minMax[1]);
+        String tip = String.format("(%s - %s)", minFormatted, maxFormatted);
         patternField.setToolTipText(tip);
+        if (patternField.getText().isEmpty())
+        {
+          if (selectedCondition == Condition.GE
+                  || selectedCondition == Condition.GT)
+          {
+            patternField.setText(minFormatted);
+          }
+          else
+          {
+            if (selectedCondition == Condition.LE
+                    || selectedCondition == Condition.LT)
+            {
+              patternField.setText(maxFormatted);
+            }
+          }
+        }
       }
     }
   }
 
   /**
-   * 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
-   * is in the list. If the pattern is now invalid (non-numeric pattern for a
-   * numeric condition), it is cleared.
+   * 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 is in the list. If the pattern is now invalid
+   * (non-numeric pattern for a numeric condition), it is cleared.
    * 
    * @param attName
    * @param cond
@@ -1528,10 +1695,11 @@ public class FeatureTypeSettings extends JalviewDialog
     ItemListener listener = condCombo.getItemListeners()[0];
     condCombo.removeItemListener(listener);
     boolean condIsValid = false;
+
     condCombo.removeAllItems();
     for (Condition c : Condition.values())
     {
-      if ((c.isNumeric() && type != Datatype.Character)
+      if ((c.isNumeric() && type == Datatype.Number)
               || (!c.isNumeric() && type != Datatype.Number))
       {
         condCombo.addItem(c);
@@ -1554,8 +1722,6 @@ public class FeatureTypeSettings extends JalviewDialog
       condCombo.setSelectedIndex(0);
     }
 
-    condCombo.addItemListener(listener);
-
     /*
      * clear pattern if it is now invalid for condition
      */
@@ -1573,15 +1739,20 @@ public class FeatureTypeSettings extends JalviewDialog
         patternField.setText("");
       }
     }
+
+    /*
+     * restore the listener
+     */
+    condCombo.addItemListener(listener);
   }
 
   /**
-   * Answers true unless a numeric condition has been selected with a non-numeric
-   * value. Sets the value field to RED with a tooltip if in error.
+   * Answers true unless a numeric condition has been selected with a
+   * non-numeric value. Sets the value field to RED with a tooltip if in error.
    * <p>
-   * If the pattern is expected but is empty, this method returns false, but does
-   * not mark the field as invalid. This supports selecting an attribute for a new
-   * condition before a match pattern has been entered.
+   * If the pattern is expected but is empty, this method returns false, but
+   * does not mark the field as invalid. This supports selecting an attribute
+   * for a new condition before a match pattern has been entered.
    * 
    * @param value
    * @param condCombo
@@ -1627,14 +1798,15 @@ public class FeatureTypeSettings extends JalviewDialog
 
   /**
    * Constructs a filter condition from the given input fields, and replaces the
-   * 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.
+   * 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.
+   * 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
@@ -1649,10 +1821,11 @@ public class FeatureTypeSettings extends JalviewDialog
     Condition cond = (Condition) condCombo.getSelectedItem();
     String pattern = valueField.getText().trim();
 
-    setPatternTooltip(attName, cond, valueField);
+    setNumericHints(attName, cond, valueField);
 
     if (pattern.length() == 0 && cond.needsAPattern())
     {
+      valueField.setEnabled(true); // ensure pattern field is enabled!
       return false;
     }
 
@@ -1681,17 +1854,6 @@ public class FeatureTypeSettings extends JalviewDialog
   }
 
   /**
-   * Makes the dialog visible, at the Feature Colour tab or at the Filters tab
-   * 
-   * @param coloursTab
-   */
-  public void showTab(boolean coloursTab)
-  {
-    setVisible(true);
-    tabbedPane.setSelectedIndex(coloursTab ? 0 : 1);
-  }
-
-  /**
    * Action on any change to feature filtering, namely
    * <ul>
    * <li>change of selected attribute</li>
@@ -1699,8 +1861,8 @@ public class FeatureTypeSettings extends JalviewDialog
    * <li>change of match pattern</li>
    * <li>removal of a condition</li>
    * </ul>
-   * The inputs are parsed into a combined filter and this is set for the feature
-   * type, and the alignment redrawn.
+   * The inputs are parsed into a combined filter and this is set for the
+   * feature type, and the alignment redrawn.
    */
   protected void filtersChanged()
   {
@@ -1732,6 +1894,15 @@ public class FeatureTypeSettings extends JalviewDialog
      * (note this might now be an empty filter with no conditions)
      */
     fr.setFeatureFilter(featureType, combined.isEmpty() ? null : combined);
+    if (applyFiltersToSubtypes)
+    {
+      for (String child : subTypes)
+      {
+        fr.setFeatureFilter(child, combined.isEmpty() ? null : combined);
+      }
+    }
+
+    refreshFeatureSettings();
     ap.paintAlignment(true, true);
 
     updateFiltersTab();