Merge branch 'merge_review/JAL-3490_2_11_2_develop' into develop
[jalview.git] / src / jalview / gui / AlignFrame.java
index b18d33c..1f3f409 100644 (file)
  */
 package jalview.gui;
 
+import java.awt.BorderLayout;
+import java.awt.Color;
+import java.awt.Component;
+import java.awt.Rectangle;
+import java.awt.Toolkit;
+import java.awt.datatransfer.Clipboard;
+import java.awt.datatransfer.DataFlavor;
+import java.awt.datatransfer.StringSelection;
+import java.awt.datatransfer.Transferable;
+import java.awt.dnd.DnDConstants;
+import java.awt.dnd.DropTargetDragEvent;
+import java.awt.dnd.DropTargetDropEvent;
+import java.awt.dnd.DropTargetEvent;
+import java.awt.dnd.DropTargetListener;
+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.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.awt.event.MouseEvent;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+import java.beans.PropertyChangeEvent;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Deque;
+import java.util.Enumeration;
+import java.util.Hashtable;
+import java.util.List;
+import java.util.Vector;
+
+import javax.swing.ButtonGroup;
+import javax.swing.JCheckBoxMenuItem;
+import javax.swing.JComponent;
+import javax.swing.JEditorPane;
+import javax.swing.JInternalFrame;
+import javax.swing.JLabel;
+import javax.swing.JLayeredPane;
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JPanel;
+import javax.swing.JScrollPane;
+import javax.swing.SwingUtilities;
+
+import ext.vamsas.ServiceHandle;
 import jalview.analysis.AlignmentSorter;
 import jalview.analysis.AlignmentUtils;
 import jalview.analysis.CrossRef;
 import jalview.analysis.Dna;
+import jalview.analysis.GeneticCodeI;
 import jalview.analysis.ParseProperties;
 import jalview.analysis.SequenceIdMatcher;
-import jalview.api.AlignExportSettingI;
+import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewControllerGuiI;
 import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
+import jalview.api.FeatureSettingsModelI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.SimilarityParamsI;
@@ -45,7 +99,7 @@ import jalview.commands.RemoveGapColCommand;
 import jalview.commands.RemoveGapsCommand;
 import jalview.commands.SlideSequencesCommand;
 import jalview.commands.TrimRegionCommand;
-import jalview.datamodel.AlignExportSettingBeanI;
+import jalview.datamodel.AlignExportSettingsAdapter;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.Alignment;
 import jalview.datamodel.AlignmentAnnotation;
@@ -64,6 +118,7 @@ import jalview.gui.ColourMenuHelper.ColourChangeListener;
 import jalview.gui.ViewSelectionMenu.ViewSetProvider;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
+import jalview.io.BackupFiles;
 import jalview.io.BioJsHTMLOutput;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
@@ -83,12 +138,14 @@ import jalview.io.ScoreMatrixFile;
 import jalview.io.TCoffeeScoreFile;
 import jalview.io.vcf.VCFLoader;
 import jalview.jbgui.GAlignFrame;
+import jalview.project.Jalview2XML;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
+import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
-import jalview.util.dialogrunner.RunResponse;
+import jalview.util.Platform;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -98,63 +155,15 @@ import jalview.ws.jws2.Jws2Discoverer;
 import jalview.ws.jws2.jabaws2.Jws2Instance;
 import jalview.ws.seqfetcher.DbSourceProxy;
 
-import java.awt.BorderLayout;
-import java.awt.Component;
-import java.awt.Rectangle;
-import java.awt.Toolkit;
-import java.awt.datatransfer.Clipboard;
-import java.awt.datatransfer.DataFlavor;
-import java.awt.datatransfer.StringSelection;
-import java.awt.datatransfer.Transferable;
-import java.awt.dnd.DnDConstants;
-import java.awt.dnd.DropTargetDragEvent;
-import java.awt.dnd.DropTargetDropEvent;
-import java.awt.dnd.DropTargetEvent;
-import java.awt.dnd.DropTargetListener;
-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.KeyAdapter;
-import java.awt.event.KeyEvent;
-import java.awt.event.MouseEvent;
-import java.awt.print.PageFormat;
-import java.awt.print.PrinterJob;
-import java.beans.PropertyChangeEvent;
-import java.beans.PropertyChangeListener;
-import java.io.File;
-import java.io.FileWriter;
-import java.io.PrintWriter;
-import java.net.URL;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Deque;
-import java.util.Enumeration;
-import java.util.Hashtable;
-import java.util.List;
-import java.util.Vector;
-
-import javax.swing.JCheckBoxMenuItem;
-import javax.swing.JEditorPane;
-import javax.swing.JFileChooser;
-import javax.swing.JInternalFrame;
-import javax.swing.JLayeredPane;
-import javax.swing.JMenu;
-import javax.swing.JMenuItem;
-import javax.swing.JScrollPane;
-import javax.swing.SwingUtilities;
-
 /**
  * DOCUMENT ME!
  * 
  * @author $author$
  * @version $Revision$
  */
+@SuppressWarnings("serial")
 public class AlignFrame extends GAlignFrame implements DropTargetListener,
-        IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener,
-        PropertyChangeListener
+        IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener
 {
 
   public static final int DEFAULT_WIDTH = 700;
@@ -330,40 +339,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     init();
   }
 
