JAL-3048 JAL-3056 reinstate save/load project, colour scheme dialogs in
[jalview.git] / src / jalview / gui / FeatureSettings.java
index 4b4f363..ea3a667 100644 (file)
@@ -22,24 +22,24 @@ package jalview.gui;
 
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
-import jalview.bin.Cache;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
+import jalview.datamodel.features.FeatureMatcher;
+import jalview.datamodel.features.FeatureMatcherI;
 import jalview.datamodel.features.FeatureMatcherSet;
 import jalview.datamodel.features.FeatureMatcherSetI;
 import jalview.gui.Help.HelpId;
+import jalview.gui.JalviewColourChooser.ColourChooserListener;
 import jalview.io.JalviewFileChooser;
 import jalview.io.JalviewFileView;
+import jalview.schemabinding.version2.Filter;
 import jalview.schemabinding.version2.JalviewUserColours;
+import jalview.schemabinding.version2.MatcherSet;
 import jalview.schemes.FeatureColour;
-import jalview.util.Format;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
-import jalview.util.QuickSort;
-import jalview.viewmodel.AlignmentViewport;
+import jalview.util.dialogrunner.RunResponse;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
-import jalview.ws.DasSequenceFeatureFetcher;
-import jalview.ws.dbsources.das.api.jalviewSourceI;
 
 import java.awt.BorderLayout;
 import java.awt.Color;
@@ -66,13 +66,14 @@ import java.io.InputStreamReader;
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.util.Arrays;
+import java.util.Comparator;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.Vector;
 
 import javax.help.HelpSetException;
 import javax.swing.AbstractCellEditor;
@@ -81,8 +82,6 @@ import javax.swing.Icon;
 import javax.swing.JButton;
 import javax.swing.JCheckBox;
 import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JColorChooser;
-import javax.swing.JDialog;
 import javax.swing.JInternalFrame;
 import javax.swing.JLabel;
 import javax.swing.JLayeredPane;
@@ -94,7 +93,8 @@ import javax.swing.JSlider;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingConstants;
-import javax.swing.SwingUtilities;
+import javax.swing.ToolTipManager;
+import javax.swing.border.Border;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.table.AbstractTableModel;
@@ -105,6 +105,9 @@ import javax.swing.table.TableColumn;
 public class FeatureSettings extends JPanel
         implements FeatureSettingsControllerI
 {
+  private static final String SEQUENCE_FEATURE_COLOURS = MessageManager
+          .getString("label.sequence_feature_colours");
+
   /*
    * column indices of fields in Feature Settings table
    */
@@ -122,11 +125,7 @@ public class FeatureSettings extends JPanel
 
   private static final int MIN_HEIGHT = 400;
 
-  DasSourceBrowser dassourceBrowser;
-
-  DasSequenceFeatureFetcher dasFeatureFetcher;
-
-  JPanel dasSettingsPane = new JPanel();
+  private final static String BASE_TOOLTIP = MessageManager.getString("label.click_to_edit");
 
   final FeatureRenderer fr;
 
@@ -137,9 +136,9 @@ public class FeatureSettings extends JPanel
    */
   Object[][] originalData;
 
-  private float originalTransparency;
+  float originalTransparency;
 
-  private Map<String, FeatureMatcherSetI> originalFilters;
+  Map<String, FeatureMatcherSetI> originalFilters;
 
   final JInternalFrame frame;
 
@@ -169,7 +168,7 @@ public class FeatureSettings extends JPanel
   /*
    * true when Feature Settings are updating from feature renderer
    */
-  private boolean handlingUpdate = false;
+  boolean handlingUpdate = false;
 
   /*
    * holds {featureCount, totalExtent} for each feature type
@@ -191,7 +190,7 @@ public class FeatureSettings extends JPanel
     int originalTransparencyAsPercent = (int) (originalTransparency * 100);
     transparency.setMaximum(100 - originalTransparencyAsPercent);
 
-    originalFilters = fr.getFeatureFilters();
+    originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
 
     try
     {
@@ -208,14 +207,20 @@ public class FeatureSettings extends JPanel
       {
         String tip = null;
         int column = table.columnAtPoint(e.getPoint());
+        int row = table.rowAtPoint(e.getPoint());
+
         switch (column)
         {
         case TYPE_COLUMN:
           tip = JvSwingUtils.wrapTooltip(true, MessageManager
                   .getString("label.feature_settings_click_drag"));
           break;
+        case COLOUR_COLUMN:
+          FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
+                  column);
+          tip = getColorTooltip(colour, true);
+          break;
         case FILTER_COLUMN:
-          int row = table.rowAtPoint(e.getPoint());
           FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
                   column);
           tip = o.isEmpty()
@@ -225,21 +230,34 @@ public class FeatureSettings extends JPanel
         default:
           break;
         }
+        
         return tip;
       }
+
+      /**
+       * Position the tooltip near the bottom edge of, and half way across, the
+       * current cell
+       */
+      @Override
+      public Point getToolTipLocation(MouseEvent e)
+      {
+        Point point = e.getPoint();
+        int column = table.columnAtPoint(point);
+        int row = table.rowAtPoint(point);
+        Rectangle r = getCellRect(row, column, false);
+        Point loc = new Point(r.x + r.width / 2, r.y + r.height - 3);
+        return loc;
+      }
     };
     table.getTableHeader().setFont(new Font("Verdana", Font.PLAIN, 12));
