JAL-2808 JAL-2069 FeatureTypeSettings (with new Filters tab) replaces FeatureColourCh...
[jalview.git] / src / jalview / gui / FeatureSettings.java
index 974b387..fedfe3f 100644 (file)
  */
 package jalview.gui;
 
+import static jalview.viewmodel.seqfeatures.FeatureRendererModel.COLOUR_COLUMN;
+import static jalview.viewmodel.seqfeatures.FeatureRendererModel.FILTER_COLUMN;
+import static jalview.viewmodel.seqfeatures.FeatureRendererModel.SHOW_COLUMN;
+import static jalview.viewmodel.seqfeatures.FeatureRendererModel.TYPE_COLUMN;
+
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
 import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
-import jalview.datamodel.features.FeatureAttributes;
 import jalview.gui.Help.HelpId;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
@@ -35,10 +39,6 @@ import jalview.util.Format;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
 import jalview.util.QuickSort;
-import jalview.util.ReverseListIterator;
-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 jalview.viewmodel.AlignmentViewport;
@@ -49,16 +49,13 @@ import java.awt.BorderLayout;
 import java.awt.Color;
 import java.awt.Component;
 import java.awt.Dimension;
-import java.awt.FlowLayout;
 import java.awt.Font;
 import java.awt.Graphics;
 import java.awt.GridLayout;
-import java.awt.LayoutManager;
+import java.awt.Point;
 import java.awt.Rectangle;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.FocusAdapter;
-import java.awt.event.FocusEvent;
 import java.awt.event.ItemEvent;
 import java.awt.event.ItemListener;
 import java.awt.event.MouseAdapter;
@@ -72,7 +69,6 @@ import java.io.FileOutputStream;
 import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -85,14 +81,11 @@ import java.util.Vector;
 import javax.help.HelpSetException;
 import javax.swing.AbstractCellEditor;
 import javax.swing.BorderFactory;
-import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
 import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JColorChooser;
-import javax.swing.JComboBox;
 import javax.swing.JDialog;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
@@ -100,26 +93,24 @@ import javax.swing.JLayeredPane;
 import javax.swing.JMenuItem;
 import javax.swing.JPanel;
 import javax.swing.JPopupMenu;
-import javax.swing.JRadioButton;
 import javax.swing.JScrollPane;
 import javax.swing.JSlider;
-import javax.swing.JTabbedPane;
 import javax.swing.JTable;
-import javax.swing.JTextArea;
-import javax.swing.JTextField;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingConstants;
 import javax.swing.SwingUtilities;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
-import javax.swing.plaf.basic.BasicArrowButton;
 import javax.swing.table.AbstractTableModel;
 import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
+import javax.swing.table.TableColumn;
 
 public class FeatureSettings extends JPanel
         implements FeatureSettingsControllerI
 {
+  private static final int COLUMN_COUNT = 4;
+
   private static final String COLON = ":";
 
   private static final int MIN_WIDTH = 400;
@@ -156,7 +147,7 @@ public class FeatureSettings extends JPanel
   JPanel groupPanel;
 
   JSlider transparency = new JSlider();
-  
+
   /*
    * when true, constructor is still executing - so ignore UI events
    */
@@ -182,29 +173,6 @@ public class FeatureSettings extends JPanel
    */
   Map<String, float[]> typeWidth = null;
 
-  /*
-   * fields of the feature filters tab
-   */
-  private JPanel filtersPane;
-
-  private JPanel chooseFiltersPanel;
-
-  private JComboBox<String> filteredFeatureChoice;
-
-  private JRadioButton andFilters;
-
-  private JRadioButton orFilters;
-
-  /*
-   * filters for the currently selected feature type
-   */
-  private List<KeyedMatcherI> filters;
-
-  private JTextArea filtersAsText;
-
-  // set white normally, black to debug layout
-  private Color debugBorderColour = Color.white;
-
   /**
    * Constructor
    * 
@@ -235,25 +203,48 @@ public class FeatureSettings extends JPanel
       @Override
       public String getToolTipText(MouseEvent e)
       {
-        if (table.columnAtPoint(e.getPoint()) == 0)
+        String tip = null;
+        int column = table.columnAtPoint(e.getPoint());
+        switch (column)
         {
-          /*
-           * Tooltip for feature name only
-           */
-          return JvSwingUtils.wrapTooltip(true, MessageManager
+        case TYPE_COLUMN:
+          tip = JvSwingUtils.wrapTooltip(true, MessageManager
                   .getString("label.feature_settings_click_drag"));
+          break;
+        case FILTER_COLUMN:
+          int row = table.rowAtPoint(e.getPoint());
+          KeyedMatcherSet o = (KeyedMatcherSet) table.getValueAt(row,
+                  column);
+          tip = o.isEmpty()
+                  ? MessageManager.getString("label.filters_tooltip")
+                  : o.toString();
+          break;
+        default:
+          break;
         }
-        return null;
+        return tip;
       }
     };
     table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
     table.setFont(new Font("Verdana", Font.PLAIN, 12));
-    table.setDefaultRenderer(Color.class, new ColorRenderer());
-
-    table.setDefaultEditor(Color.class, new ColorEditor(this));
 
+    // table.setDefaultRenderer(Color.class, new ColorRenderer());
+    // table.setDefaultEditor(Color.class, new ColorEditor(this));
+    //
     table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
     table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
