JAL-3274 resource path correction, code tidying (constants etc)
[jalview.git] / src / jalview / gui / FeatureSettings.java
index c0097cd..5aa9499 100644 (file)
  */
 package jalview.gui;
 
+import jalview.api.AlignViewportI;
 import jalview.api.FeatureColourI;
 import jalview.api.FeatureSettingsControllerI;
+import jalview.api.ViewStyleI;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.datamodel.features.FeatureMatcher;
@@ -32,18 +34,21 @@ 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.MessageManager;
 import jalview.util.Platform;
 import jalview.viewmodel.seqfeatures.FeatureRendererModel.FeatureSettingsBean;
+import jalview.viewmodel.styles.ViewStyle;
+import jalview.xml.binding.jalview.JalviewUserColours;
+import jalview.xml.binding.jalview.JalviewUserColours.Colour;
+import jalview.xml.binding.jalview.JalviewUserColours.Filter;
+import jalview.xml.binding.jalview.ObjectFactory;
 
 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;
@@ -81,8 +86,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,13 +97,20 @@ import javax.swing.JSlider;
 import javax.swing.JTable;
 import javax.swing.ListSelectionModel;
 import javax.swing.SwingConstants;
+import javax.swing.ToolTipManager;
 import javax.swing.border.Border;
 import javax.swing.event.ChangeEvent;
 import javax.swing.event.ChangeListener;
 import javax.swing.table.AbstractTableModel;
+import javax.swing.table.JTableHeader;
 import javax.swing.table.TableCellEditor;
 import javax.swing.table.TableCellRenderer;
 import javax.swing.table.TableColumn;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.JAXBElement;
+import javax.xml.bind.Marshaller;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamReader;
 
 public class FeatureSettings extends JPanel
         implements FeatureSettingsControllerI
@@ -125,7 +135,8 @@ public class FeatureSettings extends JPanel
 
   private static final int MIN_HEIGHT = 400;
 
-  private final static String BASE_TOOLTIP = "Click to edit, right-click for menu";
+  private final static String BASE_TOOLTIP = MessageManager
+          .getString("label.click_to_edit");
 
   final FeatureRenderer fr;
 
@@ -138,7 +149,9 @@ public class FeatureSettings extends JPanel
 
   float originalTransparency;
 
-  Map<String, FeatureMatcherSetI> originalFilters;
+  private ViewStyleI originalViewStyle;
+
+  private Map<String, FeatureMatcherSetI> originalFilters;
 
   final JInternalFrame frame;
 
@@ -157,12 +170,6 @@ public class FeatureSettings extends JPanel
 
   int selectedRow = -1;
 
-  JButton fetchDAS = new JButton();
-
-  JButton saveDAS = new JButton();
-
-  JButton cancelDAS = new JButton();
-
   boolean resettingTable = false;
 
   /*
@@ -191,6 +198,7 @@ public class FeatureSettings extends JPanel
     transparency.setMaximum(100 - originalTransparencyAsPercent);
 
     originalFilters = new HashMap<>(fr.getFeatureFilters()); // shallow copy
+    originalViewStyle = new ViewStyle(af.viewport.getViewStyle());
 
     try
     {
@@ -202,8 +210,6 @@ public class FeatureSettings extends JPanel
 
     table = new JTable()
     {
-      static final String tt = "Click to edit, right-click for menu"; // todo i18n
-      
       @Override
       public String getToolTipText(MouseEvent e)
       {
@@ -220,23 +226,25 @@ public class FeatureSettings extends JPanel
         case COLOUR_COLUMN:
           FeatureColourI colour = (FeatureColourI) table.getValueAt(row,
                   column);
-          tip = getColorTooltip(colour);
+          tip = getColorTooltip(colour, true);
           break;
         case FILTER_COLUMN:
           FeatureMatcherSet o = (FeatureMatcherSet) table.getValueAt(row,
                   column);
           tip = o.isEmpty()
-                  ? MessageManager.getString("label.filters_tooltip")
+                  ? MessageManager
+                          .getString("label.configure_feature_tooltip")
                   : o.toString();
           break;
         default:
           break;
         }
+
         return tip;
       }
 
       /**
-       * Position the tooltip at the bottom edge of, and half way across, the
+       * Position the tooltip near the bottom edge of, and half way across, the
        * current cell
        */
       @Override
@@ -246,28 +254,27 @@ public class FeatureSettings extends JPanel
         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);
+        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));
+    JTableHeader tableHeader = table.getTableHeader();
+    tableHeader.setFont(new Font("Verdana", Font.PLAIN, 12));
+    tableHeader.setReorderingAllowed(false);
     table.setFont(new Font("Verdana", Font.PLAIN, 12));