-  @Override
-  public void propertyChange(PropertyChangeEvent evt)
-  {
-    Desktop.getDesktop().propertyChange(evt);
-  }
-
-  /**
-   * BH 2018
-   * 
-   * @return true if we have any features
-   */
-  @Override
-  protected boolean haveAlignmentFeatures()
-  {
-    AlignmentI alignment = getViewport().getAlignment();
-
-    for (int i = 0; i < alignment.getHeight(); i++)
-    {
-      SequenceI seq = alignment.getSequenceAt(i);
-      for (String group : seq.getFeatures().getFeatureGroups(true))
-      {
-        if (group != null)
-          return true;
-      }
-    }
-    return false;
-  }
-
   /**
    * initalise the alignframe from the underlying viewport data and the
    * configurations
    */
   void init()
   {
+//       setBackground(Color.white); // BH 2019
+                 
     if (!Jalview.isHeadlessMode())
     {
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
@@ -412,12 +395,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (Desktop.desktop != null)
     {
       this.setDropTarget(new java.awt.dnd.DropTarget(this, this));
-      /**
-       * BH 2018 ignore service listeners
-       * 
-       * @j2sNative
-       * 
-       */
+      if (!Platform.isJS())
       {
         addServiceListeners();
       }
@@ -436,7 +414,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     addKeyListener();
 
-    final List<AlignmentPanel> selviews = new ArrayList<>();
+    final List<AlignmentViewPanel> selviews = new ArrayList<>();
     final List<AlignmentPanel> origview = new ArrayList<>();
     final String menuLabel = MessageManager
             .getString("label.copy_format_from");
@@ -648,7 +626,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         case KeyEvent.VK_BACK_SPACE:
           if (!viewport.cursorMode)
           {
-            cut_actionPerformed(null);
+            cut_actionPerformed();
           }
           else
           {
@@ -700,7 +678,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
         case KeyEvent.VK_F2:
           viewport.cursorMode = !viewport.cursorMode;
-          statusBar.setText(MessageManager
+          setStatus(MessageManager
                   .formatMessage("label.keyboard_editing_mode", new String[]
                   { (viewport.cursorMode ? "on" : "off") }));
           if (viewport.cursorMode)
@@ -786,9 +764,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     int aSize = alignPanels.size();
 
-    tabbedPane.setVisible(aSize > 1 || ap.av.viewName != null);
+    tabbedPane.setVisible(aSize > 1 || ap.av.getViewName() != null);
 
-    if (aSize == 1 && ap.av.viewName == null)
+    if (aSize == 1 && ap.av.getViewName() == null)
     {
       this.getContentPane().add(ap, BorderLayout.CENTER);
     }
@@ -801,7 +779,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       expandViews.setEnabled(true);
       gatherViews.setEnabled(true);
-      tabbedPane.addTab(ap.av.viewName, ap);
+      tabbedPane.addTab(ap.av.getViewName(), ap);
 
       ap.setVisible(false);
     }
@@ -824,7 +802,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     gatherViews.setEnabled(true);
     tabbedPane.setVisible(true);
     AlignmentPanel first = alignPanels.get(0);
-    tabbedPane.addTab(first.av.viewName, first);
+    tabbedPane.addTab(first.av.getViewName(), first);
     this.getContentPane().add(tabbedPane, BorderLayout.CENTER);
   }
 
@@ -871,7 +849,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Desktop.instance.removeJalviewPropertyChangeListener("services",
                 thisListener);
         closeMenuItem_actionPerformed(true);
-      };
+      }
     });
     // Finally, build the menu once to get current service state
     new Thread(new Runnable()
@@ -925,7 +903,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param av
    *          AlignViewport
    */
-  void setMenusFromViewport(AlignViewport av)
+  public void setMenusFromViewport(AlignViewport av)
   {
     padGapsMenuitem.setSelected(av.isPadGaps());
     colourTextMenuItem.setSelected(av.isShowColourText());
@@ -1016,10 +994,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return progressBar.operationInProgress();
   }
 
+  /**
+   * Sets the text of the status bar. Note that setting a null or empty value
+   * will cause the status bar to be hidden, with possibly undesirable flicker
+   * of the screen layout.
+   */
   @Override
   public void setStatus(String text)
   {
-    statusBar.setText(text);
+    statusBar.setText(text == null || text.isEmpty() ? " " : text);
   }
 
   /*
@@ -1036,9 +1019,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
-  public void fetchSequence_actionPerformed(ActionEvent e)
+  public void fetchSequence_actionPerformed()
   {
-    new jalview.gui.SequenceFetcher(this);
+    new SequenceFetcher(this);
   }
 
   @Override
@@ -1149,7 +1132,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (fileName == null || (currentFileFormat == null)
             || fileName.startsWith("http"))
     {
-      saveAs_actionPerformed(null);
+      saveAs_actionPerformed();
     }
     else
     {
@@ -1158,58 +1141,57 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Saves the alignment to a file with a name chosen by the user, if necessary
+   * warning if a file would be overwritten
    */
   @Override
-  public void saveAs_actionPerformed(ActionEvent e)
+  public void saveAs_actionPerformed()
   {
     String format = currentFileFormat == null ? null
             : currentFileFormat.getName();
-    final JalviewFileChooser chooser = JalviewFileChooser
+    JalviewFileChooser chooser = JalviewFileChooser
             .forWrite(Cache.getProperty("LAST_DIRECTORY"), format);
-    final AlignFrame us = this;
+
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.save_alignment_to_file"));
     chooser.setToolTipText(MessageManager.getString("action.save"));
 
-    chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
+    int value = chooser.showSaveDialog(this);
+
+    if (value != JalviewFileChooser.APPROVE_OPTION)
     {
-      @Override
-      public void run()
+      return;
+    }
+    currentFileFormat = chooser.getSelectedFormat();
+    // todo is this (2005) test now obsolete - value is never null?
+    while (currentFileFormat == null)
+    {
+      JvOptionPane.showInternalMessageDialog(Desktop.desktop,
+              MessageManager
+                      .getString("label.select_file_format_before_saving"),
+              MessageManager.getString("label.file_format_not_specified"),
+              JvOptionPane.WARNING_MESSAGE);
+      currentFileFormat = chooser.getSelectedFormat();
+      value = chooser.showSaveDialog(this);
+      if (value != JalviewFileChooser.APPROVE_OPTION)
       {
-        currentFileFormat = chooser.getSelectedFormat();
-        while (currentFileFormat == null)
-        {
-          JvOptionPane.showInternalMessageDialog(Desktop.desktop,
-                  MessageManager.getString(
-                          "label.select_file_format_before_saving"),
-                  MessageManager
-                          .getString("label.file_format_not_specified"),
-                  JvOptionPane.WARNING_MESSAGE);
-          currentFileFormat = chooser.getSelectedFormat();
-          chooser.showSaveDialog(us);
-        }
-
-        fileName = chooser.getSelectedFile().getPath();
+        return;
+      }
+    }
 
-        Cache.setProperty("DEFAULT_FILE_FORMAT",
-                currentFileFormat.getName());
+    fileName = chooser.getSelectedFile().getPath();
 
-        Cache.setProperty("LAST_DIRECTORY", fileName);
-        saveAlignment(fileName, currentFileFormat);
-      }
-    }).showSaveDialog(this);
+    Cache.setProperty("DEFAULT_FILE_FORMAT", currentFileFormat.getName());
+    Cache.setProperty("LAST_DIRECTORY", fileName);
+    saveAlignment(fileName, currentFileFormat);
   }
 