+
+    table.setDefaultEditor(KeyedMatcherSet.class, new FilterEditor(this));
+    table.setDefaultRenderer(KeyedMatcherSet.class, new FilterRenderer());
+
+    TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
+            new ColorRenderer(), new ColorEditor(this));
+    table.addColumn(colourColumn);
+
+    TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
+            new FilterRenderer(), new FilterEditor(this));
+    table.addColumn(filterColumn);
+
     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 
     table.addMouseListener(new MouseAdapter()
@@ -262,11 +253,12 @@ public class FeatureSettings extends JPanel
       public void mousePressed(MouseEvent evt)
       {
         selectedRow = table.rowAtPoint(evt.getPoint());
+        String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
         if (evt.isPopupTrigger())
         {
-          popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
-                  table.getValueAt(selectedRow, 1), fr.getMinMax(),
-                  evt.getX(), evt.getY());
+          Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
+          popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
+                  evt.getY());
         }
         else if (evt.getClickCount() == 2)
         {
@@ -274,8 +266,7 @@ public class FeatureSettings extends JPanel
           boolean toggleSelection = Platform.isControlDown(evt);
           boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
-                  invertSelection, extendSelection, toggleSelection,
-                  (String) table.getValueAt(selectedRow, 0));
+                  invertSelection, extendSelection, toggleSelection, type);
         }
       }
 
@@ -286,9 +277,10 @@ public class FeatureSettings extends JPanel
         selectedRow = table.rowAtPoint(evt.getPoint());
         if (evt.isPopupTrigger())
         {
-          popupSort(selectedRow, (String) table.getValueAt(selectedRow, 0),
-                  table.getValueAt(selectedRow, 1), fr.getMinMax(),
-                  evt.getX(), evt.getY());
+          String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
+          Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
+          popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
+                  evt.getY());
         }
       }
     });
@@ -344,8 +336,8 @@ public class FeatureSettings extends JPanel
         if (!fs.resettingTable && !fs.handlingUpdate)
         {
           fs.handlingUpdate = true;
-          fs.resetTable(null); // new groups may be added with new seuqence
-          // feature types only
+          fs.resetTable(null);
+          // new groups may be added with new sequence feature types only
           fs.handlingUpdate = false;
         }
       }
@@ -383,7 +375,7 @@ public class FeatureSettings extends JPanel
     inConstruction = false;
   }
 
-  protected void popupSort(final int selectedRow, final String type,
+  protected void popupSort(final int rowSelected, final String type,
           final Object typeCol, final Map<String, float[][]> minmax, int x,
           int y)
   {
@@ -443,15 +435,17 @@ public class FeatureSettings extends JPanel
         {
           if (featureColour.isSimpleColour())
           {
-            FeatureColourChooser fc = new FeatureColourChooser(me.fr, type);
+            FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
             fc.addActionListener(this);
           }
           else
           {
             // bring up simple color chooser
             colorChooser = new JColorChooser();
+            String title = MessageManager
+                    .getString("label.select_colour");
             JDialog dialog = JColorChooser.createDialog(me,
-                    "Select new Colour", true, // modal
+                    title, true, // modal
                     colorChooser, this, // OK button handler
                     null); // no CANCEL button handler
             colorChooser.setColor(featureColour.getMaxColour());
@@ -460,20 +454,25 @@ public class FeatureSettings extends JPanel
         }
         else
         {
-          if (e.getSource() instanceof FeatureColourChooser)
+          if (e.getSource() instanceof FeatureTypeSettings)
           {
-            FeatureColourChooser fc = (FeatureColourChooser) e.getSource();
-            table.setValueAt(fc.getLastColour(), selectedRow, 1);
+            /*
+             * update after OK in feature colour dialog; the updated
+             * colour will have already been set in the FeatureRenderer
+             */
+            FeatureColourI fci = fr.getFeatureColours().get(type);
+            table.setValueAt(fci, rowSelected, 1);
             table.validate();
           }
           else
           {
             // probably the color chooser!
             table.setValueAt(new FeatureColour(colorChooser.getColor()),
-                    selectedRow, 1);
+                    rowSelected, 1);
             table.validate();
             me.updateFeatureRenderer(
-                    ((FeatureTableModel) table.getModel()).getData(), false);
+                    ((FeatureTableModel) table.getModel()).getData(),
+                    false);
           }
         }
       }
@@ -548,8 +547,6 @@ public class FeatureSettings extends JPanel
       }
     }
 
-    populateFilterableFeatures();
-
     resetTable(null);
 
     validate();
@@ -654,7 +651,8 @@ public class FeatureSettings extends JPanel
       }
     }
 
-    Object[][] data = new Object[displayableTypes.size()][3];
+    int columnCount = COLUMN_COUNT;
+    Object[][] data = new Object[displayableTypes.size()][columnCount];
     int dataIndex = 0;
 
     if (fr.hasRenderOrder())
@@ -677,9 +675,13 @@ public class FeatureSettings extends JPanel
           continue;
         }
 