-
-    // table.setDefaultRenderer(Color.class, new ColorRenderer());
-    // table.setDefaultEditor(Color.class, new ColorEditor(this));
-    //
-    table.setDefaultEditor(FeatureColour.class, new ColorEditor(this));
+    ToolTipManager.sharedInstance().registerComponent(table);
+    table.setDefaultEditor(FeatureColour.class, new ColorEditor());
     table.setDefaultRenderer(FeatureColour.class, new ColorRenderer());
 
-    table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor(this));
+    table.setDefaultEditor(FeatureMatcherSet.class, new FilterEditor());
     table.setDefaultRenderer(FeatureMatcherSet.class, new FilterRenderer());
-    
+
     TableColumn colourColumn = new TableColumn(COLOUR_COLUMN, 75,
-            new ColorRenderer(), new ColorEditor(this));
+            new ColorRenderer(), new ColorEditor());
     table.addColumn(colourColumn);
 
     TableColumn filterColumn = new TableColumn(FILTER_COLUMN, 75,
-            new FilterRenderer(), new FilterEditor(this));
+            new FilterRenderer(), new FilterEditor());
     table.addColumn(filterColumn);
 
     table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
@@ -277,21 +284,23 @@ public class FeatureSettings extends JPanel
       @Override
       public void mousePressed(MouseEvent evt)
       {
-        selectedRow = table.rowAtPoint(evt.getPoint());
+        Point pt = evt.getPoint();
+        selectedRow = table.rowAtPoint(pt);
         String type = (String) table.getValueAt(selectedRow, TYPE_COLUMN);
         if (evt.isPopupTrigger())
         {
           Object colour = table.getValueAt(selectedRow, COLOUR_COLUMN);
-          popupSort(selectedRow, type, colour, fr.getMinMax(), evt.getX(),
-                  evt.getY());
+          showPopupMenu(selectedRow, type, colour, evt.getPoint());
         }
-        else if (evt.getClickCount() == 2)
+        else if (evt.getClickCount() == 2
+                && table.columnAtPoint(pt) == TYPE_COLUMN)
         {
           boolean invertSelection = evt.isAltDown();
           boolean toggleSelection = Platform.isControlDown(evt);
           boolean extendSelection = evt.isShiftDown();
           fr.ap.alignFrame.avc.markColumnsContainingFeatures(
                   invertSelection, extendSelection, toggleSelection, type);
+          fr.ap.av.sendSelection();
         }
       }
 
@@ -304,8 +313,7 @@ public class FeatureSettings extends JPanel
         {
           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());
+          showPopupMenu(selectedRow, type, colour, evt.getPoint());
         }
       }
     });
@@ -368,18 +376,9 @@ public class FeatureSettings extends JPanel
 
     frame = new JInternalFrame();
     frame.setContentPane(this);
-    if (Platform.isAMac())
-    {
-      Desktop.addInternalFrame(frame,
-              MessageManager.getString("label.sequence_feature_settings"),
-              600, 480);
-    }
-    else
-    {
-      Desktop.addInternalFrame(frame,
-              MessageManager.getString("label.sequence_feature_settings"),
-              600, 450);
-    }
+    Desktop.addInternalFrame(frame,
+            MessageManager.getString("label.sequence_feature_settings"),
+            600, Platform.isAMacAndNotJS() ? 480 : 450);
     frame.setMinimumSize(new Dimension(MIN_WIDTH, MIN_HEIGHT));
 
     frame.addInternalFrameListener(
@@ -390,62 +389,37 @@ public class FeatureSettings extends JPanel
                       javax.swing.event.InternalFrameEvent evt)
               {
                 fr.removePropertyChangeListener(change);
-              };
+              }
             });
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
     inConstruction = false;
   }
 
-  protected void popupSort(final int rowSelected, final String type,
-          final Object typeCol, final Map<String, float[][]> minmax, int x,
-          int y)
+  /**
+   * Constructs and shows a popup menu of possible actions on the selected row
+   * and feature type
+   * 
+   * @param rowSelected
+   * @param type
+   * @param typeCol
+   * @param pt
+   */
+  protected void showPopupMenu(final int rowSelected, final String type,
+          final Object typeCol, final Point pt)
   {
-    final FeatureColourI featureColour = (FeatureColourI) typeCol;
-
     JPopupMenu men = new JPopupMenu(MessageManager
             .formatMessage("label.settings_for_param", new String[]
             { type }));
-    JMenuItem scr = new JMenuItem(
-            MessageManager.getString("label.sort_by_score"));
-    men.add(scr);
-    final FeatureSettings me = this;
-    scr.addActionListener(new ActionListener()
-    {
-
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        me.af.avc
-                .sortAlignmentByFeatureScore(Arrays.asList(new String[]
-                { type }));
-      }
-
-    });
-    JMenuItem dens = new JMenuItem(
-            MessageManager.getString("label.sort_by_density"));
-    dens.addActionListener(new ActionListener()
-    {
-
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        me.af.avc
-                .sortAlignmentByFeatureDensity(Arrays.asList(new String[]
-                { type }));
-      }
-
-    });
-    men.add(dens);
+    final FeatureColourI featureColour = (FeatureColourI) typeCol;
 
     /*
-     * variable colour options include colour by label, by score,
-     * by selected attribute text, or attribute value
+     * menu option to select (or deselect) variable colour
      */
     final JCheckBoxMenuItem variableColourCB = new JCheckBoxMenuItem(
             MessageManager.getString("label.variable_colour"));
     variableColourCB.setSelected(!featureColour.isSimpleColour());
     men.add(variableColourCB);