-  private boolean lastSaveSuccessful = false;
+  boolean lastSaveSuccessful = false;
 
-  private FileFormatI lastFormatSaved;
+  FileFormatI lastFormatSaved;
 
-  private String lastFilenameSaved;
+  String lastFilenameSaved;
 
   /**
    * Raise a dialog or status message for the last call to saveAlignment.
@@ -1230,7 +1212,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     else
     {
 
-      statusBar.setText(MessageManager.formatMessage(
+      setStatus(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
               { lastFilenameSaved, lastFormatSaved }));
 
@@ -1238,113 +1220,143 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return lastSaveSuccessful;
   }
 
+  /**
+   * Saves the alignment to the specified file path, in the specified format,
+   * which may be an alignment format, or Jalview project format. If the
+   * alignment has hidden regions, or the format is one capable of including
+   * non-sequence data (features, annotations, groups), then the user may be
+   * prompted to specify what to include in the output.
+   * 
+   * @param file
+   * @param format
+   */
   public void saveAlignment(String file, FileFormatI format)
   {
-    lastSaveSuccessful = false;
+    lastSaveSuccessful = true;
     lastFilenameSaved = file;
     lastFormatSaved = format;
-    AlignFrame us = this;
+
     if (FileFormat.Jalview.equals(format))
     {
       String shortName = title;
-
-      if (shortName.indexOf(java.io.File.separatorChar) > -1)
+      if (shortName.indexOf(File.separatorChar) > -1)
       {
         shortName = shortName.substring(
-                shortName.lastIndexOf(java.io.File.separatorChar) + 1);
+                shortName.lastIndexOf(File.separatorChar) + 1);
       }
-
-      lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file,
-              shortName);
+      lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName);
+      
+      statusBar.setText(MessageManager.formatMessage(
+              "label.successfully_saved_to_file_in_format", new Object[]
+              { fileName, format }));
+      
+      return;
     }
-    else
+
+    AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
+    Runnable cancelAction = new Runnable()
     {
-      AlignExportSettingI settings = getAlignmentForExport(format,
-              alignPanel, null);
-      settings.addActionListener(new ActionListener()
+      @Override
+      public void run()
       {
-        @Override
-        public void actionPerformed(ActionEvent e)
+        lastSaveSuccessful = false;
+      }
+    };
+    Runnable outputAction = new Runnable()
+    {
+      @Override
+      public void run()
+      {
+        // todo defer this to inside formatSequences (or later)
+        AlignmentExportData exportData = viewport
+                .getAlignExportData(options);
+        String output = new FormatAdapter(alignPanel, options)
+                .formatSequences(format, exportData.getAlignment(),
+                        exportData.getOmitHidden(),
+                        exportData.getStartEndPostions(),
+                        viewport.getAlignment().getHiddenColumns());
+        if (output == null)
         {
-
-          if (settings.isCancelled())
+          lastSaveSuccessful = false;
+        }
+        else
+        {
+          // create backupfiles object and get new temp filename destination
+          boolean doBackup = BackupFiles.getEnabled();
+          BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null;
+          try
           {
-            lastSaveSuccessful = false;
-            return;
-          }
-          AlignmentExportData exportData = settings.getAlignExportData();
-          FormatAdapter f = new FormatAdapter(alignPanel,
-                  exportData.getSettings());
-          String output = f.formatSequences(format,
-                  exportData.getAlignment(), // class
-                                             // cast
-                                             // exceptions
-                                             // will
-                  // occur in the distant future
-                  exportData.getOmitHidden(),
-                  exportData.getStartEndPostions(),
-                  f.getCacheSuffixDefault(format),
-                  viewport.getAlignment().getHiddenColumns());
-
-          if (output == null)
+            String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file;
+                       PrintWriter out = new PrintWriter(
+                    new FileWriter(tempFilePath));
+
+            out.print(output);
+            out.close();
+            AlignFrame.this.setTitle(file);
+            statusBar.setText(MessageManager.formatMessage(
+                  "label.successfully_saved_to_file_in_format", new Object[]
+                  { fileName, format.getName() }));
+            lastSaveSuccessful = true;
+          } catch (Exception ex)
           {
             lastSaveSuccessful = false;
+            ex.printStackTrace();
           }
-          else
+
+          if (doBackup)
           {
-            try
-            {
-              PrintWriter out = new PrintWriter(new FileWriter(file));
-
-              out.print(output);
-              out.close();
-              us.setTitle(file);
-              statusBar.setText(MessageManager.formatMessage(
-                      "label.successfully_saved_to_file_in_format",
-                      new Object[]
-                      { fileName, format.getName() }));
-            } catch (Exception ex)
-            {
-              lastSaveSuccessful = false;
-              ex.printStackTrace();
-            }
+            backupfiles.setWriteSuccess(lastSaveSuccessful);
+            // do the backup file roll and rename the temp file to actual file
+            lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
           }
         }
-      });
+      }
+    };
 
-      settings.doShowSettings();
+    /*
+     * show dialog with export options if applicable; else just do it
+     */
+    if (AlignExportOptions.isNeeded(viewport, format))
+    {
+      AlignExportOptions choices = new AlignExportOptions(
+              alignPanel.getAlignViewport(), format, options);
+      choices.setResponseAction(0, outputAction);
+      choices.setResponseAction(1, cancelAction);
+      choices.showDialog();
+    }
+    else
+    {
+      outputAction.run();
     }
   }
 
   /**
-   * DOCUMENT ME!
+   * Outputs the alignment to textbox in the requested format, if necessary
+   * first prompting the user for whether to include hidden regions or
+   * non-sequence data
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param fileFormatName
    */
   @Override