-        data[dataIndex][0] = type;
-        data[dataIndex][1] = fr.getFeatureStyle(type);
-        data[dataIndex][2] = new Boolean(
+        data[dataIndex][TYPE_COLUMN] = type;
+        data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
+        KeyedMatcherSetI featureFilter = fr.getFeatureFilter(type);
+        data[dataIndex][FILTER_COLUMN] = featureFilter == null
+                ? new KeyedMatcherSet()
+                : featureFilter;
+        data[dataIndex][SHOW_COLUMN] = new Boolean(
                 af.getViewport().getFeaturesDisplayed().isVisible(type));
         dataIndex++;
         displayableTypes.remove(type);
@@ -693,27 +695,31 @@ public class FeatureSettings extends JPanel
     while (!displayableTypes.isEmpty())
     {
       String type = displayableTypes.iterator().next();
-      data[dataIndex][0] = type;
+      data[dataIndex][TYPE_COLUMN] = type;
 
-      data[dataIndex][1] = fr.getFeatureStyle(type);
-      if (data[dataIndex][1] == null)
+      data[dataIndex][COLOUR_COLUMN] = fr.getFeatureStyle(type);
+      if (data[dataIndex][COLOUR_COLUMN] == null)
       {
         // "Colour has been updated in another view!!"
         fr.clearRenderOrder();
         return;
       }
-
-      data[dataIndex][2] = new Boolean(true);
+      KeyedMatcherSetI featureFilter = fr.getFeatureFilter(type);
+      data[dataIndex][FILTER_COLUMN] = featureFilter == null
+              ? new KeyedMatcherSet()
+              : featureFilter;
+      data[dataIndex][SHOW_COLUMN] = new Boolean(true);
       dataIndex++;
       displayableTypes.remove(type);
     }
 
     if (originalData == null)
     {
-      originalData = new Object[data.length][3];
+      int size = data[0].length;
+      originalData = new Object[data.length][size];
       for (int i = 0; i < data.length; i++)
       {
-        System.arraycopy(data[i], 0, originalData[i], 0, 3);
+        System.arraycopy(data[i], 0, originalData[i], 0, size);
       }
     }
     else
@@ -734,8 +740,8 @@ public class FeatureSettings extends JPanel
   }
 
   /**
-   * Updates 'originalData' (used for restore on Cancel) if we detect that
-   * changes have been made outwith this dialog
+   * Updates 'originalData' (used for restore on Cancel) if we detect that changes
+   * have been made outwith this dialog
    * <ul>
    * <li>a new feature type added (and made visible)</li>
    * <li>a feature colour changed (in the Amend Features dialog)</li>
@@ -751,27 +757,27 @@ public class FeatureSettings extends JPanel
             .getData();
     for (Object[] row : foundData)
     {
-      String type = (String) row[0];
+      String type = (String) row[TYPE_COLUMN];
       boolean found = false;
       for (Object[] current : currentData)
       {
-        if (type.equals(current[0]))
+        if (type.equals(current[TYPE_COLUMN]))
         {
           found = true;
           /*
            * currently dependent on object equality here;
            * really need an equals method on FeatureColour
            */
