Merge branch 'feature/JAL-3180colourAnnotationMenu' into merge/JAL-3180
[jalview.git] / src / jalview / gui / AlignFrame.java
index 1bd1541..8dd6d0c 100644 (file)
@@ -24,6 +24,7 @@ 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;
@@ -64,6 +65,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;
@@ -81,6 +83,7 @@ import jalview.io.JnetAnnotationMaker;
 import jalview.io.NewickFile;
 import jalview.io.ScoreMatrixFile;
 import jalview.io.TCoffeeScoreFile;
+import jalview.io.vcf.VCFLoader;
 import jalview.jbgui.GAlignFrame;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.ColourSchemes;
@@ -133,6 +136,7 @@ import java.util.Hashtable;
 import java.util.List;
 import java.util.Vector;
 
+import javax.swing.ButtonGroup;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JEditorPane;
 import javax.swing.JInternalFrame;
@@ -163,8 +167,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
   AlignViewport viewport;
 
-  ViewportRanges vpRanges;
-
   public AlignViewControllerI avc;
 
   List<AlignmentPanel> alignPanels = new ArrayList<>();
@@ -336,7 +338,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       progressBar = new ProgressBar(this.statusPanel, this.statusBar);
     }
 
-    vpRanges = viewport.getRanges();
     avc = new jalview.controller.AlignViewController(this, viewport,
             alignPanel);
     if (viewport.getAlignmentConservationAnnotation() == null)
@@ -654,9 +655,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   { (viewport.cursorMode ? "on" : "off") }));
           if (viewport.cursorMode)
           {
-            alignPanel.getSeqPanel().seqCanvas.cursorX = vpRanges
+            ViewportRanges ranges = viewport.getRanges();
+            alignPanel.getSeqPanel().seqCanvas.cursorX = ranges
                     .getStartRes();
-            alignPanel.getSeqPanel().seqCanvas.cursorY = vpRanges
+            alignPanel.getSeqPanel().seqCanvas.cursorY = ranges
                     .getStartSeq();
           }
           alignPanel.getSeqPanel().seqCanvas.repaint();
@@ -689,10 +691,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           break;
         }
         case KeyEvent.VK_PAGE_UP:
-          vpRanges.pageUp();
+          viewport.getRanges().pageUp();
           break;
         case KeyEvent.VK_PAGE_DOWN:
-          vpRanges.pageDown();
+          viewport.getRanges().pageDown();
           break;
         }
       }
@@ -734,9 +736,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);
     }
@@ -749,7 +751,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);
     }
@@ -772,7 +774,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);
   }
 
@@ -841,6 +843,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentI al = getViewport().getAlignment();
     boolean nucleotide = al.isNucleotide();
 
+    loadVcf.setVisible(nucleotide);
     showTranslation.setVisible(nucleotide);
     showReverse.setVisible(nucleotide);
     showReverseComplement.setVisible(nucleotide);
@@ -872,7 +875,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());
@@ -963,6 +966,11 @@ 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)
   {
@@ -1154,7 +1162,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 shortName.lastIndexOf(java.io.File.separatorChar) + 1);
       }
 
-      success = new Jalview2XML().saveAlignment(this, file, shortName);
+      success = new jalview.project.Jalview2XML().saveAlignment(this, file,
+              shortName);
 
       statusBar.setText(MessageManager.formatMessage(
               "label.successfully_saved_to_file_in_format", new Object[]
@@ -1186,9 +1195,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       }
       else
       {
+        // create backupfiles object and get new temp filename destination
+        BackupFiles backupfiles = new BackupFiles(file);
+
         try
         {
-          PrintWriter out = new PrintWriter(new FileWriter(file));
+          PrintWriter out = new PrintWriter(
+                  new FileWriter(backupfiles.getTempFilePath()));
 
           out.print(output);
           out.close();
@@ -1201,6 +1214,11 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           success = false;
           ex.printStackTrace();
         }
+
+        backupfiles.setWriteSuccess(success);
+        // do the backup file roll and rename the temp file to actual file
+        success = backupfiles.rollBackupsAndRenameTempFile();
+
       }
     }
 