-    
+
     /*
      * checkbox action listener doubles up as listener to OK
      * from the variable colour / filters dialog
@@ -457,12 +431,16 @@ public class FeatureSettings extends JPanel
       {
         if (e.getSource() == variableColourCB)
         {
+          men.setVisible(true); // BH 2018 for JavaScript because this is a
+                                // checkbox
+          men.setVisible(false); // BH 2018 for JavaScript because this is a
+                                 // checkbox
           if (featureColour.isSimpleColour())
           {
             /*
              * toggle simple colour to variable colour - show dialog
              */
-            FeatureTypeSettings fc = new FeatureTypeSettings(me.fr, type);
+            FeatureTypeSettings fc = new FeatureTypeSettings(fr, type);
             fc.addActionListener(this);
           }
           else
@@ -470,7 +448,8 @@ public class FeatureSettings extends JPanel
             /*
              * toggle variable to simple colour - show colour chooser
              */
-            String title = MessageManager.getString("label.select_colour");
+            String title = MessageManager
+                    .formatMessage("label.select_colour_for", type);
             ColourChooserListener listener = new ColourChooserListener()
             {
               @Override
@@ -479,15 +458,17 @@ public class FeatureSettings extends JPanel
                 table.setValueAt(new FeatureColour(c), rowSelected,
                         COLOUR_COLUMN);
                 table.validate();
-                me.updateFeatureRenderer(
+                updateFeatureRenderer(
                         ((FeatureTableModel) table.getModel()).getData(),
                         false);
               }
             };
-            JalviewColourChooser.showColourChooser(me, title, featureColour.getMaxColour(), listener);
+            JalviewColourChooser.showColourChooser(FeatureSettings.this,
+                    title, featureColour.getMaxColour(), listener);
           }
         }
-        else    {
+        else
+        {
           if (e.getSource() instanceof FeatureTypeSettings)
           {
             /*
@@ -496,12 +477,42 @@ public class FeatureSettings extends JPanel
              */
             FeatureColourI fci = fr.getFeatureColours().get(type);
             table.setValueAt(fci, rowSelected, COLOUR_COLUMN);
-            table.validate();
+            // BH 2018 setting a table value does not invalidate it.
+            // System.out.println("FeatureSettings is valied" +
+            // table.validate();
           }
         }
       }
+    });
 
+    men.addSeparator();
+
+    JMenuItem scr = new JMenuItem(
+            MessageManager.getString("label.sort_by_score"));
+    men.add(scr);
+    scr.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        af.avc.sortAlignmentByFeatureScore(Arrays.asList(new String[]
+                { type }));
+      }
+    });
+    JMenuItem dens = new JMenuItem(
+            MessageManager.getString("label.sort_by_density"));
+    dens.addActionListener(new ActionListener()
+    {
+
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        af.avc.sortAlignmentByFeatureDensity(Arrays.asList(new String[]
+                { type }));
+      }
     });
+    men.add(dens);
 
     JMenuItem selCols = new JMenuItem(
             MessageManager.getString("label.select_columns_containing"));
@@ -512,6 +523,7 @@ public class FeatureSettings extends JPanel
       {
         fr.ap.alignFrame.avc.markColumnsContainingFeatures(false, false,
                 false, type);
+        fr.ap.av.sendSelection();
       }
     });
     JMenuItem clearCols = new JMenuItem(MessageManager
@@ -523,6 +535,7 @@ public class FeatureSettings extends JPanel
       {
         fr.ap.alignFrame.avc.markColumnsContainingFeatures(true, false,
                 false, type);
+        fr.ap.av.sendSelection();
       }
     });
     JMenuItem hideCols = new JMenuItem(
@@ -533,6 +546,7 @@ public class FeatureSettings extends JPanel
       public void actionPerformed(ActionEvent arg0)
       {
         fr.ap.alignFrame.hideFeatureColumns(type, true);
+        fr.ap.av.sendSelection();
       }
     });
     JMenuItem hideOtherCols = new JMenuItem(
@@ -543,13 +557,14 @@ public class FeatureSettings extends JPanel
       public void actionPerformed(ActionEvent arg0)
       {
         fr.ap.alignFrame.hideFeatureColumns(type, false);
+        fr.ap.av.sendSelection();
       }
     });
     men.add(selCols);
     men.add(clearCols);
     men.add(hideCols);
     men.add(hideOtherCols);