-    table.setFont(new Font("Verdana", Font.PLAIN, 12));
+    ToolTipManager.sharedInstance().registerComponent(table);
 
-    // 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(FeatureMatcherSet.class, new FilterEditor(this));
     table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
-
+    
     TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
             new ColorRenderer(), new ColorEditor(this));
     table.addColumn(colourColumn);
@@ -320,9 +338,6 @@ public class FeatureSettings extends JPanel
     // MessageManager.getString("label.feature_settings_click_drag")));
     scrollPane.setViewportView(table);
 
-    dassourceBrowser = new DasSourceBrowser(this);
-    dasSettingsPane.add(dassourceBrowser, BorderLayout.CENTER);
-
     if (af.getViewport().isShowSequenceFeatures() || !fr.hasRenderOrder())
     {
       fr.findAllFeatures(true); // display everything!
@@ -371,7 +386,6 @@ public class FeatureSettings extends JPanel
                       javax.swing.event.InternalFrameEvent evt)
               {
                 fr.removePropertyChangeListener(change);
-                dassourceBrowser.fs = null;
               };
             });
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
@@ -423,40 +437,53 @@ public class FeatureSettings extends JPanel
      * variable colour options include colour by label, by score,
      * by selected attribute text, or attribute value
      */
-    final JCheckBoxMenuItem mxcol = new JCheckBoxMenuItem(
+    final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
             MessageManager.getString("label.variable_colour"));