-          if (!row[1].equals(current[1]))
+          if (!row[COLOUR_COLUMN].equals(current[COLOUR_COLUMN]))
           {
             /*
              * feature colour has changed externally - update originalData
              */
             for (Object[] original : originalData)
             {
-              if (type.equals(original[0]))
+              if (type.equals(original[TYPE_COLUMN]))
               {
-                original[1] = row[1];
+                original[COLOUR_COLUMN] = row[COLOUR_COLUMN];
                 break;
               }
             }
@@ -784,10 +790,11 @@ public class FeatureSettings extends JPanel
         /*
          * new feature detected - add to original data (on top)
          */
-        Object[][] newData = new Object[originalData.length + 1][3];
+        int size = currentData[0].length;
+        Object[][] newData = new Object[originalData.length + 1][size];
         for (int i = 0; i < originalData.length; i++)
         {
-          System.arraycopy(originalData[i], 0, newData[i + 1], 0, 3);
+          System.arraycopy(originalData[i], 0, newData[i + 1], 0, size);
         }
         newData[0] = row;
         originalData = newData;
@@ -797,8 +804,8 @@ public class FeatureSettings extends JPanel
 
   /**
    * Remove from the groups panel any checkboxes for groups that are not in the
-   * foundGroups set. This enables removing a group from the display when the
-   * last feature in that group is deleted.
+   * foundGroups set. This enables removing a group from the display when the last
+   * feature in that group is deleted.
    * 
    * @param foundGroups
    */
@@ -1004,9 +1011,9 @@ public class FeatureSettings extends JPanel
   {
     for (int i = 0; i < table.getRowCount(); i++)
     {
-      Boolean value = (Boolean) table.getValueAt(i, 2);
+      Boolean value = (Boolean) table.getValueAt(i, SHOW_COLUMN);
 
-      table.setValueAt(new Boolean(!value.booleanValue()), i, 2);
+      table.setValueAt(new Boolean(!value.booleanValue()), i, SHOW_COLUMN);
     }
   }
 
@@ -1020,17 +1027,16 @@ public class FeatureSettings extends JPanel
     float[] width = new float[data.length];
     float[] awidth;
     float max = 0;
-    int num = 0;
+
     for (int i = 0; i < data.length; i++)
     {
-      awidth = typeWidth.get(data[i][0]);
+      awidth = typeWidth.get(data[i][TYPE_COLUMN]);
       if (awidth[0] > 0)
       {
         width[i] = awidth[1] / awidth[0];// *awidth[0]*awidth[2]; - better
         // weight - but have to make per
         // sequence, too (awidth[2])
         // if (width[i]==1) // hack to distinguish single width sequences.
-        num++;
       }
       else
       {
@@ -1047,16 +1053,17 @@ public class FeatureSettings extends JPanel
       // awidth = (float[]) typeWidth.get(data[i][0]);
       if (width[i] == 0)
       {
-        width[i] = fr.getOrder(data[i][0].toString());
+        width[i] = fr.getOrder(data[i][TYPE_COLUMN].toString());
         if (width[i] < 0)
         {
-          width[i] = fr.setOrder(data[i][0].toString(), i / data.length);
+          width[i] = fr.setOrder(data[i][TYPE_COLUMN].toString(),
+                  i / data.length);
         }
       }
       else
       {
         width[i] /= max; // normalize
-        fr.setOrder(data[i][0].toString(), width[i]); // store for later
+        fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
       }
       if (i > 0)
       {
@@ -1090,8 +1097,8 @@ public class FeatureSettings extends JPanel
   }
 
   /**
-   * Update the priority order of features; only repaint if this changed the
-   * order of visible features
+   * Update the priority order of features; only repaint if this changed the order
+   * of visible features
    * 
    * @param data
    * @param visibleNew
@@ -1111,8 +1118,6 @@ public class FeatureSettings extends JPanel
     JPanel settingsPane = new JPanel();
     settingsPane.setLayout(new BorderLayout());
 
-    filtersPane = new JPanel();
-
     dasSettingsPane.setLayout(new BorderLayout());
 
     JPanel bigPanel = new JPanel();
@@ -1257,7 +1262,7 @@ public class FeatureSettings extends JPanel
         if (!inConstruction)
         {
           fr.setTransparency((100 - transparency.getValue()) / 100f);
-          af.alignPanel.paintAlignment(true,true);
+          af.alignPanel.paintAlignment(true, true);
         }
       }
     });
@@ -1298,15 +1303,6 @@ public class FeatureSettings extends JPanel
       }
     });
 
-    JTabbedPane tabbedPane = new JTabbedPane();
-    this.add(tabbedPane, BorderLayout.CENTER);
-    tabbedPane.addTab(MessageManager.getString("label.feature_settings"),
-            settingsPane);
-    tabbedPane.addTab(MessageManager.getString("label.filters"),
-            filtersPane);
-    // tabbedPane.addTab(MessageManager.getString("label.das_settings"),
-    // dasSettingsPane);
-
     JPanel transPanel = new JPanel(new GridLayout(1, 2));
     bigPanel.add(transPanel, BorderLayout.SOUTH);
 
@@ -1331,445 +1327,7 @@ public class FeatureSettings extends JPanel
     dasButtonPanel.add(saveDAS);
     settingsPane.add(bigPanel, BorderLayout.CENTER);
     settingsPane.add(buttonPanel, BorderLayout.SOUTH);
-
-    initFiltersTab();
-  }
-
-  /**
-   * Populates initial layout of the feature attribute filters panel
-   */
-  protected void initFiltersTab()
-  {
-    filters = new ArrayList<>();
-
-    /*
-     * choose feature type
-     */
-    JPanel chooseTypePanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
-    chooseTypePanel.setBackground(Color.white);
-    JvSwingUtils.createItalicTitledBorder(chooseTypePanel,
-            MessageManager.getString("label.feature_type"), true);
-    filteredFeatureChoice = new JComboBox<>();
-    filteredFeatureChoice.addItemListener(new ItemListener()
-    {
-      @Override
-      public void itemStateChanged(ItemEvent e)
-      {
-        refreshFiltersDisplay();
-      }
-    });
-    chooseTypePanel.add(new JLabel(MessageManager
-            .getString("label.feature_to_filter")));
-    chooseTypePanel.add(filteredFeatureChoice);
-    populateFilterableFeatures();
-
-    /*
-     * the panel with the filters for the selected feature type
-     */
-    JPanel filtersPanel = new JPanel();
-    filtersPanel.setLayout(new BoxLayout(filtersPanel, BoxLayout.Y_AXIS));
-    filtersPanel.setBackground(Color.white);
-    JvSwingUtils.createItalicTitledBorder(filtersPanel,
-            MessageManager.getString("label.filters"), true);
-
-    /*
-     * add AND or OR radio buttons
-     */
-    JPanel andOrPanel = new JPanel(new FlowLayout(FlowLayout.LEFT));
-    andOrPanel.setBackground(Color.white);
-    andOrPanel.setBorder(BorderFactory.createLineBorder(debugBorderColour));
-    andFilters = new JRadioButton("And");
-    orFilters = new JRadioButton("Or");
-    ActionListener actionListener = new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        filtersChanged();
-      }
-    };
-    andFilters.addActionListener(actionListener);
-    orFilters.addActionListener(actionListener);
-    ButtonGroup andOr = new ButtonGroup();
-    andOr.add(andFilters);
-    andOr.add(orFilters);
-    andFilters.setSelected(true);
-    andOrPanel.add(new JLabel(MessageManager
-            .getString("label.join_conditions")));
-    andOrPanel.add(andFilters);
-    andOrPanel.add(orFilters);
-    filtersPanel.add(andOrPanel);
-
-    /*
-     * panel with filters - populated by refreshFiltersDisplay
-     */
-    chooseFiltersPanel = new JPanel();
-    LayoutManager box = new BoxLayout(chooseFiltersPanel,
-            BoxLayout.Y_AXIS);
-    chooseFiltersPanel.setLayout(box);
-    filtersPanel.add(chooseFiltersPanel);
-
-    /*
-     * a read-only text view of the current filters
-     */
-    JPanel showFiltersPanel = new JPanel(new BorderLayout(5, 5));
-    showFiltersPanel.setBackground(Color.white);
-    JvSwingUtils.createItalicTitledBorder(showFiltersPanel,
-            MessageManager.getString("label.match_condition"), true);
-    filtersAsText = new JTextArea();
-    filtersAsText.setLineWrap(true);
-    filtersAsText.setWrapStyleWord(true);
-    filtersAsText.setEnabled(false); // for display only
-    showFiltersPanel.add(filtersAsText);
-
-    filtersPane.setLayout(new BorderLayout());
-    filtersPane.add(chooseTypePanel, BorderLayout.NORTH);
-    filtersPane.add(filtersPanel, BorderLayout.CENTER);
-    filtersPane.add(showFiltersPanel, BorderLayout.SOUTH);
-
-    /*
-     * update display for initial feature type selection
-     */
-    refreshFiltersDisplay();
-  }
-
-  /**
-   * Adds entries to the 'choose feature to filter' drop-down choice. Only
-   * feature types which have known attributes (so can be filtered) are
-   * included, so recall this method to update the list (check for newly added
-   * attributes).
-   */
-  protected void populateFilterableFeatures()
-  {
-    /*
-     * suppress action handler while updating the list
-     */
-    ItemListener listener = filteredFeatureChoice.getItemListeners()[0];
-    filteredFeatureChoice.removeItemListener(listener);
-
-    filteredFeatureChoice.removeAllItems();
-    ReverseListIterator<String> types = new ReverseListIterator<>(
-            fr.getRenderOrder());
-
-    boolean found = false;
-    while (types.hasNext())
-    {
-      String type = types.next();
-      if (FeatureAttributes.getInstance().hasAttributes(type))
-      {
-        filteredFeatureChoice.addItem(type);
-        found = true;
-      }
-    }
-    if (!found)
-    {
-      filteredFeatureChoice.addItem(MessageManager
-              .getString("label.no_feature_attributes"));
-      filteredFeatureChoice.setEnabled(false);
-    }
-
-    filteredFeatureChoice.addItemListener(listener);
-  }
-
-  /**
-   * 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 on change of selected feature
-   * type, or after a filter has been removed, added or amended.
-   */
-  protected void refreshFiltersDisplay()
-  {
-    /*
-     * clear the panel and list of filter conditions
-     */
-    chooseFiltersPanel.removeAll();
-    filters.clear();
-
-    /*
-     * look up attributes known for feature type
-     */
-    String selectedType = (String) filteredFeatureChoice.getSelectedItem();
-    List<String[]> attNames = FeatureAttributes.getInstance()
-            .getAttributes(selectedType);
-
-    /*
-     * if this feature type has filters set, load them first
-     */
-    KeyedMatcherSetI featureFilters = fr.getFeatureFilter(selectedType);
-    filtersAsText.setText("");
-    if (featureFilters != null)
-    {
-      filtersAsText.setText(featureFilters.toString());
-      if (!featureFilters.isAnded())
-      {
-        orFilters.setSelected(true);
-      }
-      featureFilters.getMatchers().forEach(matcher -> filters.add(matcher));
-    }
-
-    /*
-     * and an empty filter for the user to populate (add)
-     */
-    KeyedMatcherI noFilter = new KeyedMatcher(Condition.values()[0], "",
-            (String) null);
-    filters.add(noFilter);
-
-    /*
-     * render the conditions in rows, each in its own JPanel
-     */
-    int filterIndex = 0;
-    for (KeyedMatcherI filter : filters)
-    {
-      String[] attName = filter.getKey();
-      Condition condition = filter.getMatcher()
-              .getCondition();
-      String pattern = filter.getMatcher().getPattern();
-      JPanel row = addFilter(attName, attNames, condition, pattern, filterIndex);
-      row.setBorder(BorderFactory.createLineBorder(debugBorderColour));
-      chooseFiltersPanel.add(row);
-      filterIndex++;
-    }
-    // chooseFiltersPanel.add(Box.createVerticalGlue());
-
-    filtersPane.validate();
-    filtersPane.repaint();
-  }
-
-  /**
-   * A helper method that constructs a panel with one filter condition:
-   * <ul>
-   * <li>a drop-down list of 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>
-   * </ul>
-   * If attribute, condition or pattern are not null, they are set as defaults for
-   * the input fields. The 'remove' button is added unless the pattern is null or
-   * empty (incomplete filter condition).
-   * 
-   * @param attName
-   * @param attNames
-   * @param cond
-   * @param pattern
-   * @param filterIndex
-   * @return
-   */
-  protected JPanel addFilter(String[] attName, List<String[]> attNames,
-          Condition cond, String pattern, int filterIndex)
-  {
-    JPanel filterRow = new JPanel(new FlowLayout(FlowLayout.LEFT));
-    filterRow.setBackground(Color.white);
-
-    /*
-     * drop-down choice of attribute, with description as a tooltip 
-     * if we can obtain it
-     */
-    String featureType = (String) filteredFeatureChoice.getSelectedItem();
-    final JComboBox<String> attCombo = populateAttributesDropdown(
-            featureType, attNames);
-    JComboBox<Condition> condCombo = new JComboBox<>();
-    JTextField patternField = new JTextField(8);
-
-    /*
-     * action handlers that validate and (if valid) apply changes
-     */
-    ActionListener actionListener = new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        if (attCombo.getSelectedItem() != null)
-        {
-          if (validateFilter(patternField, condCombo))
-          {
-            updateFilter(attCombo, condCombo, patternField, filterIndex);
-            filtersChanged();
-          }
-        }
-      }
-    };
-    ItemListener itemListener = new ItemListener()
-    {
-      @Override
-      public void itemStateChanged(ItemEvent e)
-      {
-        actionListener.actionPerformed(null);
-      }
-    };
-
-    if (attName == null) // the 'add a condition' row
-    {
-      attCombo.setSelectedItem(null);
-    }
-    else
-    {
-      attCombo.setSelectedItem(String.join(COLON, attName));
-    }
-    attCombo.addItemListener(itemListener);
-
-    filterRow.add(attCombo);
-
-    /*
-     * drop-down choice of test condition
-     */
-    for (Condition c : Condition.values())
-    {
-      condCombo.addItem(c);
-    }
-    if (cond != null)
-    {
-      condCombo.setSelectedItem(cond);
-    }
-    condCombo.addItemListener(itemListener);
-    filterRow.add(condCombo);
-
-    /*
-     * pattern to match against
-     */
-    patternField.setText(pattern);
-    patternField.addActionListener(actionListener);
-    patternField.addFocusListener(new FocusAdapter()
-    {
-      @Override
-      public void focusLost(FocusEvent e)
-      {
-        actionListener.actionPerformed(null);
-      }
-    });
-    filterRow.add(patternField);
-
-    /*
-     * add remove button if filter is populated (non-empty pattern)
-     */
-    if (pattern != null && pattern.trim().length() > 0)
-    {
-      // todo: gif for button drawing '-' or 'x'
-      JButton removeCondition = new BasicArrowButton(SwingConstants.WEST);
-      removeCondition.setToolTipText(MessageManager
-              .getString("label.delete_row"));
-      removeCondition.addActionListener(new ActionListener()
-      {
-        @Override
-        public void actionPerformed(ActionEvent e)
-        {
-          filters.remove(filterIndex);
-          filtersChanged();
-        }
-      });
-      filterRow.add(removeCondition);
-    }
-
-    return filterRow;
-  }
-
-  /**
-   * 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.
-   * 
-   * @param featureType
-   * @param attNames
-   */
-  protected JComboBox<String> populateAttributesDropdown(
-          String featureType, List<String[]> attNames)
-  {
-    List<String> displayNames = new ArrayList<>();
-    List<String> tooltips = new ArrayList<>();
-    FeatureAttributes fa = FeatureAttributes.getInstance();
-    for (String[] attName : attNames)
-    {
-      String desc = fa.getDescription(featureType, attName);
-      if (desc != null && desc.length() > MAX_TOOLTIP_LENGTH)
-      {
-        desc = desc.substring(0, MAX_TOOLTIP_LENGTH) + "...";
-      }
-      displayNames.add(String.join(COLON, attName));
-      tooltips.add(desc == null ? "" : desc);
-    }
-
-    JComboBox<String> attCombo = JvSwingUtils.buildComboWithTooltips(
-            displayNames, tooltips);
-    if (attNames.isEmpty())
-    {
-      attCombo.setToolTipText(MessageManager
-              .getString("label.no_attributes"));
-    }
-    return attCombo;
-  }
-
-  /**
-   * Action on any change to feature filtering, namely
-   * <ul>
-   * <li>change of selected attribute</li>
-   * <li>change of selected condition</li>
-   * <li>change of match pattern</li>
-   * <li>removal of a condition</li>
-   * </ul>
-   * The action should be to
-   * <ul>
-   * <li>parse and validate the filters</li>
-   * <li>if valid, update the filter text box</li>
-   * <li>and apply the filters to the viewport</li>
-   * </ul>
-   */
-  protected void filtersChanged()
-  {
-    /*
-     * update the filter conditions for the feature type
-     */
-    String featureType = (String) filteredFeatureChoice.getSelectedItem();
-    boolean anded = andFilters.isSelected();
-    KeyedMatcherSetI combined = new KeyedMatcherSet();
-
-    for (KeyedMatcherI filter : filters)
-    {
-      String pattern = filter.getMatcher().getPattern();
-      if (pattern.trim().length() > 0)
-      {
-        if (anded)
-        {
-          combined.and(filter);
-        }
-        else
-        {
-          combined.or(filter);
-        }
-      }
-    }
-
-    /*
-     * save the filter conditions in the FeatureRenderer
-     * (note this might now be an empty filter with no conditions)
-     */
-    fr.setFeatureFilter(featureType, combined);
-
-    filtersAsText.setText(combined.toString());
-
-    refreshFiltersDisplay();
-
-    af.alignPanel.paintAlignment(true, true);
-  }
-
-  /**
-   * Constructs a filter condition from the given input fields, and replaces the
-   * condition at filterIndex with the new one
-   * 
-   * @param attCombo
-   * @param condCombo
-   * @param valueField
-   * @param filterIndex
-   */
-  protected void 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,
-            attName.split(COLON));
-
-    filters.set(filterIndex, km);
+    this.add(settingsPane);
   }
 
   public void fetchDAS_actionPerformed(ActionEvent e)