@@ -1392,13 +1410,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void exportFeatures_actionPerformed(ActionEvent e)
   {
-    new AnnotationExporter().exportFeatures(alignPanel);
+    new AnnotationExporter(alignPanel).exportFeatures();
   }
 
   @Override
   public void exportAnnotations_actionPerformed(ActionEvent e)
   {
-    new AnnotationExporter().exportAnnotations(alignPanel);
+    new AnnotationExporter(alignPanel).exportAnnotations();
   }
 
   @Override
@@ -1711,7 +1729,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     viewport.getAlignment().moveSelectedSequencesByOne(sg,
             viewport.getHiddenRepSequences(), up);
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   synchronized void slideSequences(boolean right, int size)
@@ -1828,7 +1846,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   protected void copy_actionPerformed(ActionEvent e)
   {
-    System.gc();
     if (viewport.getSelectionGroup() == null)
     {
       return;
@@ -1864,23 +1881,17 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       return;
     }
 
-    ArrayList<int[]> hiddenColumns = null;
+    HiddenColumns hiddenColumns = null;
     if (viewport.hasHiddenColumns())
     {
-      hiddenColumns = new ArrayList<>();
       int hiddenOffset = viewport.getSelectionGroup().getStartRes();
       int hiddenCutoff = viewport.getSelectionGroup().getEndRes();
-      ArrayList<int[]> hiddenRegions = viewport.getAlignment()
-              .getHiddenColumns().getHiddenColumnsCopy();
-      for (int[] region : hiddenRegions)
-      {
-        if (region[0] >= hiddenOffset && region[1] <= hiddenCutoff)
-        {
-          hiddenColumns
-                  .add(new int[]
-                  { region[0] - hiddenOffset, region[1] - hiddenOffset });
-        }
-      }
+
+      // create new HiddenColumns object with copy of hidden regions
+      // between startRes and endRes, offset by startRes
+      hiddenColumns = new HiddenColumns(
+              viewport.getAlignment().getHiddenColumns(), hiddenOffset,
+              hiddenCutoff, hiddenOffset);
     }
 
     Desktop.jalviewClipboard = new Object[] { seqs,
@@ -2147,7 +2158,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
 
         // propagate alignment changed.
-        vpRanges.setEndSeq(alignment.getHeight());
+        viewport.getRanges().setEndSeq(alignment.getHeight());
         if (annotationAdded)
         {
           // Duplicate sequence annotation in all views.
@@ -2209,11 +2220,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         if (Desktop.jalviewClipboard != null
                 && Desktop.jalviewClipboard[2] != null)
         {
-          List<int[]> hc = (List<int[]>) Desktop.jalviewClipboard[2];
-          for (int[] region : hc)
-          {
-            af.viewport.hideColumns(region[0], region[1]);
-          }
+          HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+          af.viewport.setHiddenColumns(hc);
         }
 
         // >>>This is a fix for the moment, until a better solution is
@@ -2268,11 +2276,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       if (Desktop.jalviewClipboard != null
               && Desktop.jalviewClipboard[2] != null)
       {
-        List<int[]> hc = (List<int[]>) Desktop.jalviewClipboard[2];
-        for (int region[] : hc)
-        {
-          af.viewport.hideColumns(region[0], region[1]);
-        }
+        HiddenColumns hc = (HiddenColumns) Desktop.jalviewClipboard[2];
+        af.viewport.setHiddenColumns(hc);
       }
 
       // >>>This is a fix for the moment, until a better solution is
@@ -2397,7 +2402,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -2410,20 +2415,17 @@ 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
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
   }
 
@@ -2448,7 +2450,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
     // updating.
-    alignPanel.paintAlignment(false);
+    alignPanel.paintAlignment(false, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2479,7 +2481,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // alignPanel to decide if overview needs
     // updating.
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     PaintRefresher.Refresh(alignPanel, viewport.getSequenceSetId());
     viewport.sendSelection();
   }
@@ -2488,7 +2490,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void invertColSel_actionPerformed(ActionEvent e)
   {
     viewport.invertColumnSelection();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     viewport.sendSelection();
   }
 
@@ -2548,7 +2550,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       {
         trimRegion = new TrimRegionCommand("Remove Left", true, seqs,
                 column, viewport.getAlignment());
-        vpRanges.setStartRes(0);
+        viewport.getRanges().setStartRes(0);
       }
       else
       {
@@ -2613,13 +2615,14 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(vpRanges.getStartRes());
+    ViewportRanges ranges = viewport.getRanges();
+    int startRes = seq.findPosition(ranges.getStartRes());
     // ShiftList shifts;
     // viewport.getAlignment().removeGaps(shifts=new ShiftList());
     // edit.alColumnChanges=shifts.getInverse();
     // if (viewport.hasHiddenColumns)
     // viewport.getColumnSelection().compensateForEdits(shifts);
-    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
+    ranges.setStartRes(seq.findIndex(startRes) - 1);
     viewport.firePropertyChange("alignment", null,
             viewport.getAlignment().getSequences());
 
@@ -2652,12 +2655,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // This is to maintain viewport position on first residue
     // of first sequence
     SequenceI seq = viewport.getAlignment().getSequenceAt(0);
-    int startRes = seq.findPosition(vpRanges.getStartRes());
+    int startRes = seq.findPosition(viewport.getRanges().getStartRes());
 
     addHistoryItem(new RemoveGapsCommand("Remove Gaps", seqs, start, end,
             viewport.getAlignment()));
 
-    vpRanges.setStartRes(seq.findIndex(startRes) - 1);
+    viewport.getRanges().setStartRes(seq.findIndex(startRes) - 1);
 
     viewport.firePropertyChange("alignment", null,
             viewport.getAlignment().getSequences());
@@ -2713,8 +2716,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     /*
      * Create a new AlignmentPanel (with its own, new Viewport)
      */
-    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel,
-            true);
+    AlignmentPanel newap = new jalview.project.Jalview2XML()
+            .copyAlignPanel(alignPanel);
     if (!copyAnnotation)
     {
       /*
@@ -2726,10 +2729,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"));
     }
 
     /*
@@ -2739,6 +2742,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
@@ -2753,7 +2762,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();
@@ -2816,9 +2825,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());
         }
       }
     }
@@ -2868,21 +2877,21 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     alignPanel.getIdPanel().getIdCanvas()
             .setPreferredSize(alignPanel.calculateIdWidth());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   @Override
   public void idRightAlign_actionPerformed(ActionEvent e)
   {
     viewport.setRightAlignIds(idRightAlign.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   @Override
   public void centreColumnLabels_actionPerformed(ActionEvent e)
   {
     viewport.setCentreColumnLabels(centreColumnLabelsMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -2901,7 +2910,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
+      alignPanel.scrollToPosition(viewport.getSearchResults());
     }
   }
 
@@ -2915,7 +2924,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void colourTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setColourText(colourTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -2944,7 +2953,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showAllColumns_actionPerformed(ActionEvent e)
   {
     viewport.showAllHiddenColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3048,7 +3057,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.updateLayout();
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3064,7 +3074,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     viewport.showAllHiddenColumns();
     viewport.showAllHiddenSeqs();
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3072,7 +3082,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
-    alignPanel.paintAlignment(true);
+    alignPanel.updateLayout();
+    alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
 
@@ -3093,7 +3104,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleAbove_actionPerformed(ActionEvent e)
   {
     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
-    alignPanel.paintAlignment(true);
+    // TODO: do we actually need to update overview for scale above change ?
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3106,7 +3118,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleLeft_actionPerformed(ActionEvent e)
   {
     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3119,7 +3131,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
     viewport.setScaleRightWrapped(scaleRight.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3132,7 +3144,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewBoxesMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowBoxes(viewBoxesMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3145,7 +3157,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void viewTextMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowText(viewTextMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -3158,7 +3170,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void renderGapsMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setRenderGaps(renderGapsMenuItem.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   public FeatureSettings featureSettings;
@@ -3196,7 +3208,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void showSeqFeatures_actionPerformed(ActionEvent evt)
   {
     viewport.setShowSequenceFeatures(showSeqFeatures.isSelected());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3272,6 +3284,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 alignPanel.setOverviewPanel(null);
               };
             });
+    if (getKeyListeners().length > 0)
+    {
+      frame.addKeyListener(getKeyListeners()[0]);
+    }
 
     alignPanel.setOverviewPanel(overview);
   }
@@ -3353,7 +3369,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
     viewport.setGlobalColourScheme(cs);
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, true);
   }
 
   /**
@@ -3438,7 +3454,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             viewport.getAlignment().getSequenceAt(0));
     addHistoryItem(new OrderCommand("Pairwise Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3454,7 +3470,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByID(viewport.getAlignment());
     addHistoryItem(
             new OrderCommand("ID Sort", oldOrder, viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3470,7 +3486,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     AlignmentSorter.sortByLength(viewport.getAlignment());
     addHistoryItem(new OrderCommand("Length Sort", oldOrder,
             viewport.getAlignment()));
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3487,7 +3503,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     addHistoryItem(new OrderCommand("Group Sort", oldOrder,
             viewport.getAlignment()));
 
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
   }
 
   /**
@@ -3605,9 +3621,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;
@@ -3644,7 +3660,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         addHistoryItem(new OrderCommand(order.getName(), oldOrder,
                 viewport.getAlignment()));
 
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3673,7 +3689,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 viewport.getAlignment());// ,viewport.getSelectionGroup());
         addHistoryItem(new OrderCommand("Sort by " + scoreLabel, oldOrder,
                 viewport.getAlignment()));
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, false);
       }
     });
   }
@@ -3788,7 +3804,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       addHistoryItem(new OrderCommand(undoname, oldOrder,
               viewport.getAlignment()));
     }
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(true, false);
     return true;
   }
 
@@ -4259,7 +4275,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showProductsFor(final SequenceI[] sel, final boolean _odna,
           final String source)
   {
-    new Thread(CrossRefAction.showProductsFor(sel, _odna, source, this))
+    new Thread(CrossRefAction.getHandlerFor(sel, _odna, source, this))
             .start();
   }
 
@@ -4268,14 +4284,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(
@@ -4304,7 +4320,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))
       {
@@ -4386,7 +4402,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     // Java's Transferable for native dnd
     evt.acceptDrop(DnDConstants.ACTION_COPY_OR_MOVE);
     Transferable t = evt.getTransferable();
-    List<String> files = new ArrayList<>();
+    final AlignFrame thisaf = this;
+    final List<String> files = new ArrayList<>();
     List<DataSourceType> protocols = new ArrayList<>();
 
     try
@@ -4398,133 +4415,160 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
     if (files != null)
     {
-      try
+      new Thread(new Runnable()
       {
-        // check to see if any of these files have names matching sequences in
-        // the alignment
-        SequenceIdMatcher idm = new SequenceIdMatcher(
-                viewport.getAlignment().getSequencesArray());
-        /**
-         * Object[] { String,SequenceI}
-         */
-        ArrayList<Object[]> filesmatched = new ArrayList<>();
-        ArrayList<String> filesnotmatched = new ArrayList<>();
-        for (int i = 0; i < files.size(); i++)
+        @Override
+        public void run()
         {
-          String file = files.get(i).toString();
-          String pdbfn = "";
-          DataSourceType protocol = FormatAdapter.checkProtocol(file);
-          if (protocol == DataSourceType.FILE)
-          {
-            File fl = new File(file);
-            pdbfn = fl.getName();
-          }
-          else if (protocol == DataSourceType.URL)
-          {
-            URL url = new URL(file);
-            pdbfn = url.getFile();
-          }
-          if (pdbfn.length() > 0)
+          try
           {
-            // attempt to find a match in the alignment
-            SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
-            int l = 0, c = pdbfn.indexOf(".");
-            while (mtch == null && c != -1)
+            // check to see if any of these files have names matching sequences
+            // in
+            // the alignment
+            SequenceIdMatcher idm = new SequenceIdMatcher(
+                    viewport.getAlignment().getSequencesArray());
+            /**
+             * Object[] { String,SequenceI}
+             */
+            ArrayList<Object[]> filesmatched = new ArrayList<>();
+            ArrayList<String> filesnotmatched = new ArrayList<>();
+            for (int i = 0; i < files.size(); i++)
             {
-              do
+              String file = files.get(i).toString();
+              String pdbfn = "";
+              DataSourceType protocol = FormatAdapter.checkProtocol(file);
+              if (protocol == DataSourceType.FILE)
+              {
+                File fl = new File(file);
+                pdbfn = fl.getName();
+              }
+              else if (protocol == DataSourceType.URL)
               {
-                l = c;
-              } while ((c = pdbfn.indexOf(".", l)) > l);
-              if (l > -1)
+                URL url = new URL(file);
+                pdbfn = url.getFile();
+              }
+              if (pdbfn.length() > 0)
               {
-                pdbfn = pdbfn.substring(0, l);
+                // attempt to find a match in the alignment
+                SequenceI[] mtch = idm.findAllIdMatches(pdbfn);
+                int l = 0, c = pdbfn.indexOf(".");
+                while (mtch == null && c != -1)
+                {
+                  do
+                  {
+                    l = c;
+                  } while ((c = pdbfn.indexOf(".", l)) > l);
+                  if (l > -1)
+                  {
+                    pdbfn = pdbfn.substring(0, l);
+                  }
+                  mtch = idm.findAllIdMatches(pdbfn);
+                }
+                if (mtch != null)
+                {
+                  FileFormatI type = null;
+                  try
+                  {
+                    type = new IdentifyFile().identify(file, protocol);
+                  } catch (Exception ex)
+                  {
+                    type = null;
+                  }
+                  if (type != null && type.isStructureFile())
+                  {
+                    filesmatched.add(new Object[] { file, protocol, mtch });
+                    continue;
+                  }
+                }
+                // File wasn't named like one of the sequences or wasn't a PDB
+                // file.
+                filesnotmatched.add(file);
               }
-              mtch = idm.findAllIdMatches(pdbfn);
             }
-            if (mtch != null)
+            int assocfiles = 0;
+            if (filesmatched.size() > 0)
             {
-              FileFormatI type = null;
-              try
+              boolean autoAssociate = Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+              if (!autoAssociate)
               {
-                type = new IdentifyFile().identify(file, protocol);
-              } catch (Exception ex)
+                String msg = MessageManager.formatMessage(
+                        "label.automatically_associate_structure_files_with_sequences_same_name",
+                        new Object[]
+                        { Integer.valueOf(filesmatched.size())
+                                .toString() });
+                String ttl = MessageManager.getString(
+                        "label.automatically_associate_structure_files_by_name");
+                int choice = JvOptionPane.showConfirmDialog(thisaf, msg,
+                        ttl, JvOptionPane.YES_NO_OPTION);
+                autoAssociate = choice == JvOptionPane.YES_OPTION;
+              }
+              if (autoAssociate)
               {
-                type = null;
+                for (Object[] fm : filesmatched)
+                {
+                  // try and associate
+                  // TODO: may want to set a standard ID naming formalism for
+                  // associating PDB files which have no IDs.
+                  for (SequenceI toassoc : (SequenceI[]) fm[2])
+                  {
+                    PDBEntry pe = new AssociatePdbFileWithSeq()
+                            .associatePdbWithSeq((String) fm[0],
+                                    (DataSourceType) fm[1], toassoc, false,
+                                    Desktop.instance);
+                    if (pe != null)
+                    {
+                      System.err.println("Associated file : "
+                              + ((String) fm[0]) + " with "
+                              + toassoc.getDisplayId(true));
+                      assocfiles++;
+                    }
+                  }
+                  // TODO: do we need to update overview ? only if features are
+                  // shown I guess
+                  alignPanel.paintAlignment(true, false);
+                }
               }
-              if (type != null && type.isStructureFile())
+              else
               {
-                filesmatched.add(new Object[] { file, protocol, mtch });
-                continue;
+                /*
+                 * add declined structures as sequences
+                 */
+                for (Object[] o : filesmatched)
+                {
+                  filesnotmatched.add((String) o[0]);
+                }
               }
             }
-            // File wasn't named like one of the sequences or wasn't a PDB file.
-            filesnotmatched.add(file);
-          }
-        }
-        int assocfiles = 0;
-        if (filesmatched.size() > 0)
-        {
-          if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
-                  || JvOptionPane.showConfirmDialog(this,
-                          MessageManager.formatMessage(
-                                  "label.automatically_associate_structure_files_with_sequences_same_name",
-                                  new Object[]
-                                  { Integer.valueOf(filesmatched.size())
-                                          .toString() }),
-                          MessageManager.getString(
-                                  "label.automatically_associate_structure_files_by_name"),
-                          JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION)
-
-          {
-            for (Object[] fm : filesmatched)
+            if (filesnotmatched.size() > 0)
             {
-              // try and associate
-              // TODO: may want to set a standard ID naming formalism for
-              // associating PDB files which have no IDs.
-              for (SequenceI toassoc : (SequenceI[]) fm[2])
+              if (assocfiles > 0 && (Cache.getDefault(
+                      "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
+                      || JvOptionPane.showConfirmDialog(thisaf,
+                              "<html>" + MessageManager.formatMessage(
+                                      "label.ignore_unmatched_dropped_files_info",
+                                      new Object[]
+                                      { Integer.valueOf(
+                                              filesnotmatched.size())
+                                              .toString() })
+                                      + "</html>",
+                              MessageManager.getString(
+                                      "label.ignore_unmatched_dropped_files"),
+                              JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
               {
-                PDBEntry pe = new AssociatePdbFileWithSeq()
-                        .associatePdbWithSeq((String) fm[0],
-                                (DataSourceType) fm[1], toassoc, false,
-                                Desktop.instance);
-                if (pe != null)
-                {
-                  System.err.println("Associated file : " + ((String) fm[0])
-                          + " with " + toassoc.getDisplayId(true));
-                  assocfiles++;
-                }
+                return;
               }
-              alignPanel.paintAlignment(true);
+              for (String fn : filesnotmatched)
+              {
+                loadJalviewDataFile(fn, null, null, null);
+              }
+
             }
-          }
-        }
-        if (filesnotmatched.size() > 0)
-        {
-          if (assocfiles > 0 && (Cache.getDefault(
-                  "AUTOASSOCIATE_PDBANDSEQS_IGNOREOTHERS", false)
-                  || JvOptionPane.showConfirmDialog(this,
-                          "<html>" + MessageManager.formatMessage(
-                                  "label.ignore_unmatched_dropped_files_info",
-                                  new Object[]
-                                  { Integer.valueOf(filesnotmatched.size())
-                                          .toString() })
-                                  + "</html>",
-                          MessageManager.getString(
-                                  "label.ignore_unmatched_dropped_files"),
-                          JvOptionPane.YES_NO_OPTION) == JvOptionPane.YES_OPTION))
-          {
-            return;
-          }
-          for (String fn : filesnotmatched)
+          } catch (Exception ex)
           {
-            loadJalviewDataFile(fn, null, null, null);
+            ex.printStackTrace();
           }
-
         }
-      } catch (Exception ex)
-      {
-        ex.printStackTrace();
-      }
+      }).start();
     }
   }
 