-    mxcol.setSelected(!featureColour.isSimpleColour());
-    men.add(mxcol);
-    mxcol.addActionListener(new ActionListener()
+    variableColourCB.setSelected(!featureColour.isSimpleColour());
+    men.add(variableColourCB);
+    
+    /*
+     * checkbox action listener doubles up as listener to OK
+     * from the variable colour / filters dialog
+     */
+    variableColourCB.addActionListener(new ActionListener()
     {
-      JColorChooser colorChooser;
-
       @Override
       public void actionPerformed(ActionEvent e)
       {
-        if (e.getSource() == mxcol)
+        if (e.getSource() == variableColourCB)
         {
           if (featureColour.isSimpleColour())
           {
+            /*
+             * toggle simple colour to variable colour - show dialog
+             */
             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,
-                    title, true, // modal
-                    colorChooser, this, // OK button handler
-                    null); // no CANCEL button handler
-            colorChooser.setColor(featureColour.getMaxColour());
-            dialog.setVisible(true);
+            /*
+             * toggle variable to simple colour - show colour chooser
+             */
+            String title = MessageManager.getString("label.select_colour");
+            ColourChooserListener listener = new ColourChooserListener()
+            {
+              @Override
+              public void colourSelected(Color c)
+              {
+                table.setValueAt(new FeatureColour(c), rowSelected,
+                        COLOUR_COLUMN);
+                table.validate();
+                me.updateFeatureRenderer(
+                        ((FeatureTableModel) table.getModel()).getData(),
+                        false);
+              }
+            };
+            JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
           }
         }
-        else
-        {
+        else    {
           if (e.getSource() instanceof FeatureTypeSettings)
           {
             /*
@@ -464,18 +491,8 @@ public class FeatureSettings extends JPanel
              * 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()),
-                    rowSelected, 1);
+            table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
             table.validate();
-            me.updateFeatureRenderer(
-                    ((FeatureTableModel) table.getModel()).getData(),
-                    false);
           }
         }
       }
@@ -850,173 +867,185 @@ public class FeatureSettings extends JPanel
     }
   }
 
+  /**
+   * Offers a file chooser dialog, and then loads the feature colours and
+   * filters from file in XML format and unmarshals to Jalview feature settings
+   */
   void load()
   {
     JalviewFileChooser chooser = new JalviewFileChooser("fc",
-            "Sequence Feature Colours");
+            SEQUENCE_FEATURE_COLOURS);
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.load_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.load"));
+    chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION){
+
+               @Override
+               public void run() {
+                     File file = chooser.getSelectedFile();
+                     load(file);
+               }});
+    chooser.showOpenDialog(this);
+  }
 
-    int value = chooser.showOpenDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+  /**
+   * Loads feature colours and filters from XML stored in the given file
+   * 
+   * @param file
+   */
+  void load(File file)
+  {
+    try
     {
-      File file = chooser.getSelectedFile();
-
-      try
-      {
-        InputStreamReader in = new InputStreamReader(
-                new FileInputStream(file), "UTF-8");
+      InputStreamReader in = new InputStreamReader(
+              new FileInputStream(file), "UTF-8");
 
-        JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
+      JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
 
-        for (int i = jucs.getColourCount() - 1; i >= 0; i--)
-        {
-          String name;
-          jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
-          if (newcol.hasMax())
-          {
-            Color mincol = null, maxcol = null;
-            try
-            {
-              mincol = new Color(Integer.parseInt(newcol.getMinRGB(), 16));
-              maxcol = new Color(Integer.parseInt(newcol.getRGB(), 16));
+      /*
+       * load feature colours
+       */
+      for (int i = jucs.getColourCount() - 1; i >= 0; i--)
+      {
+        jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
+        FeatureColourI colour = Jalview2XML.unmarshalColour(newcol);
+        fr.setColour(newcol.getName(), colour);
+        fr.setOrder(newcol.getName(), i / (float) jucs.getColourCount());
+      }
 
-            } catch (Exception e)
-            {
-              Cache.log.warn("Couldn't parse out graduated feature color.",
-                      e);
-            }
-            FeatureColourI gcol = new FeatureColour(mincol, maxcol,
-                    newcol.getMin(), newcol.getMax());
-            if (newcol.hasAutoScale())
-            {
-              gcol.setAutoScaled(newcol.getAutoScale());
-            }
-            if (newcol.hasColourByLabel())
-            {
-              gcol.setColourByLabel(newcol.getColourByLabel());
-            }
-            if (newcol.hasThreshold())
-            {
-              gcol.setThreshold(newcol.getThreshold());
-            }
-            if (newcol.getThreshType().length() > 0)
-            {
-              String ttyp = newcol.getThreshType();
-              if (ttyp.equalsIgnoreCase("ABOVE"))
-              {
-                gcol.setAboveThreshold(true);
-              }
-              if (ttyp.equalsIgnoreCase("BELOW"))
-              {
-                gcol.setBelowThreshold(true);
-              }
-            }
-            fr.setColour(name = newcol.getName(), gcol);
-          }
-          else
-          {
-            Color color = new Color(
-                    Integer.parseInt(jucs.getColour(i).getRGB(), 16));
-            fr.setColour(name = jucs.getColour(i).getName(),
-                    new FeatureColour(color));
-          }
-          fr.setOrder(name, (i == 0) ? 0 : i / jucs.getColourCount());
-        }
-        if (table != null)
+      /*
+       * load feature filters; loaded filters will replace any that are
+       * currently defined, other defined filters are left unchanged 
+       */
+      for (int i = 0; i < jucs.getFilterCount(); i++)
+      {
+        jalview.schemabinding.version2.Filter filterModel = jucs
+                .getFilter(i);
+        String featureType = filterModel.getFeatureType();
+        FeatureMatcherSetI filter = Jalview2XML.unmarshalFilter(featureType,
+                filterModel.getMatcherSet());
+        if (!filter.isEmpty())
         {
-          resetTable(null);
-          Object[][] data = ((FeatureTableModel) table.getModel())
-                  .getData();
-          ensureOrder(data);
-          updateFeatureRenderer(data, false);
-          table.repaint();
+          fr.setFeatureFilter(featureType, filter);
         }
-      } catch (Exception ex)
+      }
+
+      /*
+       * update feature settings table
+       */
+      if (table != null)
       {
-        System.out.println("Error loading User Colour File\n" + ex);
+        resetTable(null);
+        Object[][] data = ((FeatureTableModel) table.getModel())
+                .getData();
+        ensureOrder(data);
+        updateFeatureRenderer(data, false);
+        table.repaint();
       }
+    } catch (Exception ex)
+    {
+      System.out.println("Error loading User Colour File\n" + ex);
     }
   }
 
+  /**
+   * Offers a file chooser dialog, and then saves the current feature colours
+   * and any filters to the selected file in XML format
+   */
   void save()
   {
     JalviewFileChooser chooser = new JalviewFileChooser("fc",
-            "Sequence Feature Colours");
+            SEQUENCE_FEATURE_COLOURS);
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.save_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
+    int option = chooser.showSaveDialog(this);
+       if (option == JalviewFileChooser.APPROVE_OPTION) 
+       {
+         File file = chooser.getSelectedFile();
+         save(file);
+       }
+  }
 
-    int value = chooser.showSaveDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+  /**
+   * Saves feature colours and filters to the given file
+   * 
+   * @param file
+   */
+  void save(File file)
+  {
+    JalviewUserColours ucs = new JalviewUserColours();
+    ucs.setSchemeName("Sequence Features");
+    try
     {
-      String choice = chooser.getSelectedFile().getPath();
-      jalview.schemabinding.version2.JalviewUserColours ucs = new jalview.schemabinding.version2.JalviewUserColours();
-      ucs.setSchemeName("Sequence Features");
-      try
-      {
-        PrintWriter out = new PrintWriter(new OutputStreamWriter(
-                new FileOutputStream(choice), "UTF-8"));
+      PrintWriter out = new PrintWriter(new OutputStreamWriter(
+              new FileOutputStream(file), "UTF-8"));
 
-        Set<String> fr_colours = fr.getAllFeatureColours();
-        Iterator<String> e = fr_colours.iterator();
-        float[] sortOrder = new float[fr_colours.size()];
-        String[] sortTypes = new String[fr_colours.size()];
-        int i = 0;
-        while (e.hasNext())
+      /*
+       * sort feature types by colour order, from 0 (highest)
+       * to 1 (lowest)
+       */
+      Set<String> fr_colours = fr.getAllFeatureColours();
+      String[] sortedTypes = fr_colours
+              .toArray(new String[fr_colours.size()]);
+      Arrays.sort(sortedTypes, new Comparator<String>()
+      {
+        @Override
+        public int compare(String type1, String type2)
         {
-          sortTypes[i] = e.next();
-          sortOrder[i] = fr.getOrder(sortTypes[i]);
-          i++;
+          return Float.compare(fr.getOrder(type1), fr.getOrder(type2));
         }
-        QuickSort.sort(sortOrder, sortTypes);
-        sortOrder = null;
-        for (i = 0; i < sortTypes.length; i++)
+      });
+
+      /*
+       * save feature colours
+       */
+      for (String featureType : sortedTypes)
+      {
+        FeatureColourI fcol = fr.getFeatureStyle(featureType);
+        jalview.schemabinding.version2.Colour col = Jalview2XML.marshalColour(
+                featureType, fcol);
+        ucs.addColour(col);
+      }
+
+      /*
+       * save any feature filters
+       */
+      for (String featureType : sortedTypes)
+      {
+        FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
+        if (filter != null && !filter.isEmpty())
         {
-          jalview.schemabinding.version2.Colour col = new jalview.schemabinding.version2.Colour();
-          col.setName(sortTypes[i]);
-          FeatureColourI fcol = fr.getFeatureStyle(sortTypes[i]);
-          if (fcol.isSimpleColour())
-          {
-            col.setRGB(Format.getHexString(fcol.getColour()));
-          }
-          else
-          {
-            col.setRGB(Format.getHexString(fcol.getMaxColour()));
-            col.setMin(fcol.getMin());
-            col.setMax(fcol.getMax());
-            col.setMinRGB(
-                    jalview.util.Format.getHexString(fcol.getMinColour()));
-            col.setAutoScale(fcol.isAutoScaled());
-            col.setThreshold(fcol.getThreshold());
-            col.setColourByLabel(fcol.isColourByLabel());
-            col.setThreshType(fcol.isAboveThreshold() ? "ABOVE"
-                    : (fcol.isBelowThreshold() ? "BELOW" : "NONE"));
-          }
-          ucs.addColour(col);
+          Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
+          FeatureMatcherI firstMatcher = iterator.next();
+          MatcherSet ms = Jalview2XML.marshalFilter(firstMatcher, iterator,
+                  filter.isAnded());
+          Filter filterModel = new Filter();
+          filterModel.setFeatureType(featureType);
+          filterModel.setMatcherSet(ms);
+          ucs.addFilter(filterModel);
         }
-        ucs.marshal(out);
-        out.close();
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
       }
+
+      ucs.marshal(out);
+      out.close();
+    } catch (Exception ex)
+    {
+      ex.printStackTrace();
     }
   }
 
   public void invertSelection()
   {
-    for (int i = 0; i < table.getRowCount(); i++)
+    Object[][] data = ((FeatureTableModel) table.getModel()).getData();
+    for (int i = 0; i < data.length; i++)
     {
-      Boolean value = (Boolean) table.getValueAt(i, SHOW_COLUMN);
-
-      table.setValueAt(new Boolean(!value.booleanValue()), i, SHOW_COLUMN);
+      data[i][SHOW_COLUMN] = !(Boolean) data[i][SHOW_COLUMN];
     }
+    updateFeatureRenderer(data, true);
+    table.repaint();
   }
 
   public void orderByAvWidth()
@@ -1105,7 +1134,7 @@ public class FeatureSettings extends JPanel
    * @param data
    * @param visibleNew
    */
-  private void updateFeatureRenderer(Object[][] data, boolean visibleNew)
+  void updateFeatureRenderer(Object[][] data, boolean visibleNew)
   {
     FeatureSettingsBean[] rowData = getTableAsBeans(data);
 
@@ -1140,8 +1169,6 @@ public class FeatureSettings extends JPanel
     JPanel settingsPane = new JPanel();
     settingsPane.setLayout(new BorderLayout());
 
-    dasSettingsPane.setLayout(new BorderLayout());
-
     JPanel bigPanel = new JPanel();
     bigPanel.setLayout(new BorderLayout());
 
@@ -1256,6 +1283,8 @@ public class FeatureSettings extends JPanel
     JButton loadColours = new JButton(
             MessageManager.getString("label.load_colours"));
     loadColours.setFont(JvSwingUtils.getLabelFont());
+    loadColours.setToolTipText(
+            MessageManager.getString("label.load_colours_tooltip"));
     loadColours.addActionListener(new ActionListener()
     {
       @Override
@@ -1268,6 +1297,8 @@ public class FeatureSettings extends JPanel
     JButton saveColours = new JButton(
             MessageManager.getString("label.save_colours"));
     saveColours.setFont(JvSwingUtils.getLabelFont());
+    saveColours.setToolTipText(
+            MessageManager.getString("label.save_colours_tooltip"));
     saveColours.addActionListener(new ActionListener()
     {
       @Override
@@ -1292,38 +1323,6 @@ public class FeatureSettings extends JPanel
     transparency.setMaximum(70);
     transparency.setToolTipText(
             MessageManager.getString("label.transparency_tip"));
-    fetchDAS.setText(MessageManager.getString("label.fetch_das_features"));
-    fetchDAS.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        fetchDAS_actionPerformed(e);
-      }
-    });
-    saveDAS.setText(MessageManager.getString("action.save_as_default"));
-    saveDAS.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        saveDAS_actionPerformed(e);
-      }
-    });
-
-    JPanel dasButtonPanel = new JPanel();
-    dasButtonPanel.setBorder(BorderFactory.createEtchedBorder());
-    dasSettingsPane.setBorder(null);
-    cancelDAS.setEnabled(false);
-    cancelDAS.setText(MessageManager.getString("action.cancel_fetch"));
-    cancelDAS.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        cancelDAS_actionPerformed(e);
-      }
-    });
 
     JPanel transPanel = new JPanel(new GridLayout(1, 2));
     bigPanel.add(transPanel, BorderLayout.SOUTH);