-  protected void outputText_actionPerformed(ActionEvent e)
+  protected void outputText_actionPerformed(String fileFormatName)
   {
     FileFormatI fileFormat = FileFormats.getInstance()
-            .forName(e.getActionCommand());
-    AlignExportSettingI settings = getAlignmentForExport(fileFormat,
-            alignPanel, null);
-    settings.addActionListener(new ActionListener()
+            .forName(fileFormatName);
+    AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
+    Runnable outputAction = new Runnable()
     {
       @Override
-      public void actionPerformed(ActionEvent e)
+      public void run()
       {
-        if (settings.isCancelled())
-        {
-          return;
-        }
-        AlignmentExportData exportData = settings.getAlignExportData();
+        // todo defer this to inside formatSequences (or later)
+        AlignmentExportData exportData = viewport
+                .getAlignExportData(options);
         CutAndPasteTransfer cap = new CutAndPasteTransfer();
         cap.setForInput(null);
         try
         {
           FileFormatI format = fileFormat;
-          cap.setText(new FormatAdapter(alignPanel, settings)
+          cap.setText(new FormatAdapter(alignPanel, options)
                   .formatSequences(format, exportData.getAlignment(),
                           exportData.getOmitHidden(),
                           exportData.getStartEndPostions(),
@@ -1358,19 +1370,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   oom);
           cap.dispose();
         }
-        // TODO Auto-generated method stub
-
       }
-    });
-    settings.doShowSettings();
-  }
-
-  public static AlignExportSettingI getAlignmentForExport(
-          FileFormatI format, AlignmentPanel alignPanel,
-          AlignExportSettingBeanI exportSettings)
-  {
+    };
 
-    return new AlignExportSettings(alignPanel, format, exportSettings);
+    /*
+     * show dialog with export options if applicable; else just do it
+     */
+    if (AlignExportOptions.isNeeded(viewport, fileFormat))
+    {
+      AlignExportOptions choices = new AlignExportOptions(
+              alignPanel.getAlignViewport(), fileFormat, options);
+      choices.setResponseAction(0, outputAction);
+      choices.showDialog();
+    }
+    else
+    {
+      outputAction.run();
+    }
   }
 
   /**
@@ -1399,33 +1415,39 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Creates a PNG image of the alignment and writes it to the given file. If
+   * the file is null, the user is prompted to choose a file.
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param f
    */
   @Override
   public void createPNG(File f)
   {
-    alignPanel.makePNG(f);
+    alignPanel.makeAlignmentImage(TYPE.PNG, f);
   }
 
   /**
-   * DOCUMENT ME!
+   * Creates an EPS image of the alignment and writes it to the given file. If
+   * the file is null, the user is prompted to choose a file.
    * 
-   * @param e
-   *          DOCUMENT ME!
+   * @param f
    */
   @Override
   public void createEPS(File f)
   {
-    alignPanel.makeEPS(f);
+    alignPanel.makeAlignmentImage(TYPE.EPS, f);
   }
 
+  /**
+   * Creates an SVG image of the alignment and writes it to the given file. If
+   * the file is null, the user is prompted to choose a file.
+   * 
+   * @param f
+   */
   @Override
   public void createSVG(File f)
   {
-    alignPanel.makeSVG(f);
+    alignPanel.makeAlignmentImage(TYPE.SVG, f);
   }
 
   @Override
@@ -1467,13 +1489,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     final JalviewFileChooser chooser = new JalviewFileChooser(
             jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
-    chooser.setDialogTitle(
-            MessageManager.getString("label.load_jalview_annotations"));
-    chooser.setToolTipText(
-            MessageManager.getString("label.load_jalview_annotations"));
-    chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
+    String tooltip = MessageManager.getString("label.load_jalview_annotations");
+    chooser.setDialogTitle(tooltip);
+    chooser.setToolTipText(tooltip);
+    chooser.setResponseHandler(0, new Runnable()
     {
-
       @Override
       public void run()
       {
@@ -1481,10 +1501,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
         loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
       }
-
     });
 
-    chooser.openDialog(this);
+    chooser.showOpenDialog(this);
   }
 
   /**
@@ -1523,9 +1542,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           closeView(alignPanel);
         }
       }
-
       if (closeAllTabs)
       {
+        if (featureSettings != null && featureSettings.isOpen())
+        {
+          featureSettings.close();
+          featureSettings = null;
+        }
         /*
          * this will raise an INTERNAL_FRAME_CLOSED event and this method will
          * be called recursively, with the frame now in 'closed' state
@@ -1759,10 +1782,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Calls AlignmentI.moveSelectedSequencesByOne with current sequence selection or the sequence under cursor in keyboard mode 
    * 
    * @param up
-   *          DOCUMENT ME!
+   *          or down (if !up)
    */
   public void moveSelectedSequences(boolean up)
   {
@@ -1770,8 +1793,23 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (sg == null)
     {
-      return;
+      if (viewport.cursorMode) 
+      {
+        sg = new SequenceGroup();
+        sg.addSequence(viewport.getAlignment()
+                .getSequenceAt(alignPanel.getSeqPanel().seqCanvas.cursorY),false);
+      } else {
+        return;
+      }
+    }
+    
+    if (sg.getSize() < 1)
+    {
+        return;
     }
+    
+    // TODO: JAL-3733 - add an event to the undo buffer for this !
+    
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             viewport.getHiddenRepSequences(), up);
     alignPanel.paintAlignment(true, false);
@@ -1889,7 +1927,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          DOCUMENT ME!
    */
   @Override
-  protected void copy_actionPerformed(ActionEvent e)
+  protected void copy_actionPerformed()
   {
     if (viewport.getSelectionGroup() == null)
     {
@@ -1941,7 +1979,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     Desktop.jalviewClipboard = new Object[] { seqs,
         viewport.getAlignment().getDataset(), hiddenColumns };
-    statusBar.setText(MessageManager.formatMessage(
+    setStatus(MessageManager.formatMessage(
             "label.copied_sequences_to_clipboard", new Object[]
             { Integer.valueOf(seqs.length).toString() }));
   }
@@ -2064,7 +2102,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 && Desktop.jalviewClipboard[1] != alignment.getDataset();
         // importDs==true instructs us to copy over new dataset sequences from
         // an existing alignment
-        Vector newDs = (importDs) ? new Vector() : null; // used to create
+        Vector<SequenceI> newDs = (importDs) ? new Vector<>() : null; // used to
+                                                                      // create
         // minimum dataset set
 
         for (int i = 0; i < sequences.length; i++)
@@ -2137,7 +2176,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     newGraphGroups.add(q, null);
                   }
                   newGraphGroups.set(newann.graphGroup,
-                          new Integer(++fgroup));
+                          Integer.valueOf(++fgroup));
                 }
                 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                         .intValue();
@@ -2184,7 +2223,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     newGraphGroups.add(q, null);
                   }
                   newGraphGroups.set(newann.graphGroup,
-                          new Integer(++fgroup));
+                          Integer.valueOf(++fgroup));
                 }
                 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                         .intValue();