-    men.show(table, x, y);
+    men.show(table, pt.x, pt.y);
   }
 
   @Override
@@ -606,7 +621,7 @@ public class FeatureSettings extends JPanel
       {
         fr.setGroupVisibility(check.getText(), check.isSelected());
         resetTable(new String[] { grp });
-        af.alignPanel.paintAlignment(true, true);
+        refreshDisplay();
       }
     });
     groupPanel.add(check);
@@ -704,7 +719,7 @@ public class FeatureSettings extends JPanel
         data[dataIndex][FILTER_COLUMN] = featureFilter == null
                 ? new FeatureMatcherSet()
                 : featureFilter;
-        data[dataIndex][SHOW_COLUMN] = new Boolean(
+        data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(
                 af.getViewport().getFeaturesDisplayed().isVisible(type));
         dataIndex++;
         displayableTypes.remove(type);
@@ -731,7 +746,7 @@ public class FeatureSettings extends JPanel
       data[dataIndex][FILTER_COLUMN] = featureFilter == null
               ? new FeatureMatcherSet()
               : featureFilter;
-      data[dataIndex][SHOW_COLUMN] = new Boolean(true);
+      data[dataIndex][SHOW_COLUMN] = Boolean.valueOf(true);
       dataIndex++;
       displayableTypes.remove(type);
     }
@@ -762,8 +777,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>
@@ -827,8 +842,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
    */
@@ -877,23 +892,22 @@ public class FeatureSettings extends JPanel
    */
   void load()
   {
-    // TODO: JAL-3048 relies on Castor XML parsing: not needed for JS-jalview core
-    // functionalty
-
     JalviewFileChooser chooser = new JalviewFileChooser("fc",
             SEQUENCE_FEATURE_COLOURS);
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.load_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.load"));
-
-    int value = chooser.showOpenDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    chooser.setResponseHandler(0, new Runnable()
     {
-      File file = chooser.getSelectedFile();
-      load(file);
-    }
+      @Override
+      public void run()
+      {
+        File file = chooser.getSelectedFile();
+        load(file);
+      }
+    });
+    chooser.showOpenDialog(this);
   }
 
   /**
@@ -908,30 +922,39 @@ public class FeatureSettings extends JPanel
       InputStreamReader in = new InputStreamReader(
               new FileInputStream(file), "UTF-8");
 
-      JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
+      JAXBContext jc = JAXBContext
+              .newInstance("jalview.xml.binding.jalview");
+      javax.xml.bind.Unmarshaller um = jc.createUnmarshaller();
+      XMLStreamReader streamReader = XMLInputFactory.newInstance()
+              .createXMLStreamReader(in);
+      JAXBElement<JalviewUserColours> jbe = um.unmarshal(streamReader,
+              JalviewUserColours.class);
+      JalviewUserColours jucs = jbe.getValue();
+
+      // JalviewUserColours jucs = JalviewUserColours.unmarshal(in);
 
       /*
        * load feature colours
        */