@@ -1343,170 +1342,93 @@ public class FeatureSettings extends JPanel
     buttonPanel.add(loadColours);
     buttonPanel.add(saveColours);
     bigPanel.add(scrollPane, BorderLayout.CENTER);
-    dasSettingsPane.add(dasButtonPanel, BorderLayout.SOUTH);
-    dasButtonPanel.add(fetchDAS);
-    dasButtonPanel.add(cancelDAS);
-    dasButtonPanel.add(saveDAS);
     settingsPane.add(bigPanel, BorderLayout.CENTER);
     settingsPane.add(buttonPanel, BorderLayout.SOUTH);
     this.add(settingsPane);
   }
 
-  public void fetchDAS_actionPerformed(ActionEvent e)
-  {
-    fetchDAS.setEnabled(false);
-    cancelDAS.setEnabled(true);
-    dassourceBrowser.setGuiEnabled(false);
-    Vector<jalviewSourceI> selectedSources = dassourceBrowser
-            .getSelectedSources();
-    doDasFeatureFetch(selectedSources, true, true);
-  }
-
   /**
-   * get the features from selectedSources for all or the current selection
+   * Answers a suitable tooltip to show on the colour cell of the table
    * 
-   * @param selectedSources
-   * @param checkDbRefs
-   * @param promptFetchDbRefs
+   * @param fcol
+   * @param withHint
+   *          if true include 'click to edit' and similar text
+   * @return
    */