@@ -1929,68 +1487,25 @@ public class FeatureSettings extends JPanel
             JvOptionPane.DEFAULT_OPTION, JvOptionPane.INFORMATION_MESSAGE);
   }
 
-  /**
-   * 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 entered 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
-   */
-  protected boolean validateFilter(JTextField value,
-          JComboBox<Condition> condCombo)
-  {
-    if (value == null || condCombo == null)
-    {
-      return true; // fields not populated
-    }
-  
-    Condition cond = (Condition) condCombo.getSelectedItem();
-    value.setBackground(Color.white);
-    value.setToolTipText("");
-    String v1 = value.getText().trim();
-    if (v1.length() == 0)
-    {
-      return false;
-    }
-
-    if (cond.isNumeric())
-    {
-      try
-      {
-        Float.valueOf(v1);
-      } catch (NumberFormatException e)
-      {
-        value.setBackground(Color.red);
-        value.setToolTipText(MessageManager
-                .getString("label.numeric_required"));
-        return false;
-      }
-    }
-  
-    return true;
-  }
-
   // ///////////////////////////////////////////////////////////////////////
   // http://java.sun.com/docs/books/tutorial/uiswing/components/table.html
   // ///////////////////////////////////////////////////////////////////////
   class FeatureTableModel extends AbstractTableModel
   {
-    FeatureTableModel(Object[][] data)
-    {
-      this.data = data;
-    }
 
     private String[] columnNames = {
         MessageManager.getString("label.feature_type"),
         MessageManager.getString("action.colour"),
-        MessageManager.getString("label.display") };
+        MessageManager.getString("label.filter"),
+        MessageManager.getString("label.show") };
 
     private Object[][] data;
 