-      for (int i = jucs.getColourCount() - 1; i >= 0; i--)
+      for (int i = jucs.getColour().size() - 1; i >= 0; i--)
       {
-        jalview.schemabinding.version2.Colour newcol = jucs.getColour(i);
-        FeatureColourI colour = Jalview2XML.unmarshalColour(newcol);
+        Colour newcol = jucs.getColour().get(i);
+        FeatureColourI colour = jalview.project.Jalview2XML
+                .parseColour(newcol);
         fr.setColour(newcol.getName(), colour);
-        fr.setOrder(newcol.getName(), i / (float) jucs.getColourCount());
+        fr.setOrder(newcol.getName(), i / (float) jucs.getColour().size());
       }
 
       /*
        * 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++)
+      for (int i = 0; i < jucs.getFilter().size(); i++)
       {
-        jalview.schemabinding.version2.Filter filterModel = jucs
-                .getFilter(i);
+        Filter filterModel = jucs.getFilter().get(i);
         String featureType = filterModel.getFeatureType();
-        FeatureMatcherSetI filter = Jalview2XML.unmarshalFilter(featureType,
-                filterModel.getMatcherSet());
+        FeatureMatcherSetI filter = jalview.project.Jalview2XML
+                .parseFilter(featureType, filterModel.getMatcherSet());
         if (!filter.isEmpty())
         {
           fr.setFeatureFilter(featureType, filter);
@@ -944,8 +967,7 @@ public class FeatureSettings extends JPanel
       if (table != null)
       {
         resetTable(null);
-        Object[][] data = ((FeatureTableModel) table.getModel())
-                .getData();
+        Object[][] data = ((FeatureTableModel) table.getModel()).getData();
         ensureOrder(data);
         updateFeatureRenderer(data, false);
         table.repaint();
@@ -962,19 +984,17 @@ public class FeatureSettings extends JPanel
    */
   void save()
   {
-    // TODO: JAL-3048 not needed for Jalview-JS - save colours
     JalviewFileChooser chooser = new JalviewFileChooser("fc",
             SEQUENCE_FEATURE_COLOURS);
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.save_feature_colours"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
-
-    int value = chooser.showSaveDialog(this);
-
-    if (value == JalviewFileChooser.APPROVE_OPTION)
+    int option = chooser.showSaveDialog(this);
+    if (option == JalviewFileChooser.APPROVE_OPTION)
     {
-      save(chooser.getSelectedFile());
+      File file = chooser.getSelectedFile();
+      save(file);
     }
   }
 