@@ -4626,11 +4670,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             new JnetAnnotationMaker();
             JnetAnnotationMaker.add_annotation(predictions,
                     viewport.getAlignment(), 0, false);
-            SequenceI repseq = viewport.getAlignment().getSequenceAt(0);
-            viewport.getAlignment().setSeqrep(repseq);
-            HiddenColumns cs = new HiddenColumns();
-            cs.hideInsertionsFor(repseq);
-            viewport.getAlignment().setHiddenColumns(cs);
+            viewport.getAlignment().setupJPredAlignment();
             isAnnotation = true;
           }
           // else if (IdentifyFile.FeaturesFile.equals(format))
@@ -4638,7 +4678,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
           {
             if (parseFeaturesFile(file, sourceType))
             {
-              alignPanel.paintAlignment(true);
+              alignPanel.paintAlignment(true, true);
             }
           }
           else
@@ -4653,7 +4693,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
         alignPanel.adjustAnnotationHeight();
         viewport.updateSequenceIdColours();
         buildSortByAnnotationScoresMenu();
-        alignPanel.paintAlignment(true);
+        alignPanel.paintAlignment(true, true);
       }
     } catch (Exception ex)
     {
@@ -4751,7 +4791,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
 
       if (reply != null)
       {
-        viewport.viewName = reply;
+        viewport.setViewName(reply);
         // TODO warn if reply is in getExistingViewNames()?
         tabbedPane.setTitleAt(tabbedPane.getSelectedIndex(), reply);
       }
@@ -4852,14 +4892,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             MessageManager.getString("option.trim_retrieved_seqs"));
     trimrs.setToolTipText(
             MessageManager.getString("label.trim_retrieved_sequences"));