+    FeatureTableModel(Object[][] data)
+    {
+      this.data = data;
+    }
+
     public Object[][] getData()
     {
       return data;
@@ -2030,10 +1545,14 @@ public class FeatureSettings extends JPanel
       return data[row][col];
     }
 
+    /**
+     * Answers the class of the object in column c of the first row of the table
+     */
     @Override
-    public Class getColumnClass(int c)
+    public Class<?> getColumnClass(int c)
     {
-      return getValueAt(0, c).getClass();
+      Object v = getValueAt(0, c);
+      return v == null ? null : v.getClass();
     }
 
     @Override
@@ -2110,6 +1629,54 @@ public class FeatureSettings extends JPanel
     }
   }
 
+  class FilterRenderer extends JLabel implements TableCellRenderer
+  {
+    javax.swing.border.Border unselectedBorder = null;
+
+    javax.swing.border.Border selectedBorder = null;
+
+    public FilterRenderer()
+    {
+      setOpaque(true); // MUST do this for background to show up.
+      setHorizontalTextPosition(SwingConstants.CENTER);
+      setVerticalTextPosition(SwingConstants.CENTER);
+    }
+
+    @Override
+    public Component getTableCellRendererComponent(JTable tbl,
+            Object filter, boolean isSelected, boolean hasFocus, int row,
+            int column)
+    {
+      KeyedMatcherSetI theFilter = (KeyedMatcherSetI) filter;
+      setOpaque(true);
+      String asText = theFilter.toString();
+      setBackground(tbl.getBackground());
+      this.setText(asText);
+      this.setIcon(null);
+
+      if (isSelected)
+      {
+        if (selectedBorder == null)
+        {
+          selectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
+                  tbl.getSelectionBackground());
+        }
+        setBorder(selectedBorder);
+      }
+      else
+      {
+        if (unselectedBorder == null)
+        {
+          unselectedBorder = BorderFactory.createMatteBorder(2, 5, 2, 5,
+                  tbl.getBackground());
+        }
+        setBorder(unselectedBorder);
+      }
+
+      return this;
+    }
+  }
+
   /**
    * update comp using rendering settings from gcol
    * 
@@ -2197,11 +1764,250 @@ public class FeatureSettings extends JPanel
       }
       else
       {
-        comp.setToolTipText(tt.append(" ").append(comp.getToolTipText())
-                .toString());
+        comp.setToolTipText(
+                tt.append(" ").append(comp.getToolTipText()).toString());
       }
     }
   }
+
+  class ColorEditor extends AbstractCellEditor
+          implements TableCellEditor, ActionListener
+  {
+    FeatureSettings me;
+
+    FeatureColourI currentColor;
+
+    FeatureTypeSettings chooser;
+
+    String type;
+
+    JButton button;
+
+    JColorChooser colorChooser;
+
+    JDialog dialog;
+
+    protected static final String EDIT = "edit";
+
+    int rowSelected = 0;
+
+    public ColorEditor(FeatureSettings me)
+    {
+      this.me = me;
+      // Set up the editor (from the table's point of view),
+      // which is a button.
+      // This button brings up the color chooser dialog,
+      // which is the editor from the user's point of view.
+      button = new JButton();
+      button.setActionCommand(EDIT);
+      button.addActionListener(this);
+      button.setBorderPainted(false);
+      // Set up the dialog that the button brings up.
+      colorChooser = new JColorChooser();
+      dialog = JColorChooser.createDialog(button,
+              MessageManager.getString("label.select_colour"), true, // modal
+              colorChooser, this, // OK button handler
+              null); // no CANCEL button handler
+    }
+
+    /**
+     * Handles events from the editor button and from the dialog's OK button.
+     */
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+      // todo test e.getSource() instead here
+      if (EDIT.equals(e.getActionCommand()))
+      {
+        // The user has clicked the cell, so
+        // bring up the dialog.
+        if (currentColor.isSimpleColour())
+        {
+          // bring up simple color chooser
+          button.setBackground(currentColor.getColour());
+          colorChooser.setColor(currentColor.getColour());
+          dialog.setVisible(true);
+        }
+        else
+        {
+          // bring up graduated chooser.
+          chooser = new FeatureTypeSettings(me.fr, type);
+          chooser.setRequestFocusEnabled(true);
+          chooser.requestFocus();
+          chooser.addActionListener(this);
+          chooser.showTab(true);
+        }
+        // Make the renderer reappear.
+        fireEditingStopped();
+
+      }
+      else
+      {
+        if (currentColor.isSimpleColour())
+        {
+          /*
+           * read off colour picked in colour chooser after OK pressed
+           */
+          currentColor = new FeatureColour(colorChooser.getColor());
+          me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+        }
+        else
+        {
+          /*
+           * after OK in variable colour dialog, any changes to colour 
+           * (or filters!) are already set in FeatureRenderer, so just
+           * update table data without triggering updateFeatureRenderer
+           */
+          currentColor = fr.getFeatureColours().get(type);
+          KeyedMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
+          if (currentFilter == null)
+          {
+            currentFilter = new KeyedMatcherSet();
+          }
+          Object[] data = ((FeatureTableModel) table.getModel())
+                  .getData()[rowSelected];
+          data[COLOUR_COLUMN] = currentColor;
+          data[FILTER_COLUMN] = currentFilter;
+        }
+        fireEditingStopped();
+        me.table.validate();
+      }
+    }
+
+    // Implement the one CellEditor method that AbstractCellEditor doesn't.
+    @Override
+    public Object getCellEditorValue()
+    {
+      return currentColor;
+    }
+
+    // Implement the one method defined by TableCellEditor.
+    @Override
+    public Component getTableCellEditorComponent(JTable theTable, Object value,
+            boolean isSelected, int row, int column)
+    {
+      currentColor = (FeatureColourI) value;
+      this.rowSelected = row;
+      type = me.table.getValueAt(row, TYPE_COLUMN).toString();
+      button.setOpaque(true);
+      button.setBackground(me.getBackground());
+      if (!currentColor.isSimpleColour())
+      {
+        JLabel btn = new JLabel();
+        btn.setSize(button.getSize());
+        FeatureSettings.renderGraduatedColor(btn, currentColor);
+        button.setBackground(btn.getBackground());
+        button.setIcon(btn.getIcon());
+        button.setText(btn.getText());
+      }
+      else
+      {
+        button.setText("");
+        button.setIcon(null);
+        button.setBackground(currentColor.getColour());
+      }
+      return button;
+    }
+  }
+
+  /**
+   * The cell editor for the Filter column. It displays the text of any filters
+   * for the feature type in that row (in full as a tooltip, possible abbreviated
+   * as display text). On click in the cell, opens the Feature Display Settings
+   * dialog at the Filters tab.
+   */
+  class FilterEditor extends AbstractCellEditor
+          implements TableCellEditor, ActionListener
+  {
+    FeatureSettings me;
+
+    KeyedMatcherSetI currentFilter;
+
+    Point lastLocation;
+
+    String type;
+
+    JButton button;
+
+    protected static final String EDIT = "edit";
+
+    int rowSelected = 0;
+
+    public FilterEditor(FeatureSettings me)
+    {
+      this.me = me;
+      button = new JButton();
+      button.setActionCommand(EDIT);
+      button.addActionListener(this);
+      button.setBorderPainted(false);
+    }
+
+    /**
+     * Handles events from the editor button
+     */
+    @Override
+    public void actionPerformed(ActionEvent e)
+    {
+      if (button == e.getSource())
+      {
+        FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
+        chooser.addActionListener(this);
+        chooser.setRequestFocusEnabled(true);
+        chooser.requestFocus();
+        if (lastLocation != null)
+        {
+          // todo open at its last position on screen
+          chooser.setBounds(lastLocation.x, lastLocation.y,
+                  chooser.getWidth(), chooser.getHeight());
+          chooser.validate();
+        }
+        chooser.showTab(false);
+        fireEditingStopped();
+      }
+      else if (e.getSource() instanceof Component)
+      {
+
+        /*
+         * after OK in variable colour dialog, any changes to filter
+         * (or colours!) are already set in FeatureRenderer, so just
+         * update table data without triggering updateFeatureRenderer
+         */
+        FeatureColourI currentColor = fr.getFeatureColours().get(type);
+        currentFilter = me.fr.getFeatureFilter(type);
+        if (currentFilter == null)
+        {
+          currentFilter = new KeyedMatcherSet();
+        }
+        Object[] data = ((FeatureTableModel) table.getModel())
+                .getData()[rowSelected];
+        data[COLOUR_COLUMN] = currentColor;
+        data[FILTER_COLUMN] = currentFilter;
+        fireEditingStopped();
+        me.table.validate();
+      }
+    }
+
+    @Override
+    public Object getCellEditorValue()
+    {
+      return currentFilter;
+    }
+
+    @Override
+    public Component getTableCellEditorComponent(JTable theTable, Object value,
+            boolean isSelected, int row, int column)
+    {
+      currentFilter = (KeyedMatcherSetI) value;
+      this.rowSelected = row;
+      type = me.table.getValueAt(row, TYPE_COLUMN).toString();
+      button.setOpaque(true);
+      button.setBackground(me.getBackground());
+      button.setText(currentFilter.toString());
+      button.setToolTipText(currentFilter.toString());
+      button.setIcon(null);
+      return button;
+    }
+  }
 }
 
 class FeatureIcon implements Icon