-  private void doDasFeatureFetch(List<jalviewSourceI> selectedSources,
-          boolean checkDbRefs, boolean promptFetchDbRefs)
+  public static String getColorTooltip(FeatureColourI fcol,
+          boolean withHint)
   {
-    SequenceI[] dataset, seqs;
-    int iSize;
-    AlignmentViewport vp = af.getViewport();
-    if (vp.getSelectionGroup() != null
-            && vp.getSelectionGroup().getSize() > 0)
-    {
-      iSize = vp.getSelectionGroup().getSize();
-      dataset = new SequenceI[iSize];
-      seqs = vp.getSelectionGroup().getSequencesInOrder(vp.getAlignment());
+    if (fcol == null)
+    {
+      return null;
     }
-    else
+    if (fcol.isSimpleColour())
     {
-      iSize = vp.getAlignment().getHeight();
-      seqs = vp.getAlignment().getSequencesArray();
+      return withHint ? BASE_TOOLTIP : null;
     }
-
-    dataset = new SequenceI[iSize];
-    for (int i = 0; i < iSize; i++)
+    String description = fcol.getDescription();
+    description = description.replaceAll("<", "&lt;");
+    description = description.replaceAll(">", "&gt;");
+    StringBuilder tt = new StringBuilder(description);
+    if (withHint)
     {
-      dataset[i] = seqs[i].getDatasetSequence();
+      tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
     }
-
-    cancelDAS.setEnabled(true);
-    dasFeatureFetcher = new jalview.ws.DasSequenceFeatureFetcher(dataset,
-            this, selectedSources, checkDbRefs, promptFetchDbRefs);
-    af.getViewport().setShowSequenceFeatures(true);
-    af.showSeqFeatures.setSelected(true);
-  }
-
-  /**
-   * blocking call to initialise the das source browser
-   */
-  public void initDasSources()
-  {
-    dassourceBrowser.initDasSources();
-  }
-
-  /**
-   * examine the current list of das sources and return any matching the given
-   * nicknames in sources
-   * 
-   * @param sources
-   *          Vector of Strings to resolve to DAS source nicknames.
-   * @return sources that are present in source list.
-   */
-  public List<jalviewSourceI> resolveSourceNicknames(Vector<String> sources)
-  {
-    return dassourceBrowser.sourceRegistry.resolveSourceNicknames(sources);
-  }
-
-  /**
-   * get currently selected das sources. ensure you have called initDasSources
-   * before calling this.
-   * 
-   * @return vector of selected das source nicknames
-   */
-  public Vector<jalviewSourceI> getSelectedSources()
-  {
-    return dassourceBrowser.getSelectedSources();
+    return JvSwingUtils.wrapTooltip(true, tt.toString());
   }
 
-  /**
-   * properly initialise DAS fetcher and then initiate a new thread to fetch
-   * features from the named sources (rather than any turned on by default)
-   * 
-   * @param sources
-   * @param block
-   *          if true then runs in same thread, otherwise passes to the Swing
-   *          executor
-   */
-  public void fetchDasFeatures(Vector<String> sources, boolean block)
+  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
+          int w, int h)
   {
-    initDasSources();
-    List<jalviewSourceI> resolved = dassourceBrowser.sourceRegistry
-            .resolveSourceNicknames(sources);
-    if (resolved.size() == 0)
+    boolean thr = false;
+    StringBuilder tx = new StringBuilder();
+  
+    if (gcol.isColourByAttribute())
     {
-      resolved = dassourceBrowser.getSelectedSources();
+      tx.append(FeatureMatcher
+              .toAttributeDisplayName(gcol.getAttributeName()));
     }
-    if (resolved.size() > 0)
+    else if (!gcol.isColourByLabel())
     {
-      final List<jalviewSourceI> dassources = resolved;
-      fetchDAS.setEnabled(false);
-      // cancelDAS.setEnabled(true); doDasFetch does this.
-      Runnable fetcher = new Runnable()
-      {
-
-        @Override
-        public void run()
-        {
-          doDasFeatureFetch(dassources, true, false);
-
-        }
-      };
-      if (block)
+      tx.append(MessageManager.getString("label.score"));
+    }
+    tx.append(" ");
+    if (gcol.isAboveThreshold())
+    {
+      thr = true;
+      tx.append(">");
+    }
+    if (gcol.isBelowThreshold())
+    {
+      thr = true;
+      tx.append("<");
+    }
+    if (gcol.isColourByLabel())
+    {
+      if (thr)
       {
-        fetcher.run();
+        tx.append(" ");
       }
-      else
+      if (!gcol.isColourByAttribute())
       {
-        SwingUtilities.invokeLater(fetcher);
+        tx.append("Label");
       }
+      comp.setIcon(null);
     }
-  }
-
-  public void saveDAS_actionPerformed(ActionEvent e)
-  {
-    dassourceBrowser
-            .saveProperties(jalview.bin.Cache.applicationProperties);
-  }
-
-  public void complete()
-  {
-    fetchDAS.setEnabled(true);
-    cancelDAS.setEnabled(false);
-    dassourceBrowser.setGuiEnabled(true);
-
-  }
-
-  public void cancelDAS_actionPerformed(ActionEvent e)
-  {
-    if (dasFeatureFetcher != null)
+    else
     {
-      dasFeatureFetcher.cancel();
+      Color newColor = gcol.getMaxColour();
+      comp.setBackground(newColor);
+      // System.err.println("Width is " + w / 2);
+      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
+      comp.setIcon(ficon);
+      // tt+="RGB value: Max (" + newColor.getRed() + ", "
+      // + newColor.getGreen() + ", " + newColor.getBlue()
+      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
+      // + ", " + minCol.getBlue() + ")");
     }
-    complete();
-  }
-
-  public void noDasSourceActive()
-  {
-    complete();
-    JvOptionPane.showInternalConfirmDialog(Desktop.desktop,
-            MessageManager.getString("label.no_das_sources_selected_warn"),
-            MessageManager.getString("label.no_das_sources_selected_title"),
-            JvOptionPane.DEFAULT_OPTION, JvOptionPane.INFORMATION_MESSAGE);
+    comp.setHorizontalAlignment(SwingConstants.CENTER);
+    comp.setText(tx.toString());
   }
 
   // ///////////////////////////////////////////////////////////////////////
