JAL-629 Much better way of dealing with list of filenames/URLs without an --open...
[jalview.git] / src / jalview / gui / AlignFrame.java
index eed9846..eb98d98 100644 (file)
@@ -48,6 +48,8 @@ import java.awt.print.PrinterJob;
 import java.beans.PropertyChangeEvent;
 import java.io.File;
 import java.io.FileWriter;
+import java.io.IOException;
+import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.net.URL;
 import java.util.ArrayList;
@@ -56,6 +58,7 @@ import java.util.Deque;
 import java.util.Enumeration;
 import java.util.Hashtable;
 import java.util.List;
+import java.util.Locale;
 import java.util.Vector;
 
 import javax.swing.ButtonGroup;
@@ -90,6 +93,7 @@ import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.SimilarityParamsI;
 import jalview.bin.Cache;
+import jalview.bin.Console;
 import jalview.bin.Jalview;
 import jalview.commands.CommandI;
 import jalview.commands.EditCommand;
@@ -108,6 +112,7 @@ import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
+import jalview.datamodel.ContactMatrixI;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -136,6 +141,7 @@ import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
 import jalview.io.ScoreMatrixFile;
 import jalview.io.TCoffeeScoreFile;
+import jalview.io.exceptions.ImageOutputException;
 import jalview.io.vcf.VCFLoader;
 import jalview.jbgui.GAlignFrame;
 import jalview.project.Jalview2XML;
@@ -143,9 +149,11 @@ import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
+import jalview.util.HttpUtils;
 import jalview.util.ImageMaker.TYPE;
 import jalview.util.MessageManager;
 import jalview.util.Platform;
+import jalview.util.imagemaker.BitmapImageSizing;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -345,8 +353,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   void init()
   {
-//       setBackground(Color.white); // BH 2019
-                 
+    setFrameIcon(null);
+
+    // setBackground(Color.white); // BH 2019
+
     if (!Jalview.isHeadlessMode())
     {
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
@@ -364,8 +374,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       // modifyPID.setEnabled(false);
     }
 
-    String sortby = jalview.bin.Cache.getDefault("SORT_ALIGNMENT",
-            "No sort");
+    String sortby = Cache.getDefault("SORT_ALIGNMENT", "No sort");
 
     if (sortby.equals("Id"))
     {
@@ -407,7 +416,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       wrapMenuItem_actionPerformed(null);
     }
 
-    if (jalview.bin.Cache.getDefault("SHOW_OVERVIEW", false))
+    if (Cache.getDefault("SHOW_OVERVIEW", false))
     {
       this.overviewMenuItem_actionPerformed(null);
     }
@@ -482,10 +491,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               }
             });
-    if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
+    if (Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase(Locale.ROOT)
             .indexOf("devel") > -1
-            || Cache.getDefault("VERSION", "DEVELOPMENT").toLowerCase()
-                    .indexOf("test") > -1)
+            || Cache.getDefault("VERSION", "DEVELOPMENT")
+                    .toLowerCase(Locale.ROOT).indexOf("test") > -1)
     {
       formatMenu.add(vsel);
     }
@@ -563,7 +572,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, 1);
+            alignPanel.getSeqPanel().moveCursor(0, 1, evt.isShiftDown());
           }
           break;
 
@@ -574,7 +583,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().moveCursor(0, -1);
+            alignPanel.getSeqPanel().moveCursor(0, -1, evt.isShiftDown());
           }
 
           break;
@@ -587,7 +596,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(-1, 0);
+            alignPanel.getSeqPanel().moveCursor(-1, 0, evt.isShiftDown());
           }
 
           break;
@@ -599,7 +608,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
           else
           {
-            alignPanel.getSeqPanel().moveCursor(1, 0);
+            alignPanel.getSeqPanel().moveCursor(1, 0, evt.isShiftDown());
           }
           break;
 
@@ -615,12 +624,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         // if (viewport.cursorMode)
         // {
         // alignPanel.seqPanel.insertNucAtCursor(false,"A");
-        // //System.out.println("A");
+        // //jalview.bin.Console.outPrintln("A");
         // }
         // break;
         /*
          * case KeyEvent.VK_CLOSE_BRACKET: if (viewport.cursorMode) {
-         * System.out.println("closing bracket"); } break;
+         * jalview.bin.Console.outPrintln("closing bracket"); } break;
          */
         case KeyEvent.VK_DELETE:
         case KeyEvent.VK_BACK_SPACE:
@@ -821,7 +830,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               @Override
               public void propertyChange(PropertyChangeEvent evt)
               {
-                // // System.out.println("Discoverer property change.");
+                // // jalview.bin.Console.outPrintln("Discoverer property
+                // change.");
                 // if (evt.getPropertyName().equals("services"))
                 {
                   SwingUtilities.invokeLater(new Runnable()
@@ -830,7 +840,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     @Override
                     public void run()
                     {
-                      System.err.println(
+                      jalview.bin.Console.errPrintln(
                               "Rebuild WS Menu for service change");
                       BuildWebServiceMenu();
                     }
@@ -845,7 +855,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       public void internalFrameClosed(
               javax.swing.event.InternalFrameEvent evt)
       {
-        // System.out.println("deregistering discoverer listener");
+        // jalview.bin.Console.outPrintln("deregistering discoverer listener");
         Desktop.instance.removeJalviewPropertyChangeListener("services",
                 thisListener);
         closeMenuItem_actionPerformed(true);
@@ -974,14 +984,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void setProgressBar(String message, long id)
   {
-    progressBar.setProgressBar(message, id);
+    if (!Platform.isHeadless() && progressBar != null)
+      progressBar.setProgressBar(message, id);
   }
 
   @Override
   public void registerHandler(final long id,
           final IProgressIndicatorHandler handler)
   {
-    progressBar.registerHandler(id, handler);
+    if (progressBar != null)
+      progressBar.registerHandler(id, handler);
   }
 
   /**
@@ -991,7 +1003,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public boolean operationInProgress()
   {
-    return progressBar.operationInProgress();
+    return progressBar == null ? false : progressBar.operationInProgress();
   }
 
   /**
@@ -1010,7 +1022,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public String getVersion()
   {
-    return jalview.bin.Cache.getProperty("VERSION");
+    return Cache.getProperty("VERSION");
   }
 
   public FeatureRenderer getFeatureRenderer()
@@ -1061,7 +1073,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         Desktop.instance.closeAssociatedWindows();
 
         FileLoader loader = new FileLoader();
-        DataSourceType protocol = fileName.startsWith("http:")
+        DataSourceType protocol = HttpUtils.startsWithHttpOrHttps(fileName)
                 ? DataSourceType.URL
                 : DataSourceType.FILE;
         loader.LoadFile(viewport, fileName, protocol, currentFileFormat);
@@ -1077,9 +1089,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         if (fileObject == null)
         {
 
-          DataSourceType protocol = (fileName.startsWith("http:")
-                  ? DataSourceType.URL
-                  : DataSourceType.FILE);
+          DataSourceType protocol = HttpUtils.startsWithHttpOrHttps(
+                  fileName) ? DataSourceType.URL : DataSourceType.FILE;
           newframe = loader.LoadFileWaitTillLoaded(fileName, protocol,
                   currentFileFormat);
         }
@@ -1130,7 +1141,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void save_actionPerformed(ActionEvent e)
   {
     if (fileName == null || (currentFileFormat == null)
-            || fileName.startsWith("http"))
+            || HttpUtils.startsWithHttpOrHttps(fileName))
     {
       saveAs_actionPerformed();
     }
@@ -1203,11 +1214,20 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (!lastSaveSuccessful)
     {
-      JvOptionPane.showInternalMessageDialog(this, MessageManager
-              .formatMessage("label.couldnt_save_file", new Object[]
-              { lastFilenameSaved }),
-              MessageManager.getString("label.error_saving_file"),
-              JvOptionPane.WARNING_MESSAGE);
+      if (!Platform.isHeadless())
+      {
+        JvOptionPane.showInternalMessageDialog(this, MessageManager
+                .formatMessage("label.couldnt_save_file", new Object[]
+                { lastFilenameSaved }),
+                MessageManager.getString("label.error_saving_file"),
+                JvOptionPane.WARNING_MESSAGE);
+      }
+      else
+      {
+        Console.error(MessageManager
+                .formatMessage("label.couldnt_save_file", new Object[]
+                { lastFilenameSaved }));
+      }
     }
     else
     {
@@ -1232,8 +1252,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public void saveAlignment(String file, FileFormatI format)
   {
+    saveAlignment(file, format, false);
+  }
+
+  public void saveAlignment(String file, FileFormatI format, boolean stdout)
+  {
     lastSaveSuccessful = true;
-    lastFilenameSaved = file;
+    if (!stdout)
+    {
+      lastFilenameSaved = file;
+    }
     lastFormatSaved = format;
 
     if (FileFormat.Jalview.equals(format))
@@ -1241,74 +1269,123 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       String shortName = title;
       if (shortName.indexOf(File.separatorChar) > -1)
       {
-        shortName = shortName.substring(
-                shortName.lastIndexOf(File.separatorChar) + 1);
+        shortName = shortName
+                .substring(shortName.lastIndexOf(File.separatorChar) + 1);
       }
-      lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file, shortName);
-      
+      // TODO deal with stdout=true
+      lastSaveSuccessful = new Jalview2XML().saveAlignment(this, file,
+              shortName);
+
+      Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
+      if (lastSaveSuccessful)
+      {
+        this.getViewport().setSavedUpToDate(true);
+      }
+
       statusBar.setText(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
-              { fileName, format }));
-      
+              { file, format }));
+
       return;
     }
 
     AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
-    Runnable cancelAction = new Runnable()
-    {
-      @Override
-      public void run()
+    Runnable cancelAction = () -> {
+      lastSaveSuccessful = false;
+    };
+    Runnable outputAction = () -> {
+      // 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)
       {
         lastSaveSuccessful = false;
       }
-    };
-    Runnable outputAction = new Runnable()
-    {
-      @Override
-      public void run()
+      else
       {
-        // 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)
+        // create backupfiles object and get new temp filename destination
+        boolean doBackup = BackupFiles.getEnabled() && !stdout;
+        BackupFiles backupfiles = null;
+        if (doBackup)
         {
-          lastSaveSuccessful = false;
+          Console.trace("ALIGNFRAME making backupfiles object for " + file);
+          backupfiles = new BackupFiles(file);
         }
-        else
+        try
         {
-          // create backupfiles object and get new temp filename destination
-          boolean doBackup = BackupFiles.getEnabled();
-          BackupFiles backupfiles = doBackup ? new BackupFiles(file) : null;
-          try
+          String tempFilePath = doBackup ? backupfiles.getTempFilePath()
+                  : file;
+          Console.trace("ALIGNFRAME setting PrintWriter");
+          PrintWriter out = stdout
+                  ? new PrintWriter(new OutputStreamWriter(System.out))
+                  : new PrintWriter(new FileWriter(tempFilePath));
+
+          if (backupfiles != null)
           {
-            String tempFilePath = doBackup ? backupfiles.getTempFilePath() : file;
-                       PrintWriter out = new PrintWriter(
-                    new FileWriter(tempFilePath));
+            Console.trace("ALIGNFRAME about to write to temp file "
+                    + backupfiles.getTempFilePath());
+          }
 
-            out.print(output);
+          out.print(output);
+          out.flush();
+          if (!stdout)
+          {
+            Console.trace("ALIGNFRAME about to close file");
             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)
+            Console.trace("ALIGNFRAME closed file");
+          }
+          AlignFrame.this.setTitle(stdout ? "STDOUT" : file);
+          if (stdout)
           {
-            lastSaveSuccessful = false;
-            ex.printStackTrace();
+            statusBar.setText(MessageManager.formatMessage(
+                    "label.successfully_printed_to_stdout_in_format",
+                    new Object[]
+                    { format.getName() }));
           }
-
-          if (doBackup)
+          else
           {
-            backupfiles.setWriteSuccess(lastSaveSuccessful);
-            // do the backup file roll and rename the temp file to actual file
-            lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
+            statusBar.setText(MessageManager.formatMessage(
+                    "label.successfully_saved_to_file_in_format",
+                    new Object[]
+                    { fileName, format.getName() }));
           }
+          lastSaveSuccessful = true;
+        } catch (IOException e)
+        {
+          lastSaveSuccessful = false;
+          Console.error(
+                  "ALIGNFRAME Something happened writing the temp file");
+          Console.error(e.getMessage());
+          Console.debug(Cache.getStackTraceString(e));
+        } catch (Exception ex)
+        {
+          lastSaveSuccessful = false;
+          Console.error(
+                  "ALIGNFRAME Something unexpected happened writing the temp file");
+          Console.error(ex.getMessage());
+          Console.debug(Cache.getStackTraceString(ex));
+        }
+
+        if (doBackup)
+        {
+          backupfiles.setWriteSuccess(lastSaveSuccessful);
+          Console.debug("ALIGNFRAME writing temp file was "
+                  + (lastSaveSuccessful ? "" : "NOT ") + "successful");
+          // do the backup file roll and rename the temp file to actual file
+          Console.trace("ALIGNFRAME about to rollBackupsAndRenameTempFile");
+          lastSaveSuccessful = backupfiles.rollBackupsAndRenameTempFile();
+          Console.debug("ALIGNFRAME performed rollBackupsAndRenameTempFile "
+                  + (lastSaveSuccessful ? "" : "un") + "successfully");
+        }
+
+        Console.debug("lastSaveSuccessful=" + lastSaveSuccessful);
+        if (lastSaveSuccessful)
+        {
+          AlignFrame.this.getViewport().setSavedUpToDate(true);
         }
       }
     };
@@ -1326,7 +1403,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      outputAction.run();
+      try
+      {
+        outputAction.run();
+      } catch (Exception e)
+      {
+        // TODO Auto-generated catch block
+        e.printStackTrace();
+      }
     }
   }
 
@@ -1343,33 +1427,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     FileFormatI fileFormat = FileFormats.getInstance()
             .forName(fileFormatName);
     AlignExportSettingsI options = new AlignExportSettingsAdapter(false);
-    Runnable outputAction = new Runnable()
-    {
-      @Override
-      public void run()
+    Runnable outputAction = () -> {
+      // todo defer this to inside formatSequences (or later)
+      AlignmentExportData exportData = viewport.getAlignExportData(options);
+      CutAndPasteTransfer cap = new CutAndPasteTransfer();
+      cap.setForInput(null);
+      try
       {
-        // 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, options)
-                  .formatSequences(format, exportData.getAlignment(),
-                          exportData.getOmitHidden(),
-                          exportData.getStartEndPostions(),
-                          viewport.getAlignment().getHiddenColumns()));
-          Desktop.addInternalFrame(cap, MessageManager.formatMessage(
-                  "label.alignment_output_command", new Object[]
-                  { fileFormat.getName() }), 600, 500);
-        } catch (OutOfMemoryError oom)
-        {
-          new OOMWarning("Outputting alignment as " + fileFormat.getName(),
-                  oom);
-          cap.dispose();
-        }
+        FileFormatI format = fileFormat;
+        cap.setText(new FormatAdapter(alignPanel, options).formatSequences(
+                format, exportData.getAlignment(),
+                exportData.getOmitHidden(),
+                exportData.getStartEndPostions(),
+                viewport.getAlignment().getHiddenColumns()));
+        Desktop.addInternalFrame(cap, MessageManager.formatMessage(
+                "label.alignment_output_command", new Object[]
+                { fileFormat.getName() }), 600, 500);
+      } catch (OutOfMemoryError oom)
+      {
+        new OOMWarning("Outputting alignment as " + fileFormat.getName(),
+                oom);
+        cap.dispose();
       }
     };
 
@@ -1385,7 +1463,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      outputAction.run();
+      try
+      {
+        outputAction.run();
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
     }
   }
 
@@ -1399,19 +1483,75 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void htmlMenuItem_actionPerformed(ActionEvent e)
   {
     HtmlSvgOutput htmlSVG = new HtmlSvgOutput(alignPanel);
-    htmlSVG.exportHTML(null);
+    try
+    {
+      htmlSVG.exportHTML(null);
+    } catch (ImageOutputException x)
+    {
+      // report problem to console and raise dialog
+    }
   }
 
   @Override
   public void bioJSMenuItem_actionPerformed(ActionEvent e)
   {
     BioJsHTMLOutput bjs = new BioJsHTMLOutput(alignPanel);
-    bjs.exportHTML(null);
+    try
+    {
+      bjs.exportHTML(null);
+    } catch (ImageOutputException x)
+    {
+      // report problem to console and raise dialog
+    }
   }
 
   public void createImageMap(File file, String image)
   {
-    alignPanel.makePNGImageMap(file, image);
+    try
+    {
+      alignPanel.makePNGImageMap(file, image);
+    } catch (ImageOutputException x)
+    {
+      // report problem to console and raise dialog
+    }
+  }
+
+  @Override
+  public void createPNG_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      createPNG(null);
+    } catch (ImageOutputException ioex)
+    {
+      // raise dialog, and report via console
+    }
+  }
+
+  @Override
+  public void createEPS_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      createEPS(null);
+    } catch (ImageOutputException ioex)
+    {
+      // raise dialog, and report via console
+    }
+
+  }
+
+  @Override
+  public void createSVG_actionPerformed(ActionEvent e)
+  {
+    try
+    {
+      createSVG(null);
+    } catch (ImageOutputException ioex)
+    {
+      // raise dialog, and report via console
+    }
+
   }
 
   /**
@@ -1420,10 +1560,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param f
    */
-  @Override
-  public void createPNG(File f)
+  public void createPNG(File f) throws ImageOutputException
+  {
+    createPNG(f, null, BitmapImageSizing.nullBitmapImageSizing());
+  }
+
+  public void createPNG(File f, String renderer, BitmapImageSizing userBis)
+          throws ImageOutputException
   {
-    alignPanel.makeAlignmentImage(TYPE.PNG, f);
+    alignPanel.makeAlignmentImage(TYPE.PNG, f, renderer, userBis);
   }
 
   /**
@@ -1432,10 +1577,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param f
    */
-  @Override
-  public void createEPS(File f)
+  public void createEPS(File f) throws ImageOutputException
+  {
+    createEPS(f, null);
+  }
+
+  public void createEPS(File f, String renderer) throws ImageOutputException
   {
-    alignPanel.makeAlignmentImage(TYPE.EPS, f);
+    alignPanel.makeAlignmentImage(TYPE.EPS, f, renderer);
   }
 
   /**
@@ -1444,10 +1593,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    * 
    * @param f
    */
-  @Override
-  public void createSVG(File f)
+  public void createSVG(File f) throws ImageOutputException
+  {
+    createSVG(f, null);
+  }
+
+  public void createSVG(File f, String renderer) throws ImageOutputException
   {
-    alignPanel.makeAlignmentImage(TYPE.SVG, f);
+    alignPanel.makeAlignmentImage(TYPE.SVG, f, renderer);
   }
 
   @Override
@@ -1487,20 +1640,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void associatedData_actionPerformed(ActionEvent e)
   {
     final JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
-    String tooltip = MessageManager.getString("label.load_jalview_annotations");
+    String tooltip = MessageManager
+            .getString("label.load_jalview_annotations");
     chooser.setDialogTitle(tooltip);
     chooser.setToolTipText(tooltip);
-    chooser.setResponseHandler(0, new Runnable()
-    {
-      @Override
-      public void run()
-      {
-        String choice = chooser.getSelectedFile().getPath();
-        jalview.bin.Cache.setProperty("LAST_DIRECTORY", choice);
-        loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
-      }
+    chooser.setResponseHandler(0, () -> {
+      String choice = chooser.getSelectedFile().getPath();
+      Cache.setProperty("LAST_DIRECTORY", choice);
+      loadJalviewDataFile(chooser.getSelectedFile(), null, null, null);
     });
 
     chooser.showOpenDialog(this);
@@ -1685,7 +1834,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       if (originalSource != viewport)
       {
-        Cache.log.warn(
+        Console.warn(
                 "Implementation worry: mismatch of viewport origin for undo");
       }
       originalSource.updateHiddenColumns();
@@ -1725,7 +1874,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       if (originalSource != viewport)
       {
-        Cache.log.warn(
+        Console.warn(
                 "Implementation worry: mismatch of viewport origin for redo");
       }
       originalSource.updateHiddenColumns();
@@ -1782,7 +1931,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   /**
-   * Calls AlignmentI.moveSelectedSequencesByOne with current sequence selection or the sequence under cursor in keyboard mode 
+   * Calls AlignmentI.moveSelectedSequencesByOne with current sequence selection
+   * or the sequence under cursor in keyboard mode
    * 
    * @param up
    *          or down (if !up)
@@ -1793,23 +1943,25 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (sg == null)
     {
-      if (viewport.cursorMode) 
+      if (viewport.cursorMode)
       {
         sg = new SequenceGroup();
-        sg.addSequence(viewport.getAlignment()
-                .getSequenceAt(alignPanel.getSeqPanel().seqCanvas.cursorY),false);
-      } else {
+        sg.addSequence(viewport.getAlignment().getSequenceAt(
+                alignPanel.getSeqPanel().seqCanvas.cursorY), false);
+      }
+      else
+      {
         return;
       }
     }
-    
+
     if (sg.getSize() < 1)
     {
-        return;
+      return;
     }
-    
+
     // TODO: JAL-3733 - add an event to the undo buffer for this !
-    
+
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             viewport.getHiddenRepSequences(), up);
     alignPanel.paintAlignment(true, false);
@@ -2229,10 +2381,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                         .intValue();
               }
             }
-            alignment.addAnnotation(sequences[i].getAnnotation()[a]); // annotation
-            // was
-            // duplicated
-            // earlier
+            // annotation was duplicated earlier
+            alignment.addAnnotation(sequences[i].getAnnotation()[a]);
+            // take care of contact matrix too
+            ContactMatrixI cm = sequences[i]
+                    .getContactMatrixFor(sequences[i].getAnnotation()[a]);
+            if (cm != null)
+            {
+              alignment.addContactListFor(sequences[i].getAnnotation()[a],
+                      cm);
+            }
+
             alignment.setAnnotationIndex(sequences[i].getAnnotation()[a],
                     a);
           }
@@ -2340,7 +2499,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     } catch (Exception ex)
     {
       ex.printStackTrace();
-      System.out.println("Exception whilst pasting: " + ex);
+      jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex);
       // could be anything being pasted in here
     }
 
@@ -2388,7 +2547,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     } catch (Exception ex)
     {
       ex.printStackTrace();
-      System.out.println("Exception whilst pasting: " + ex);
+      jalview.bin.Console.outPrintln("Exception whilst pasting: " + ex);
       // could be anything being pasted in here
     } catch (OutOfMemoryError oom)
     {
@@ -2419,56 +2578,61 @@ 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)
-                     {
-                     }
-                   }
-               }};
+    Runnable okAction = () -> {
+      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, prompt for confirmation
      */
-    boolean wholeHeight = sg.getSize() == viewport.getAlignment().getHeight();
+    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();
-       }
+    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
+    {
+      try
+      {
+        okAction.run();
+      } catch (Exception e)
+      {
+        e.printStackTrace();
+      }
+    }
   }
 
   /**
@@ -2573,6 +2737,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.invertColumnSelection();
     alignPanel.paintAlignment(true, false);
+    PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
 
@@ -2640,8 +2805,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 column, viewport.getAlignment());
       }
 
-      setStatus(MessageManager
-              .formatMessage("label.removed_columns", new String[]
+      setStatus(MessageManager.formatMessage("label.removed_columns",
+              new String[]
               { Integer.valueOf(trimRegion.getSize()).toString() }));
 
       addHistoryItem(trimRegion);
@@ -2690,8 +2855,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     addHistoryItem(removeGapCols);
 
-    setStatus(MessageManager
-            .formatMessage("label.removed_empty_columns", new Object[]
+    setStatus(MessageManager.formatMessage("label.removed_empty_columns",
+            new Object[]
             { Integer.valueOf(removeGapCols.getSize()).toString() }));
 
     // This is to maintain viewport position on first residue
@@ -2771,7 +2936,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void findMenuItem_actionPerformed(ActionEvent e)
   {
-    new Finder(alignPanel);
+    new Finder(alignPanel, false, null);
   }
 
   /**
@@ -2812,8 +2977,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     if (viewport.getViewName() == null)
     {
-      viewport.setViewName(MessageManager
-              .getString("label.view_name_original"));
+      viewport.setViewName(
+              MessageManager.getString("label.view_name_original"));
     }
 
     /*
@@ -2854,19 +3019,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     tabbedPane.setSelectedIndex(tabbedPane.getTabCount() - 1);
 
-    /*
-     * finally if new view has acquired an Overview window (because
-     * Preferences option to open Overview is selected), set its title
-     */
-    OverviewPanel ov = newap.overviewPanel;
-    if (ov != null)
-    {
-      String ttl = getOverviewTitle();
-      ((JInternalFrame) SwingUtilities
-              .getAncestorOfClass(JInternalFrame.class, ov))
-                      .setTitle(ttl);
-    }
-
     return newap;
   }
 
@@ -3353,7 +3505,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       JLabel textLabel = new JLabel();
       textLabel.setText(content);
       textLabel.setBackground(Color.WHITE);
-      
+
       pane = new JPanel(new BorderLayout());
       ((JPanel) pane).setOpaque(true);
       pane.setBackground(Color.WHITE);
@@ -3389,8 +3541,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void overviewMenuItem_actionPerformed(ActionEvent e)
   {
-    boolean showHiddenRegions = Cache.getDefault(Preferences.SHOW_OV_HIDDEN_AT_START,
-                false);
+    boolean showHiddenRegions = Cache
+            .getDefault(Preferences.SHOW_OV_HIDDEN_AT_START, false);
     openOverviewPanel(showHiddenRegions);
   }
 
@@ -3401,14 +3553,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return alignPanel.overviewPanel;
     }
     JInternalFrame frame = new JInternalFrame();
-    final OverviewPanel overview = new OverviewPanel(alignPanel, showHidden);
+    final OverviewPanel overview = new OverviewPanel(alignPanel, frame,
+            showHidden);
     frame.setContentPane(overview);
-    String overviewTitle = getOverviewTitle();
-    Desktop.addInternalFrame(frame, overviewTitle, true, frame.getWidth(), frame.getHeight(),
-            true, true);
+    Desktop.addInternalFrame(frame, "", true, frame.getWidth(),
+            frame.getHeight(), true, true);
+    frame.setFrameIcon(null);
     frame.pack();
     frame.setLayer(JLayeredPane.PALETTE_LAYER);
-    final AlignmentPanel thePanel = this.alignPanel; 
+    final AlignmentPanel thePanel = this.alignPanel;
     frame.addInternalFrameListener(
             new javax.swing.event.InternalFrameAdapter()
             {
@@ -3426,27 +3579,9 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
     alignPanel.setOverviewPanel(overview);
-    
-    return overview;
-  }
+    alignPanel.setOverviewTitle(this);
 
-  /**
-   * Constructs a title for the Overview window including the alignment window's
-   * title, and view name (if applicable)
-   * 
-   * @return
-   */
-  public String getOverviewTitle()
-  {
-    String overviewTitle = MessageManager
-            .formatMessage("label.overview_params", new Object[]
-            { this.getTitle() });
-    String viewName = alignPanel.getViewName();
-    if (viewName != null)
-    {
-      overviewTitle += (" " + viewName);
-    }
-    return overviewTitle;
+    return overview;
   }
 
   @Override
@@ -3509,8 +3644,8 @@ 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());
+            viewport, viewport.getAlignment(),
+            viewport.getHiddenRepSequences());
     changeColour(cs);
   }
 
@@ -3893,8 +4028,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       Enumeration<String> labels = scoreSorts.keys();
       while (labels.hasMoreElements())
       {
-        addSortByAnnotScoreMenuItem(sortByAnnotScore,
-                labels.nextElement());
+        addSortByAnnotScoreMenuItem(sortByAnnotScore, labels.nextElement());
       }
       sortByAnnotScore.setVisible(scoreSorts.size() > 0);
       scoreSorts.clear();
@@ -4054,42 +4188,36 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     // Pick the tree file
     JalviewFileChooser chooser = new JalviewFileChooser(
-            jalview.bin.Cache.getProperty("LAST_DIRECTORY"));
+            Cache.getProperty("LAST_DIRECTORY"));
     chooser.setFileView(new JalviewFileView());
     chooser.setDialogTitle(
             MessageManager.getString("label.select_newick_like_tree_file"));
     chooser.setToolTipText(
             MessageManager.getString("label.load_tree_file"));
 
-    chooser.setResponseHandler(0,new Runnable()
-    {
-      @Override
-      public void run()
+    chooser.setResponseHandler(0, () -> {
+      String filePath = chooser.getSelectedFile().getPath();
+      Cache.setProperty("LAST_DIRECTORY", filePath);
+      NewickFile fin = null;
+      try
       {
-        String filePath = chooser.getSelectedFile().getPath();
-        Cache.setProperty("LAST_DIRECTORY", filePath);
-        NewickFile fin = null;
-        try
-        {
-          fin = new NewickFile(new FileParse(chooser.getSelectedFile(),
-                  DataSourceType.FILE));
-          viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
-        } catch (Exception ex)
-        {
-          JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
-                  MessageManager
-                          .getString("label.problem_reading_tree_file"),
-                  JvOptionPane.WARNING_MESSAGE);
-          ex.printStackTrace();
-        }
-        if (fin != null && fin.hasWarningMessage())
-        {
-          JvOptionPane.showMessageDialog(Desktop.desktop,
-                  fin.getWarningMessage(),
-                  MessageManager.getString(
-                          "label.possible_problem_with_tree_file"),
-                  JvOptionPane.WARNING_MESSAGE);
-        }
+        fin = new NewickFile(new FileParse(chooser.getSelectedFile(),
+                DataSourceType.FILE));
+        viewport.setCurrentTree(showNewickTree(fin, filePath).getTree());
+      } catch (Exception ex)
+      {
+        JvOptionPane.showMessageDialog(Desktop.desktop, ex.getMessage(),
+                MessageManager.getString("label.problem_reading_tree_file"),
+                JvOptionPane.WARNING_MESSAGE);
+        ex.printStackTrace();
+      }
+      if (fin != null && fin.hasWarningMessage())
+      {
+        JvOptionPane.showMessageDialog(Desktop.desktop,
+                fin.getWarningMessage(),
+                MessageManager
+                        .getString("label.possible_problem_with_tree_file"),
+                JvOptionPane.WARNING_MESSAGE);
       }
     });
     chooser.showOpenDialog(this);
@@ -4156,6 +4284,57 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return tp;
   }
 
+  public void showContactMapTree(AlignmentAnnotation aa, ContactMatrixI cm)
+  {
+    int x = 4, y = 5;
+    int w = 400, h = 500;
+
+    try
+    {
+      NewickFile fin = new NewickFile(
+              new FileParse(cm.getNewick(), DataSourceType.PASTE));
+      String title = aa.label + " " + cm.getTreeMethod() + " tree"
+              + (aa.sequenceRef != null
+                      ? (" for " + aa.sequenceRef.getDisplayId(false))
+                      : "");
+
+      showColumnWiseTree(fin, aa, title, w, h, x, y);
+    } catch (Throwable xx)
+    {
+      Console.error("Unexpected exception showing tree for contact matrix",
+              xx);
+    }
+  }
+
+  public TreePanel showColumnWiseTree(NewickFile nf, AlignmentAnnotation aa,
+          String treeTitle, int w, int h, int x, int y)
+  {
+    try
+    {
+      nf.parse();
+      if (nf.getTree() == null)
+      {
+        return null;
+      }
+      TreePanel tp = new TreePanel(alignPanel, nf, aa, treeTitle);
+
+      tp.setSize(w, h);
+
+      if (x > 0 && y > 0)
+      {
+        tp.setLocation(x, y);
+      }
+
+      Desktop.addInternalFrame(tp, treeTitle, w, h);
+      return tp;
+    } catch (Throwable xx)
+    {
+      Console.error("Unexpected exception showing tree for contact matrix",
+              xx);
+    }
+    return null;
+  }
+
   private boolean buildingMenu = false;
 
   /**
@@ -4168,7 +4347,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       try
       {
-        System.err.println("Waiting for building menu to finish.");
+        jalview.bin.Console
+                .errPrintln("Waiting for building menu to finish.");
         Thread.sleep(10);
       } catch (Exception e)
       {
@@ -4184,7 +4364,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         final List<JMenuItem> legacyItems = new ArrayList<>();
         try
         {
-          // System.err.println("Building ws menu again "
+          // jalview.bin.Console.errPrintln("Building ws menu again "
           // + Thread.currentThread());
           // TODO: add support for context dependent disabling of services based
           // on
@@ -4229,8 +4409,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               // Add any secondary structure prediction services
               for (int i = 0, j = secstrpr.size(); i < j; i++)
               {
-                final ext.vamsas.ServiceHandle sh = secstrpr
-                        .get(i);
+                final ext.vamsas.ServiceHandle sh = secstrpr.get(i);
                 jalview.ws.WSMenuEntryProviderI impl = jalview.ws.jws1.Discoverer
                         .getServiceClient(sh);
                 int p = secstrmenu.getItemCount();
@@ -4274,9 +4453,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   webService.add(me.webServiceNoServices);
                 }
                 // TODO: move into separate menu builder class.
-                boolean new_sspred = false;
-                if (Cache.getDefault("SHOW_JWS2_SERVICES", true))
                 {
+                  // logic for 2.11.1.4 is
+                  // always look to see if there is a discover. if there isn't
+                  // we can't show any Jws2 services
+                  // if there are services available, show them - regardless of
+                  // the 'show JWS2 preference'
+                  // if the discoverer is running then say so
+                  // otherwise offer to trigger discovery if 'show JWS2' is not
+                  // enabled
                   Jws2Discoverer jws2servs = Jws2Discoverer.getDiscoverer();
                   if (jws2servs != null)
                   {
@@ -4285,7 +4470,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       jws2servs.attachWSMenuEntry(webService, me);
                       for (Jws2Instance sv : jws2servs.getServices())
                       {
-                        if (sv.description.toLowerCase().contains("jpred"))
+                        if (sv.description.toLowerCase(Locale.ROOT)
+                                .contains("jpred"))
                         {
                           for (JMenuItem jmi : legacyItems)
                           {
@@ -4293,8 +4479,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                           }
                         }
                       }
-
                     }
+
                     if (jws2servs.isRunning())
                     {
                       JMenuItem tm = new JMenuItem(
@@ -4302,6 +4488,26 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       tm.setEnabled(false);
                       webService.add(tm);
                     }
+                    else if (!Cache.getDefault("SHOW_JWS2_SERVICES", true))
+                    {
+                      JMenuItem enableJws2 = new JMenuItem(
+                              "Discover Web Services");
+                      enableJws2.setToolTipText(
+                              "Select to start JABA Web Service discovery (or enable option in Web Service preferences)");
+                      enableJws2.setEnabled(true);
+                      enableJws2.addActionListener(new ActionListener()
+                      {
+
+                        @Override
+                        public void actionPerformed(ActionEvent e)
+                        {
+                          // start service discoverer, but ignore preference
+                          Desktop.instance.startServiceDiscovery(false,
+                                  true);
+                        }
+                      });
+                      webService.add(enableJws2);
+                    }
                   }
                 }
                 build_urlServiceMenu(me.webService);
@@ -4319,7 +4525,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 }
               } catch (Exception e)
               {
-                Cache.log.debug(
+                Console.debug(
                         "Exception during web service menu building process.",
                         e);
               }
@@ -4416,7 +4622,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       showProducts.setEnabled(showp);
     } catch (Exception e)
     {
-      Cache.log.warn(
+      Console.warn(
               "canShowProducts threw an exception - please report to help@jalview.org",
               e);
       return false;
@@ -4457,8 +4663,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       al = dna.translateCdna(codeTable);
     } catch (Exception ex)
     {
-      jalview.bin.Cache.log.error(
-              "Exception during translation. Please report this !", ex);
+      Console.error("Exception during translation. Please report this !",
+              ex);
       final String msg = MessageManager.getString(
               "label.error_when_translating_sequences_submit_bug_report");
       final String errorTitle = MessageManager
@@ -4609,10 +4815,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               if (protocol == DataSourceType.FILE)
               {
                 File fl;
-                if (file instanceof File) {
+                if (file instanceof File)
+                {
                   fl = (File) file;
                   Platform.cacheFileData(fl);
-                } else {
+                }
+                else
+                {
                   fl = new File(fileName);
                 }
                 pdbfn = fl.getName();
@@ -4693,7 +4902,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                     Desktop.instance);
                     if (pe != null)
                     {
-                      System.err.println("Associated file : "
+                      jalview.bin.Console.errPrintln("Associated file : "
                               + (fm[0].toString()) + " with "
                               + toassoc.getDisplayId(true));
                       assocfiles++;
@@ -4817,7 +5026,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           }
         } catch (Exception x)
         {
-          Cache.log.debug(
+          Console.debug(
                   "Exception when processing data source as T-COFFEE score file",
                   x);
           tcf = null;
@@ -4915,7 +5124,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     if (index > -1)
     {
+      /*
+       * update current Overview window title (if there is one)
+       * to add view name "Original" if necessary
+       */
+      alignPanel.setOverviewTitle(this);
+
+      /*
+       * switch panels and set Overview title (if there is one
+       * because it was opened automatically)
+       */
       alignPanel = alignPanels.get(index);
+      alignPanel.setOverviewTitle(this);
+
       viewport = alignPanel.av;
       avc.setViewportAndAlignmentPanel(viewport, alignPanel);
       setMenusFromViewport(viewport);
@@ -5579,7 +5800,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    *          update non-sequence-related annotations
    */
   @Override
-  protected void setAnnotationsVisibility(boolean visible,
+  public void setAnnotationsVisibility(boolean visible,
           boolean forSequences, boolean forAlignment)
   {
     AlignmentAnnotation[] anns = alignPanel.getAlignment()
@@ -5714,7 +5935,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               viewport.getAlignment()));
     } catch (Exception ex)
     {
-      System.err.println(ex.getMessage());
+      jalview.bin.Console.errPrintln(ex.getMessage());
       return;
     }
   }
@@ -5736,7 +5957,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         console.runScript();
       } catch (Exception ex)
       {
-        System.err.println((ex.toString()));
+        jalview.bin.Console.errPrintln((ex.toString()));
         JvOptionPane.showInternalMessageDialog(Desktop.desktop,
                 MessageManager.getString("label.couldnt_run_groovy_script"),
                 MessageManager.getString("label.groovy_support_failed"),
@@ -5745,7 +5966,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     else
     {
-      System.err.println("Can't run Groovy script as console not found");
+      jalview.bin.Console
+              .errPrintln("Can't run Groovy script as console not found");
     }
   }
 
@@ -5785,6 +6007,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     | ActionEvent.CTRL_MASK)) != 0);
   }
 
+  @Override
+  protected void copyHighlightedColumns_actionPerformed(
+          ActionEvent actionEvent)
+  {
+    avc.copyHighlightedRegionsToClipboard();
+  }
+
   /**
    * Rebuilds the Colour menu, including any user-defined colours which have
    * been loaded either on startup or during the session
@@ -5833,22 +6062,18 @@ 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.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.setResponseHandler(0, () -> {
+      String choice = chooser.getSelectedFile().getPath();
+      Cache.setProperty("LAST_DIRECTORY", choice);
+      SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
+      new VCFLoader(choice).loadVCF(seqs, us);
     });
     chooser.showOpenDialog(null);
 
   }
 
   private Rectangle lastFeatureSettingsBounds = null;
+
   @Override
   public void setFeatureSettingsGeometry(Rectangle bounds)
   {
@@ -5860,6 +6085,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     return lastFeatureSettingsBounds;
   }
+
 }
 
 class PrintThread extends Thread