@@ -2285,125 +2091,3 @@ class FeatureIcon implements Icon
     }
   }
 }
-
-class ColorEditor extends AbstractCellEditor
-        implements TableCellEditor, ActionListener
-{
-  FeatureSettings me;
-
-  FeatureColourI currentColor;
-
-  FeatureColourChooser chooser;
-
-  String type;
-
-  JButton button;
-
-  JColorChooser colorChooser;
-
-  JDialog dialog;
-
-  protected static final String EDIT = "edit";
-
-  int selectedRow = 0;
-
-  public ColorEditor(FeatureSettings me)
-  {
-    this.me = me;
-    // Set up the editor (from the table's point of view),
-    // which is a button.
-    // This button brings up the color chooser dialog,
-    // which is the editor from the user's point of view.
-    button = new JButton();
-    button.setActionCommand(EDIT);
-    button.addActionListener(this);
-    button.setBorderPainted(false);
-    // Set up the dialog that the button brings up.
-    colorChooser = new JColorChooser();
-    dialog = JColorChooser.createDialog(button,
-            MessageManager.getString("label.select_new_colour"), true, // modal
-            colorChooser, this, // OK button handler
-            null); // no CANCEL button handler
-  }
-
-  /**
-   * Handles events from the editor button and from the dialog's OK button.
-   */
-  @Override
-  public void actionPerformed(ActionEvent e)
-  {
-
-    if (EDIT.equals(e.getActionCommand()))
-    {
-      // The user has clicked the cell, so
-      // bring up the dialog.
-      if (currentColor.isSimpleColour())
-      {
-        // bring up simple color chooser
-        button.setBackground(currentColor.getColour());
-        colorChooser.setColor(currentColor.getColour());
-        dialog.setVisible(true);
-      }
-      else
-      {
-        // bring up graduated chooser.
-        chooser = new FeatureColourChooser(me.fr, type);
-        chooser.setRequestFocusEnabled(true);
-        chooser.requestFocus();
-        chooser.addActionListener(this);
-      }
-      // Make the renderer reappear.
-      fireEditingStopped();
-
-    }
-    else
-    { // User pressed dialog's "OK" button.
-      if (currentColor.isSimpleColour())
-      {
-        currentColor = new FeatureColour(colorChooser.getColor());
-      }
-      else
-      {
-        currentColor = chooser.getLastColour();
-      }
-      me.table.setValueAt(getCellEditorValue(), selectedRow, 1);
-      fireEditingStopped();
-      me.table.validate();
-    }
-  }
-
-  // Implement the one CellEditor method that AbstractCellEditor doesn't.
-  @Override
-  public Object getCellEditorValue()
-  {
-    return currentColor;
-  }
-
-  // Implement the one method defined by TableCellEditor.
-  @Override
-  public Component getTableCellEditorComponent(JTable table, Object value,
-          boolean isSelected, int row, int column)
-  {
-    currentColor = (FeatureColourI) value;
-    this.selectedRow = row;
-    type = me.table.getValueAt(row, 0).toString();
-    button.setOpaque(true);
-    button.setBackground(me.getBackground());
-    if (!currentColor.isSimpleColour())
-    {
-      JLabel btn = new JLabel();
-      btn.setSize(button.getSize());
-      FeatureSettings.renderGraduatedColor(btn, currentColor);
-      button.setBackground(btn.getBackground());
-      button.setIcon(btn.getIcon());
-      button.setText(btn.getText());
-    }
-    else
-    {
-      button.setText("");
-      button.setIcon(null);
-      button.setBackground(currentColor.getColour());
-    }
-    return button;
-  }
-}