@@ -2203,7 +2242,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
 
         // propagate alignment changed.
-        viewport.getRanges().setEndSeq(alignment.getHeight());
+        viewport.getRanges().setEndSeq(alignment.getHeight() - 1);
         if (annotationAdded)
         {
           // Duplicate sequence annotation in all views.
@@ -2358,26 +2397,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Action Cut (delete and copy) the selected region
    */
   @Override
-  protected void cut_actionPerformed(ActionEvent e)
+  protected void cut_actionPerformed()
   {
-    copy_actionPerformed(null);
-    delete_actionPerformed(null);
+    copy_actionPerformed();
+    delete_actionPerformed();
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @param e
-   *          DOCUMENT ME!
+   * Performs menu option to Delete the currently selected region
    */
   @Override
-  protected void delete_actionPerformed(ActionEvent evt)
+  protected void delete_actionPerformed()
   {
 
     SequenceGroup sg = viewport.getSelectionGroup();
@@ -2386,52 +2419,56 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return;
     }
 
+    Runnable okAction = new Runnable() 
+    {
+               @Override
+               public void run() 
+               {
+                   SequenceI[] cut = sg.getSequences()
+                           .toArray(new SequenceI[sg.getSize()]);
+
+                   addHistoryItem(new EditCommand(
+                           MessageManager.getString("label.cut_sequences"), Action.CUT,
+                           cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
+                           viewport.getAlignment()));
+
+                   viewport.setSelectionGroup(null);
+                   viewport.sendSelection();
+                   viewport.getAlignment().deleteGroup(sg);
+
+                   viewport.firePropertyChange("alignment", null,
+                           viewport.getAlignment().getSequences());
+                   if (viewport.getAlignment().getHeight() < 1)
+                   {
+                     try
+                     {
+                       AlignFrame.this.setClosed(true);
+                     } catch (Exception ex)
+                     {
+                     }
+                   }
+               }};
+
     /*
-     * If the cut affects all sequences, warn, remove highlighted columns
+     * If the cut affects all sequences, prompt for confirmation
      */
-    if (sg.getSize() == viewport.getAlignment().getHeight())
-    {
-      boolean isEntireAlignWidth = (((sg.getEndRes() - sg.getStartRes())
-              + 1) == viewport.getAlignment().getWidth()) ? true : false;
-      if (isEntireAlignWidth)
-      {
-        int confirm = JvOptionPane.showConfirmDialog(this,
-                MessageManager.getString("warn.delete_all"), // $NON-NLS-1$
-                MessageManager.getString("label.delete_all"), // $NON-NLS-1$
-                JvOptionPane.OK_CANCEL_OPTION);
-
-        if (confirm == JvOptionPane.CANCEL_OPTION
-                || confirm == JvOptionPane.CLOSED_OPTION)
-        {
-          return;
-        }
-      }
-      viewport.getColumnSelection().removeElements(sg.getStartRes(),
-              sg.getEndRes() + 1);
-    }
-    SequenceI[] cut = sg.getSequences()
-            .toArray(new SequenceI[sg.getSize()]);
-
-    addHistoryItem(new EditCommand(
-            MessageManager.getString("label.cut_sequences"), Action.CUT,
-            cut, sg.getStartRes(), sg.getEndRes() - sg.getStartRes() + 1,
-            viewport.getAlignment()));
-
-    viewport.setSelectionGroup(null);
-    viewport.sendSelection();
-    viewport.getAlignment().deleteGroup(sg);
-
-    viewport.firePropertyChange("alignment", null,
-            viewport.getAlignment().getSequences());
-    if (viewport.getAlignment().getHeight() < 1)
-    {
-      try
-      {
-        this.setClosed(true);
-      } catch (Exception ex)
-      {
-      }
-    }
+    boolean wholeHeight = sg.getSize() == viewport.getAlignment().getHeight();
+    boolean wholeWidth = (((sg.getEndRes() - sg.getStartRes())
+            + 1) == viewport.getAlignment().getWidth()) ? true : false;
+       if (wholeHeight && wholeWidth)
+       {
+           JvOptionPane dialog = JvOptionPane.newOptionDialog(Desktop.desktop);
+               dialog.setResponseHandler(0, okAction); // 0 = OK_OPTION
+           Object[] options = new Object[] { MessageManager.getString("action.ok"),
+                   MessageManager.getString("action.cancel") };
+               dialog.showDialog(MessageManager.getString("warn.delete_all"),
+                   MessageManager.getString("label.delete_all"),
+                   JvOptionPane.DEFAULT_OPTION, JvOptionPane.PLAIN_MESSAGE, null,
+                   options, options[0]);
+       } else 
+       {
+               okAction.run();
+       }
   }
 
   /**
@@ -2460,15 +2497,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
   {
-    SequenceGroup sg = new SequenceGroup();
-
-    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
-    {
-      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
-    }
+    SequenceGroup sg = new SequenceGroup(
+            viewport.getAlignment().getSequences());
 
     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
     viewport.setSelectionGroup(sg);
+    viewport.isSelectionGroupChanged(true);
     viewport.sendSelection();
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
@@ -2493,7 +2527,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     viewport.setSelectionGroup(null);
     viewport.getColumnSelection().clear();
-    viewport.setSelectionGroup(null);
+    viewport.setSearchResults(null);
     alignPanel.getIdPanel().getIdCanvas().searchResults = null;
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
@@ -2606,7 +2640,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 column, viewport.getAlignment());
       }
 
-      statusBar.setText(MessageManager
+      setStatus(MessageManager
               .formatMessage("label.removed_columns", new String[]
               { Integer.valueOf(trimRegion.getSize()).toString() }));
 
@@ -2656,7 +2690,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     addHistoryItem(removeGapCols);
 
-    statusBar.setText(MessageManager
+    setStatus(MessageManager
             .formatMessage("label.removed_empty_columns", new Object[]
             { Integer.valueOf(removeGapCols.getSize()).toString() }));
 
@@ -2730,15 +2764,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * DOCUMENT ME!
+   * Opens a Finder dialog
    * 
    * @param e
-   *          DOCUMENT ME!
    */
   @Override
   public void findMenuItem_actionPerformed(ActionEvent e)
   {
-    new Finder();
+    new Finder(alignPanel);
   }
 
   /**
@@ -2764,7 +2797,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     /*
      * Create a new AlignmentPanel (with its own, new Viewport)
      */
-    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel);
+    AlignmentPanel newap = new jalview.project.Jalview2XML()
+            .copyAlignPanel(alignPanel);
     if (!copyAnnotation)
     {
       /*
@@ -2776,10 +2810,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     newap.av.setGatherViewsHere(false);
 
-    if (viewport.viewName == null)
+    if (viewport.getViewName() == null)
     {
-      viewport.viewName = MessageManager
-              .getString("label.view_name_original");
+      viewport.setViewName(MessageManager
+              .getString("label.view_name_original"));
     }
 
     /*
@@ -2789,6 +2823,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     newap.av.setRedoList(viewport.getRedoList());
 
     /*
+     * copy any visualisation settings that are not saved in the project
+     */
+    newap.av.setColourAppliesToAllGroups(
+            viewport.getColourAppliesToAllGroups());
+
+    /*
      * Views share the same mappings; need to deregister any new mappings
      * created by copyAlignPanel, and register the new reference to the shared
      * mappings
@@ -2803,7 +2843,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       newap.refresh(true); // adjust layout of annotations
     }
 
-    newap.av.viewName = getNewViewName(viewTitle);
+    newap.av.setViewName(getNewViewName(viewTitle));
 
     addAlignmentPanel(newap, true);
     newap.alignmentChanged();
@@ -2866,9 +2906,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       if (comp instanceof AlignmentPanel)
       {
         AlignmentPanel ap = (AlignmentPanel) comp;
-        if (!existingNames.contains(ap.av.viewName))
+        if (!existingNames.contains(ap.av.getViewName()))
         {
-          existingNames.add(ap.av.viewName);
+          existingNames.add(ap.av.getViewName());
         }
       }
     }
@@ -2951,7 +2991,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
+      alignPanel.scrollToPosition(viewport.getSearchResults());
     }
   }
 
@@ -3010,7 +3050,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * @param toggleSeqs
    * @param toggleCols
    */
-  private void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
+  protected void toggleHiddenRegions(boolean toggleSeqs, boolean toggleCols)
   {
 
     boolean hide = false;
@@ -3098,6 +3138,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -3122,6 +3163,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -3143,7 +3185,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleAbove_actionPerformed(ActionEvent e)
   {
     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
-    // TODO: do we actually need to update overview for scale above change ?
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3157,6 +3199,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleLeft_actionPerformed(ActionEvent e)
   {
     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3170,6 +3213,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
     viewport.setScaleRightWrapped(scaleRight.isSelected());
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3223,9 +3267,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void featureSettings_actionPerformed(ActionEvent e)
   {
+    showFeatureSettingsUI();
+  }
+
+  @Override
+  public FeatureSettingsControllerI showFeatureSettingsUI()
+  {
     if (featureSettings != null)
     {
-      featureSettings.close();
+      featureSettings.closeOldSettings();
       featureSettings = null;
     }
     if (!showSeqFeatures.isSelected())
@@ -3235,6 +3285,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showSeqFeatures_actionPerformed(null);
     }
     featureSettings = new FeatureSettings(this);
+    return featureSettings;
   }
 
   /**
@@ -3274,15 +3325,42 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void alignmentProperties()
   {
-    JEditorPane editPane = new JEditorPane("text/html", "");
-    editPane.setEditable(false);
+    JComponent pane;
     StringBuffer contents = new AlignmentProperties(viewport.getAlignment())
+
             .formatAsHtml();
-    editPane.setText(
-            MessageManager.formatMessage("label.html_content", new Object[]
-            { contents.toString() }));
+    String content = MessageManager.formatMessage("label.html_content",
+            new Object[]
+            { contents.toString() });
+    contents = null;
+
+    if (Platform.isJS())
+    {
+      JLabel textLabel = new JLabel();
+      textLabel.setText(content);
+      textLabel.setBackground(Color.WHITE);
+      
+      pane = new JPanel(new BorderLayout());
+      ((JPanel) pane).setOpaque(true);
+      pane.setBackground(Color.WHITE);
+      ((JPanel) pane).add(textLabel, BorderLayout.NORTH);
+    }
+    else
+    /**
+     * Java only
+     * 
+     * @j2sIgnore
+     */
+    {
+      JEditorPane editPane = new JEditorPane("text/html", "");
+      editPane.setEditable(false);
+      editPane.setText(content);
+      pane = editPane;
+    }
+
     JInternalFrame frame = new JInternalFrame();
-    frame.getContentPane().add(new JScrollPane(editPane));
+
+    frame.getContentPane().add(new JScrollPane(pane));
 
     Desktop.addInternalFrame(frame, MessageManager
             .formatMessage("label.alignment_properties", new Object[]
@@ -3321,7 +3399,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               {
                 overview.dispose();
                 alignPanel.setOverviewPanel(null);
-              };
+              }
             });
     if (getKeyListeners().length > 0)
     {
@@ -3391,6 +3469,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
      * otherwise set the chosen colour scheme (or null for 'None')
      */
     ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
+            viewport,
             viewport.getAlignment(), viewport.getHiddenRepSequences());
     changeColour(cs);
   }
@@ -3660,9 +3739,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     frameTitle += " from ";
 
-    if (viewport.viewName != null)
+    if (viewport.getViewName() != null)
     {
-      frameTitle += viewport.viewName + " of ";
+      frameTitle += viewport.getViewName() + " of ";
     }
 
     frameTitle += this.title;
@@ -3758,7 +3837,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       sortByAnnotScore.removeAll();
       // almost certainly a quicker way to do this - but we keep it simple
-      Hashtable scoreSorts = new Hashtable();
+      Hashtable<String, String> scoreSorts = new Hashtable<>();
       AlignmentAnnotation aann[];
       for (SequenceI sqa : viewport.getAlignment().getSequences())
       {
@@ -3771,11 +3850,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
         }
       }