@@ -989,8 +1009,8 @@ public class FeatureSettings extends JPanel
     ucs.setSchemeName("Sequence Features");
     try
     {
-      PrintWriter out = new PrintWriter(new OutputStreamWriter(
-              new FileOutputStream(file), "UTF-8"));
+      PrintWriter out = new PrintWriter(
+              new OutputStreamWriter(new FileOutputStream(file), "UTF-8"));
 
       /*
        * sort feature types by colour order, from 0 (highest)
@@ -1014,9 +1034,9 @@ public class FeatureSettings extends JPanel
       for (String featureType : sortedTypes)
       {
         FeatureColourI fcol = fr.getFeatureStyle(featureType);
-        jalview.schemabinding.version2.Colour col = Jalview2XML.marshalColour(
-                featureType, fcol);
-        ucs.addColour(col);
+        Colour col = jalview.project.Jalview2XML.marshalColour(featureType,
+                fcol);
+        ucs.getColour().add(col);
       }
 
       /*
@@ -1027,18 +1047,28 @@ public class FeatureSettings extends JPanel
         FeatureMatcherSetI filter = fr.getFeatureFilter(featureType);
         if (filter != null && !filter.isEmpty())
         {
-          Iterator<FeatureMatcherI> iterator = filter.getMatchers().iterator();
+          Iterator<FeatureMatcherI> iterator = filter.getMatchers()
+                  .iterator();
           FeatureMatcherI firstMatcher = iterator.next();
-          MatcherSet ms = Jalview2XML.marshalFilter(firstMatcher, iterator,
-                  filter.isAnded());
+          jalview.xml.binding.jalview.FeatureMatcherSet ms = jalview.project.Jalview2XML
+                  .marshalFilter(firstMatcher, iterator, filter.isAnded());
           Filter filterModel = new Filter();
           filterModel.setFeatureType(featureType);
           filterModel.setMatcherSet(ms);
-          ucs.addFilter(filterModel);
+          ucs.getFilter().add(filterModel);
         }
       }
+      JAXBContext jaxbContext = JAXBContext
+              .newInstance(JalviewUserColours.class);
+      Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
+      jaxbMarshaller.marshal(
+              new ObjectFactory().createJalviewUserColours(ucs), out);
 
-      ucs.marshal(out);
+      // jaxbMarshaller.marshal(object, pout);
+      // marshaller.marshal(object);
+      out.flush();
+
+      // ucs.marshal(out);
       out.close();
     } catch (Exception ex)
     {
@@ -1103,7 +1133,8 @@ public class FeatureSettings extends JPanel
       else
       {
         width[i] /= max; // normalize
-        fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for later
+        fr.setOrder(data[i][TYPE_COLUMN].toString(), width[i]); // store for
+                                                                // later
       }
       if (i > 0)
       {
@@ -1137,8 +1168,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
@@ -1149,7 +1180,7 @@ public class FeatureSettings extends JPanel
 
     if (fr.setFeaturePriority(rowData, visibleNew))
     {
-      af.alignPanel.paintAlignment(true, true);
+      refreshDisplay();
     }
   }
 
@@ -1247,22 +1278,6 @@ public class FeatureSettings extends JPanel
         }
       }
     });
-    help.setFont(JvSwingUtils.getLabelFont());
-    help.setText(MessageManager.getString("action.help"));
-    help.addActionListener(new ActionListener()
-    {
-      @Override
-      public void actionPerformed(ActionEvent e)
-      {
-        try
-        {
-          Help.showHelpWindow(HelpId.SequenceFeatureSettings);
-        } catch (HelpSetException e1)
-        {
-          e1.printStackTrace();
-        }
-      }
-    });
 
     JButton cancel = new JButton(MessageManager.getString("action.cancel"));
     cancel.setFont(JvSwingUtils.getLabelFont());
@@ -1274,6 +1289,7 @@ public class FeatureSettings extends JPanel
         fr.setTransparency(originalTransparency);
         fr.setFeatureFilters(originalFilters);
         updateFeatureRenderer(originalData);
+        af.getViewport().setViewStyle(originalViewStyle);
         close();
       }
     });
@@ -1324,7 +1340,7 @@ public class FeatureSettings extends JPanel
         if (!inConstruction)
         {
           fr.setTransparency((100 - transparency.getValue()) / 100f);
-          af.alignPanel.paintAlignment(true, true);
+          refreshDisplay();
         }
       }
     });
@@ -1333,8 +1349,42 @@ public class FeatureSettings extends JPanel
     transparency.setToolTipText(
             MessageManager.getString("label.transparency_tip"));
 
-    JPanel transPanel = new JPanel(new GridLayout(1, 2));
-    bigPanel.add(transPanel, BorderLayout.SOUTH);
+    boolean nucleotide = af.getViewport().getAlignment().isNucleotide();
+    String text = MessageManager.formatMessage("label.show_linked_features",
+            nucleotide
+                    ? MessageManager.getString("label.protein")
+                            .toLowerCase()
+                    : "CDS");
+    JCheckBox showComplement = new JCheckBox(text);
+    showComplement.setSelected(af.getViewport().isShowComplementFeatures());
+    showComplement.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        af.getViewport()
+                .setShowComplementFeatures(showComplement.isSelected());
+        refreshDisplay();
+      }
+    });
+
+    JCheckBox showComplementOnTop = new JCheckBox(
+            MessageManager.getString("label.on_top"));
+    showComplementOnTop
+            .setSelected(af.getViewport().isShowComplementFeaturesOnTop());
+    showComplementOnTop.addActionListener(new ActionListener()
+    {
+      @Override
+      public void actionPerformed(ActionEvent e)
+      {
+        af.getViewport().setShowComplementFeaturesOnTop(
+                showComplementOnTop.isSelected());
+        refreshDisplay();
+      }
+    });
+
+    JPanel lowerPanel = new JPanel(new GridLayout(1, 2));
+    bigPanel.add(lowerPanel, BorderLayout.SOUTH);
 
     JPanel transbuttons = new JPanel(new GridLayout(5, 1));
     transbuttons.add(optimizeOrder);
@@ -1342,8 +1392,21 @@ public class FeatureSettings extends JPanel
     transbuttons.add(sortByScore);
     transbuttons.add(sortByDens);
     transbuttons.add(help);
-    transPanel.add(transparency);
-    transPanel.add(transbuttons);
+
+    boolean hasComplement = af.getViewport().getCodingComplement() != null;
+    JPanel transPanelLeft = new JPanel(
+            new GridLayout(hasComplement ? 3 : 2, 1));
+    transPanelLeft.add(new JLabel(" Colour transparency" + ":"));
+    transPanelLeft.add(transparency);
+    if (hasComplement)
+    {
+      JPanel cp = new JPanel(new FlowLayout(FlowLayout.LEFT));
+      cp.add(showComplement);
+      cp.add(showComplementOnTop);
+      transPanelLeft.add(cp);
+    }
+    lowerPanel.add(transPanelLeft);
+    lowerPanel.add(transbuttons);
 
     JPanel buttonPanel = new JPanel();
     buttonPanel.add(ok);
@@ -1357,12 +1420,31 @@ public class FeatureSettings extends JPanel
   }
 
   /**
+   * Repaints alignment, structure and overview (if shown). If there is a
+   * complementary view which is showing this view's features, then also
+   * repaints that.
+   */
+  void refreshDisplay()
+  {
+    af.alignPanel.paintAlignment(true, true);
+    AlignViewportI complement = af.getViewport().getCodingComplement();
+    if (complement != null && complement.isShowComplementFeatures())
+    {
+      AlignFrame af2 = Desktop.getAlignFrameFor(complement);
+      af2.alignPanel.paintAlignment(true, true);
+    }
+  }
+
+  /**
    * Answers a suitable tooltip to show on the colour cell of the table
    * 
    * @param fcol
+   * @param withHint
+   *                   if true include 'click to edit' and similar text
    * @return
    */
-  public static String getColorTooltip(FeatureColourI fcol)
+  public static String getColorTooltip(FeatureColourI fcol,
+          boolean withHint)
   {
     if (fcol == null)
     {
@@ -1370,13 +1452,16 @@ public class FeatureSettings extends JPanel
     }
     if (fcol.isSimpleColour())
     {
-      return BASE_TOOLTIP;
+      return withHint ? BASE_TOOLTIP : null;
     }
     String description = fcol.getDescription();
     description = description.replaceAll("<", "&lt;");
     description = description.replaceAll(">", "&gt;");
     StringBuilder tt = new StringBuilder(description);
-    tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
+    if (withHint)
+    {
+      tt.append("<br>").append(BASE_TOOLTIP).append("</br>");
+    }
     return JvSwingUtils.wrapTooltip(true, tt.toString());
   }
 
@@ -1385,7 +1470,7 @@ public class FeatureSettings extends JPanel
   {
     boolean thr = false;
     StringBuilder tx = new StringBuilder();
-  
+
     if (gcol.isColourByAttribute())
     {
       tx.append(FeatureMatcher
@@ -1442,7 +1527,7 @@ public class FeatureSettings extends JPanel
     private String[] columnNames = {
         MessageManager.getString("label.feature_type"),
         MessageManager.getString("action.colour"),
-        MessageManager.getString("label.filter"),
+        MessageManager.getString("label.configuration"),
         MessageManager.getString("label.show") };
 
     private Object[][] data;
@@ -1492,13 +1577,22 @@ public class FeatureSettings extends JPanel
     }
 
     /**
-     * Answers the class of the object in column c of the first row of the table
+     * Answers the class of column c of the table
      */
     @Override
     public Class<?> getColumnClass(int c)
     {
-      Object v = getValueAt(0, c);
-      return v == null ? null : v.getClass();
+      switch (c)
+      {
+      case TYPE_COLUMN:
+        return String.class;
+      case COLOUR_COLUMN:
+        return FeatureColour.class;
+      case FILTER_COLUMN:
+        return FeatureMatcherSet.class;
+      default:
+        return Boolean.class;
+      }
     }
 
     @Override
@@ -1642,11 +1736,10 @@ public class FeatureSettings extends JPanel
     renderGraduatedColor(comp, gcol, w, h);
   }
 
+  @SuppressWarnings("serial")
   class ColorEditor extends AbstractCellEditor
           implements TableCellEditor, ActionListener
   {
-    FeatureSettings me;
-
     FeatureColourI currentColor;
 
     FeatureTypeSettings chooser;
@@ -1659,9 +1752,8 @@ public class FeatureSettings extends JPanel
 
     int rowSelected = 0;
 
-    public ColorEditor(FeatureSettings fs)
+    public ColorEditor()
     {
-      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,
@@ -1686,32 +1778,44 @@ public class FeatureSettings extends JPanel
           /*
            * simple colour chooser
            */
-          String ttl = MessageManager.getString("label.select_colour");
-          ColourChooserListener listener = new ColourChooserListener() {
+          String ttl = MessageManager
+                  .formatMessage("label.select_colour_for", type);
+          ColourChooserListener listener = new ColourChooserListener()
+          {
             @Override
             public void colourSelected(Color c)
             {
               currentColor = new FeatureColour(c);
-              me.table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+              table.setValueAt(currentColor, rowSelected, COLOUR_COLUMN);
+              fireEditingStopped();
+            }
+
+            @Override
+            public void cancel()
+            {
+              fireEditingStopped();
             }
           };
-          JalviewColourChooser.showColourChooser(button,  ttl,  currentColor.getColour(), listener);
+          JalviewColourChooser.showColourChooser(button, ttl,
+                  currentColor.getColour(), listener);
         }
         else
         {
           /*
            * variable colour and filters dialog
            */
-          chooser = new FeatureTypeSettings(me.fr, type);
+          chooser = new FeatureTypeSettings(fr, type);
+          if (!Platform.isJS())
           /**
-           * @j2sNative
+           * Java only
+           * 
+           * @j2sIgnore
            */
           {
             chooser.setRequestFocusEnabled(true);
             chooser.requestFocus();
           }
           chooser.addActionListener(this);
-          // Make the renderer reappear.
           fireEditingStopped();
         }
       }
@@ -1723,7 +1827,7 @@ public class FeatureSettings extends JPanel
          * update table data without triggering updateFeatureRenderer
          */
         currentColor = fr.getFeatureColours().get(type);
-        FeatureMatcherSetI currentFilter = me.fr.getFeatureFilter(type);
+        FeatureMatcherSetI currentFilter = fr.getFeatureFilter(type);
         if (currentFilter == null)
         {
           currentFilter = new FeatureMatcherSet();
@@ -1732,12 +1836,25 @@ public class FeatureSettings extends JPanel
                 .getData()[rowSelected];
         data[COLOUR_COLUMN] = currentColor;
         data[FILTER_COLUMN] = currentFilter;
-
         fireEditingStopped();
-        me.table.validate();
+        // SwingJS needs an explicit repaint() here,
+        // rather than relying upon no validation having
+        // occurred since the stopEditing call was made.
+        // Its laying out has not been stopped by the modal frame
+        table.validate();
+        table.repaint();
       }
     }
 
+    /**
+     * Override allows access to this method from anonymous inner classes
+     */
+    @Override
+    protected void fireEditingStopped()
+    {
+      super.fireEditingStopped();
+    }
+
     // Implement the one CellEditor method that AbstractCellEditor doesn't.
     @Override
     public Object getCellEditorValue()
@@ -1747,14 +1864,14 @@ public class FeatureSettings extends JPanel
 
     // Implement the one method defined by TableCellEditor.
     @Override
-    public Component getTableCellEditorComponent(JTable theTable, Object value,
-            boolean isSelected, int row, int column)
+    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();
+      type = table.getValueAt(row, TYPE_COLUMN).toString();
       button.setOpaque(true);
-      button.setBackground(me.getBackground());
+      button.setBackground(FeatureSettings.this.getBackground());
       if (!currentColor.isSimpleColour())
       {
         JLabel btn = new JLabel();
@@ -1776,14 +1893,14 @@ public class FeatureSettings extends JPanel
 
   /**
    * 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.
+   * 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.
    */
+  @SuppressWarnings("serial")
   class FilterEditor extends AbstractCellEditor
           implements TableCellEditor, ActionListener
   {
-    FeatureSettings me;
 
     FeatureMatcherSetI currentFilter;
 
@@ -1797,9 +1914,8 @@ public class FeatureSettings extends JPanel
 
     int rowSelected = 0;
 
-    public FilterEditor(FeatureSettings me)
+    public FilterEditor()
     {
-      this.me = me;
       button = new JButton();
       button.setActionCommand(EDIT);
       button.addActionListener(this);
@@ -1814,7 +1930,7 @@ public class FeatureSettings extends JPanel
     {
       if (button == e.getSource())
       {
-        FeatureTypeSettings chooser = new FeatureTypeSettings(me.fr, type);
+        FeatureTypeSettings chooser = new FeatureTypeSettings(fr, type);
         chooser.addActionListener(this);
         chooser.setRequestFocusEnabled(true);
         chooser.requestFocus();
@@ -1836,17 +1952,23 @@ public class FeatureSettings extends JPanel
          * update table data without triggering updateFeatureRenderer
          */
         FeatureColourI currentColor = fr.getFeatureColours().get(type);
-        currentFilter = me.fr.getFeatureFilter(type);
+        currentFilter = fr.getFeatureFilter(type);
         if (currentFilter == null)
         {
           currentFilter = new FeatureMatcherSet();
         }
+
         Object[] data = ((FeatureTableModel) table.getModel())
                 .getData()[rowSelected];
         data[COLOUR_COLUMN] = currentColor;
         data[FILTER_COLUMN] = currentFilter;
         fireEditingStopped();
-        me.table.validate();
+        // SwingJS needs an explicit repaint() here,
+        // rather than relying upon no validation having
+        // occurred since the stopEditing call was made.
+        // Its laying out has not been stopped by the modal frame
+        table.validate();
+        table.repaint();
       }
     }
 
@@ -1857,14 +1979,14 @@ public class FeatureSettings extends JPanel
     }
 
     @Override
-    public Component getTableCellEditorComponent(JTable theTable, Object value,
-            boolean isSelected, int row, int column)
+    public Component getTableCellEditorComponent(JTable theTable,
+            Object value, boolean isSelected, int row, int column)
     {
       currentFilter = (FeatureMatcherSetI) value;
       this.rowSelected = row;
-      type = me.table.getValueAt(row, TYPE_COLUMN).toString();
+      type = table.getValueAt(row, TYPE_COLUMN).toString();
       button.setOpaque(true);
-      button.setBackground(me.getBackground());
+      button.setBackground(FeatureSettings.this.getBackground());
       button.setText(currentFilter.toString());
       button.setIcon(null);
       return button;
@@ -1949,7 +2071,8 @@ class FeatureIcon implements Icon
         g.fillRect(s1, 0, e1 - s1, height);
       }
       g.setColor(gcol.getMaxColour());
-      g.fillRect(0, e1, width - e1, height);
+      // g.fillRect(0, e1, width - e1, height); // BH 2018
+      g.fillRect(e1, 0, width - e1, height);
     }
   }
 }