-    trimrs.setSelected(Cache.getDefault("TRIM_FETCHED_DATASET_SEQS", true));
+    trimrs.setSelected(
+            Cache.getDefault(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES, true));
     trimrs.addActionListener(new ActionListener()
     {
       @Override
       public void actionPerformed(ActionEvent e)
       {
         trimrs.setSelected(trimrs.isSelected());
-        Cache.setProperty("TRIM_FETCHED_DATASET_SEQS",
+        Cache.setProperty(DBRefFetcher.TRIM_RETRIEVED_SEQUENCES,
                 Boolean.valueOf(trimrs.isSelected()).toString());
       };
     });
@@ -5178,7 +5219,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void showUnconservedMenuItem_actionPerformed(ActionEvent e)
   {
     viewport.setShowUnconserved(showNonconservedMenuItem.getState());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /*
@@ -5267,7 +5308,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5279,7 +5320,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       viewport.getAlignment().setSeqrep(null);
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true);
+      alignPanel.paintAlignment(true, true);
     }
   }
 
@@ -5288,6 +5329,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     if (avc.createGroup())
     {
+      if (applyAutoAnnotationSettings.isSelected())
+      {
+        alignPanel.updateAnnotation(true, false);
+      }
       alignPanel.alignmentChanged();
     }
   }
@@ -5369,7 +5414,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     this.alignPanel.av.setSortAnnotationsBy(getAnnotationSortOrder());
     this.alignPanel.av
             .setShowAutocalculatedAbove(isShowAutoCalculatedAbove());
-    alignPanel.paintAlignment(true);
+    alignPanel.paintAlignment(false, false);
   }
 
   /**
@@ -5378,7 +5423,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;
   }
 
   /**
@@ -5547,15 +5594,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);
@@ -5572,6 +5620,27 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
       new CalculationChooser(AlignFrame.this);
     }
   }
+
+  @Override
+  protected void loadVcf_actionPerformed()
+  {
+    JalviewFileChooser chooser = new JalviewFileChooser(
+            Cache.getProperty("LAST_DIRECTORY"));
+    chooser.setFileView(new JalviewFileView());
+    chooser.setDialogTitle(MessageManager.getString("label.load_vcf_file"));
+    chooser.setToolTipText(MessageManager.getString("label.load_vcf_file"));
+
+    int value = chooser.showOpenDialog(null);
+
+    if (value == JalviewFileChooser.APPROVE_OPTION)
+    {
+      String choice = chooser.getSelectedFile().getPath();
+      Cache.setProperty("LAST_DIRECTORY", choice);
+      SequenceI[] seqs = viewport.getAlignment().getSequencesArray();
+      new VCFLoader(choice).loadVCF(seqs, this);
+    }
+
+  }
 }
 
 class PrintThread extends Thread