@@ -1594,11 +1516,9 @@ public class FeatureSettings extends JPanel
 
   class ColorRenderer extends JLabel implements TableCellRenderer
   {
-    javax.swing.border.Border unselectedBorder = null;
-
-    javax.swing.border.Border selectedBorder = null;
+    Border unselectedBorder = null;
 
-    final String baseTT = "Click to edit, right/apple click for menu.";
+    Border selectedBorder = null;
 
     public ColorRenderer()
     {
@@ -1613,7 +1533,6 @@ public class FeatureSettings extends JPanel
     {
       FeatureColourI cellColour = (FeatureColourI) color;
       setOpaque(true);
-      setToolTipText(baseTT);
       setBackground(tbl.getBackground());
       if (!cellColour.isSimpleColour())
       {
@@ -1720,77 +1639,6 @@ public class FeatureSettings extends JPanel
     renderGraduatedColor(comp, gcol, w, h);
   }
 
-  public static void renderGraduatedColor(JLabel comp, FeatureColourI gcol,
-          int w, int h)
-  {
-    boolean thr = false;
-    StringBuilder tt = new StringBuilder();
-    StringBuilder tx = new StringBuilder();
-
-    if (gcol.isColourByAttribute())
-    {
-      tx.append(String.join(":", gcol.getAttributeName()));
-    }
-    else if (!gcol.isColourByLabel())
-    {
-      tx.append(MessageManager.getString("label.score"));
-    }
-    tx.append(" ");
-    if (gcol.isAboveThreshold())
-    {
-      thr = true;
-      tx.append(">");
-      tt.append("Thresholded (Above ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isBelowThreshold())
-    {
-      thr = true;
-      tx.append("<");
-      tt.append("Thresholded (Below ").append(gcol.getThreshold())
-              .append(") ");
-    }
-    if (gcol.isColourByLabel())
-    {
-      tt.append("Coloured by label text. ").append(tt);
-      if (thr)
-      {
-        tx.append(" ");
-      }
-      if (!gcol.isColourByAttribute())
-      {
-        tx.append("Label");
-      }
-      comp.setIcon(null);
-    }
-    else
-    {
-      Color newColor = gcol.getMaxColour();
-      comp.setBackground(newColor);
-      // System.err.println("Width is " + w / 2);
-      Icon ficon = new FeatureIcon(gcol, comp.getBackground(), w, h, thr);
-      comp.setIcon(ficon);
-      // tt+="RGB value: Max (" + newColor.getRed() + ", "
-      // + newColor.getGreen() + ", " + newColor.getBlue()
-      // + ")\nMin (" + minCol.getRed() + ", " + minCol.getGreen()
-      // + ", " + minCol.getBlue() + ")");
-    }
-    comp.setHorizontalAlignment(SwingConstants.CENTER);
-    comp.setText(tx.toString());
-    if (tt.length() > 0)
-    {
-      if (comp.getToolTipText() == null)
-      {
-        comp.setToolTipText(tt.toString());
-      }
-      else
-      {
-        comp.setToolTipText(
-                tt.append(" ").append(comp.getToolTipText()).toString());
-      }
-    }
-  }
-
   class ColorEditor extends AbstractCellEditor
           implements TableCellEditor, ActionListener
   {
@@ -1804,17 +1652,13 @@ public class FeatureSettings extends JPanel
 
     JButton button;
 
-    JColorChooser colorChooser;
-
-    JDialog dialog;
-
     protected static final String EDIT = "edit";
 
     int rowSelected = 0;
 
-    public ColorEditor(FeatureSettings me)
+    public ColorEditor(FeatureSettings fs)
     {
-      this.me = me;
+      this.me = fs;
       // Set up the editor (from the table's point of view),
       // which is a button.
       // This button brings up the color chooser dialog,
@@ -1823,73 +1667,69 @@ public class FeatureSettings extends JPanel
       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.
+     * Handles events from the editor button, and from the colour/filters
+     * dialog's OK button
      */
     @Override
     public void actionPerformed(ActionEvent e)
     {
-      // todo test e.getSource() instead here
-      if (EDIT.equals(e.getActionCommand()))
+      if (button == e.getSource())
       {
-        // 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);
+          /*
+           * simple colour chooser
+           */
+          String ttl = MessageManager.getString("label.select_colour");
+          ColourChooserListener listener = new ColourChooserListener() {
+            @Override
+            public void colourSelected(Color c)
+            {
+              currentColor = new FeatureColour(c);
+              me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+            }
+          };
+          JalviewColourChooser.showColourChooser(button,  ttl,  currentColor.getColour(), listener);
         }
         else
         {
-          // bring up graduated chooser.
+          /*
+           * variable colour and filters dialog
+           */
           chooser = new FeatureTypeSettings(me.fr, type);
-          chooser.setRequestFocusEnabled(true);
-          chooser.requestFocus();
+          /**
+           * @j2sNative
+           */
+          {
+            chooser.setRequestFocusEnabled(true);
+            chooser.requestFocus();
+          }
           chooser.addActionListener(this);
-          chooser.showTab(true);
+          // Make the renderer reappear.
+          fireEditingStopped();
         }
-        // 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);
+        FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
+        if (currentFilter == null)
         {
-          /*
-           * 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);
-          FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
-          if (currentFilter == null)
-          {
-            currentFilter = new FeatureMatcherSet();
-          }
-          Object[] data = ((FeatureTableModel) table.getModel())
-                  .getData()[rowSelected];
-          data[COLOUR_COLUMN] = currentColor;
-          data[FILTER_COLUMN] = currentFilter;
+          currentFilter = new FeatureMatcherSet();
         }
+        Object[] data = ((FeatureTableModel) table.getModel())
+                .getData()[rowSelected];
+        data[COLOUR_COLUMN] = currentColor;
+        data[FILTER_COLUMN] = currentFilter;
+
         fireEditingStopped();
         me.table.validate();
       }
@@ -1982,7 +1822,6 @@ public class FeatureSettings extends JPanel
                   chooser.getWidth(), chooser.getHeight());
           chooser.validate();
         }
-        chooser.showTab(false);
         fireEditingStopped();
       }
       else if (e.getSource() instanceof Component)
@@ -2024,7 +1863,6 @@ public class FeatureSettings extends JPanel
       button.setOpaque(true);
       button.setBackground(me.getBackground());
       button.setText(currentFilter.toString());
-      button.setToolTipText(currentFilter.toString());
       button.setIcon(null);
       return button;
     }