-      Enumeration labels = scoreSorts.keys();
+      Enumeration<String> labels = scoreSorts.keys();
       while (labels.hasMoreElements())
       {
         addSortByAnnotScoreMenuItem(sortByAnnotScore,
-                (String) labels.nextElement());
+                labels.nextElement());
       }
       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
       scoreSorts.clear();
@@ -3942,8 +4021,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     chooser.setToolTipText(
             MessageManager.getString("label.load_tree_file"));
 
-    chooser.response(new jalview.util.dialogrunner.RunResponse(
-            JalviewFileChooser.APPROVE_OPTION)
+    chooser.setResponseHandler(0,new Runnable()
     {
       @Override
       public void run()
@@ -3973,7 +4051,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   JvOptionPane.WARNING_MESSAGE);
         }
       }
-    }).openDialog(this);
+    });
+    chooser.showOpenDialog(this);
   }
 
   public TreePanel showNewickTree(NewickFile nf, String treeTitle)
@@ -4103,14 +4182,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             // No MSAWS used any more:
             // Vector msaws = null; // (Vector)
             // Discoverer.services.get("MsaWS");
-            Vector secstrpr = (Vector) Discoverer.services
+            Vector<ServiceHandle> secstrpr = Discoverer.services
                     .get("SecStrPred");
             if (secstrpr != null)
             {
               // Add any secondary structure prediction services
               for (int i = 0, j = secstrpr.size(); i < j; i++)
               {
-                final ext.vamsas.ServiceHandle sh = (ext.vamsas.ServiceHandle) secstrpr
+                final ext.vamsas.ServiceHandle sh = secstrpr
                         .get(i);
                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
                         .getServiceClient(sh);
@@ -4220,7 +4299,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param webService
    */
-  private void build_urlServiceMenu(JMenu webService)
+  protected void build_urlServiceMenu(JMenu webService)
   {
     // TODO: remove this code when 2.7 is released
     // DEBUG - alignmentView
@@ -4328,14 +4407,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * frame's DNA sequences to their aligned protein (amino acid) equivalents.
    */
   @Override
-  public void showTranslation_actionPerformed(ActionEvent e)
+  public void showTranslation_actionPerformed(GeneticCodeI codeTable)
   {
     AlignmentI al = null;
     try
     {
       Dna dna = new Dna(viewport, viewport.getViewAsVisibleContigs(true));
 
-      al = dna.translateCdna();
+      al = dna.translateCdna(codeTable);
     } catch (Exception ex)
     {
       jalview.bin.Cache.log.error(
@@ -4364,7 +4443,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       af.setFileFormat(this.currentFileFormat);
       final String newTitle = MessageManager
               .formatMessage("label.translation_of_params", new Object[]
-              { this.getTitle() });
+              { this.getTitle(), codeTable.getId() });
       af.setTitle(newTitle);
       if (Cache.getDefault(Preferences.ENABLE_SPLIT_FRAME, true))
       {
@@ -4489,8 +4568,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       : FormatAdapter.checkProtocol(fileName));
               if (protocol == DataSourceType.FILE)
               {
-                File fl = (file instanceof File ? (File) file
-                        : new File(fileName));
+                File fl;
+                if (file instanceof File) {
+                  fl = (File) file;
+                  Platform.cacheFileData(fl);
+                } else {
+                  fl = new File(fileName);
+                }
                 pdbfn = fl.getName();
               }
               else if (protocol == DataSourceType.URL)
@@ -4564,13 +4648,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   for (SequenceI toassoc : (SequenceI[]) fm[2])
                   {
                     PDBEntry pe = new AssociatePdbFileWithSeq()
-                            .associatePdbWithSeq((String) fm[0],
+                            .associatePdbWithSeq(fm[0].toString(),
                                     (DataSourceType) fm[1], toassoc, false,
                                     Desktop.instance);
                     if (pe != null)
                     {
                       System.err.println("Associated file : "
-                              + ((String) fm[0]) + " with "
+                              + (fm[0].toString()) + " with "
                               + toassoc.getDisplayId(true));
                       assocfiles++;
                     }
@@ -4670,7 +4754,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               changeColour(
                       new TCoffeeColourScheme(viewport.getAlignment()));
               isAnnotation = true;
-              statusBar.setText(MessageManager.getString(
+              setStatus(MessageManager.getString(
                       "label.successfully_pasted_tcoffee_scores_to_alignment"));
             }
             else
@@ -4713,7 +4797,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     new FileParse(file, sourceType));
             sm.parse();
             // todo: i18n this message
-            statusBar.setText(MessageManager.formatMessage(
+            setStatus(MessageManager.formatMessage(
                     "label.successfully_loaded_matrix",
                     sm.getMatrixName()));
           }
@@ -4731,7 +4815,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             if (parseFeaturesFile(file, sourceType))
             {
-              alignPanel.paintAlignment(true, true);
+              SplitFrame splitFrame = (SplitFrame) getSplitViewContainer();
+              if (splitFrame != null)
+              {
+                splitFrame.repaint();
+              }
+              else
+              {
+                alignPanel.paintAlignment(true, true);
+              }
             }
           }
           else
@@ -4787,6 +4879,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport = alignPanel.av;
       avc.setViewportAndAlignmentPanel(viewport, alignPanel);
       setMenusFromViewport(viewport);
+      if (featureSettings != null && featureSettings.isOpen()
+              && featureSettings.fr.getViewport() != viewport)
+      {
+        if (viewport.isShowSequenceFeatures())
+        {
+          // refresh the featureSettings to reflect UI change
+          showFeatureSettingsUI();
+        }
+        else
+        {
+          // close feature settings for this view.
+          featureSettings.close();
+        }
+      }
+
     }
 
     /*
@@ -4839,12 +4946,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     if (e.isPopupTrigger())
     {
       String msg = MessageManager.getString("label.enter_view_name");
-      String reply = JvOptionPane.showInternalInputDialog(this, msg, msg,
-              JvOptionPane.QUESTION_MESSAGE);
+      String ttl = tabbedPane.getTitleAt(tabbedPane.getSelectedIndex());
+      String reply = JvOptionPane.showInputDialog(msg, ttl);
 
       if (reply != null)
       {
-        viewport.viewName = reply;
+        viewport.setViewName(reply);
         // TODO warn if reply is in getExistingViewNames()?
         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
       }
@@ -4955,7 +5062,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         trimrs.setSelected(trimrs.isSelected());
         Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
                 Boolean.valueOf(trimrs.isSelected()).toString());
-      };
+      }
     });
     rfetch.add(trimrs);
     JMenuItem fetchr = new JMenuItem(
@@ -4984,6 +5091,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               @Override
               public void finished()
               {
+
+                for (FeatureSettingsModelI srcSettings : dbRefFetcher
+                        .getFeatureSettingsModels())
+                {
+
+                  alignPanel.av.mergeFeaturesStyle(srcSettings);
+                }
                 AlignFrame.this.setMenusForViewport();
               }
             });
@@ -4995,22 +5109,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     });
     rfetch.add(fetchr);
-    final AlignFrame me = this;
     new Thread(new Runnable()
     {
       @Override
       public void run()
       {
         final jalview.ws.SequenceFetcher sf = jalview.gui.SequenceFetcher
-                .getSequenceFetcherSingleton(me);
+                .getSequenceFetcherSingleton();
         javax.swing.SwingUtilities.invokeLater(new Runnable()
         {
           @Override
           public void run()
           {
-            String[] dbclasses = sf.getOrderedSupportedSources();
-            // sf.getDbInstances(jalview.ws.dbsources.DasSequenceSource.class);
-            // jalview.util.QuickSort.sort(otherdb, otherdb);
+            String[] dbclasses = sf.getNonAlignmentSources();
             List<DbSourceProxy> otherdb;
             JMenu dfetch = new JMenu();
             JMenu ifetch = new JMenu();
@@ -5027,12 +5138,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               {
                 continue;
               }
-              // List<DbSourceProxy> dbs=otherdb;
-              // otherdb=new ArrayList<DbSourceProxy>();
-              // for (DbSourceProxy db:dbs)
-              // {
-              // if (!db.isA(DBRefSource.ALIGNMENTDB)
-              // }
               if (mname == null)
               {
                 mname = "From " + dbclass;
@@ -5069,6 +5174,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                   @Override
                                   public void finished()
                                   {
+                                    FeatureSettingsModelI srcSettings = dassource[0]
+                                            .getFeatureColourScheme();
+                                    alignPanel.av.mergeFeaturesStyle(
+                                            srcSettings);
                                     AlignFrame.this.setMenusForViewport();
                                   }
                                 });
@@ -5361,7 +5470,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true, true);
+      alignPanel.paintAlignment(true,
+              viewport.needToUpdateStructureViews());
     }
   }
 
@@ -5382,6 +5492,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     if (avc.createGroup())
     {
+      if (applyAutoAnnotationSettings.isSelected())
+      {
+        alignPanel.updateAnnotation(true, false);
+      }
       alignPanel.alignmentChanged();
     }
   }
@@ -5472,7 +5586,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public List<? extends AlignmentViewPanel> getAlignPanels()
   {
-    return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
+    // alignPanels is never null
+    // return alignPanels == null ? Arrays.asList(alignPanel) : alignPanels;
+    return alignPanels;
   }
 
   /**
@@ -5641,15 +5757,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     colourMenu.add(textColour);
     colourMenu.addSeparator();
 
-    ColourMenuHelper.addMenuItems(colourMenu, this, viewport.getAlignment(),
-            false);
+    ButtonGroup bg = ColourMenuHelper.addMenuItems(colourMenu, this,
+            viewport.getAlignment(), false);
 
+    colourMenu.add(annotationColour);
+    bg.add(annotationColour);
     colourMenu.addSeparator();
     colourMenu.add(conservationMenuItem);
     colourMenu.add(modifyConservation);
     colourMenu.add(abovePIDThreshold);
     colourMenu.add(modifyPID);
-    colourMenu.add(annotationColour);
 
     ColourSchemeI colourScheme = viewport.getGlobalColourScheme();
     ColourMenuHelper.setColourSelected(colourMenu, colourScheme);
@@ -5676,24 +5793,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file"));
     chooser.setToolTipText(MessageManager.getString("label.load_vcf_file"));
     final AlignFrame us = this;
-    chooser.response(new RunResponse(JalviewFileChooser.APPROVE_OPTION)
+    chooser.setResponseHandler(0, new Runnable()
     {
       @Override
       public void run()
       {
+        String choice = chooser.getSelectedFile().getPath();
+        Cache.setProperty("LAST_DIRECTORY", choice);
+        SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
+        new VCFLoader(choice).loadVCF(seqs, us);
+      }
+    });
+    chooser.showOpenDialog(null);
 
-        {
-          String choice = chooser.getSelectedFile().getPath();
-          Cache.setProperty("LAST_DIRECTORY", choice);
-          SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
-          new VCFLoader(choice).loadVCF(seqs, us);
-        }
-
-      };
-    }).openDialog(null);
+  }
 
+  private Rectangle lastFeatureSettingsBounds = null;
+  @Override
+  public void setFeatureSettingsGeometry(Rectangle bounds)
+  {
+    lastFeatureSettingsBounds = bounds;
   }
 
+  @Override
+  public Rectangle getFeatureSettingsGeometry()
+  {
+    return lastFeatureSettingsBounds;
+  }
 }
 
 class PrintThread extends Thread