JAL-3066 Implement clustaloWS using slivka system.
[jalview.git] / src / jalview / gui / AlignFrame.java
index 27d4f5e..5a5df3b 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;
@@ -32,6 +33,7 @@ import jalview.api.AlignViewControllerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeatureSettingsControllerI;
+import jalview.api.FeatureSettingsModelI;
 import jalview.api.SplitContainerI;
 import jalview.api.ViewStyleI;
 import jalview.api.analysis.SimilarityParamsI;
@@ -54,7 +56,6 @@ import jalview.datamodel.AlignmentOrder;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
-import jalview.datamodel.HiddenMarkovModel;
 import jalview.datamodel.HiddenSequences;
 import jalview.datamodel.PDBEntry;
 import jalview.datamodel.SeqCigar;
@@ -69,8 +70,10 @@ import jalview.hmmer.HMMERParamStore;
 import jalview.hmmer.HMMERPreset;
 import jalview.hmmer.HMMSearch;
 import jalview.hmmer.HmmerCommand;
+import jalview.hmmer.JackHMMER;
 import jalview.io.AlignmentProperties;
 import jalview.io.AnnotationFile;
+import jalview.io.BackupFiles;
 import jalview.io.BioJsHTMLOutput;
 import jalview.io.DataSourceType;
 import jalview.io.FileFormat;
@@ -95,7 +98,6 @@ import jalview.schemes.ColourSchemes;
 import jalview.schemes.ResidueColourScheme;
 import jalview.schemes.TCoffeeColourScheme;
 import jalview.util.MessageManager;
-import jalview.util.StringUtils;
 import jalview.viewmodel.AlignmentViewport;
 import jalview.viewmodel.ViewportRanges;
 import jalview.ws.DBRefFetcher;
@@ -107,6 +109,7 @@ import jalview.ws.params.ArgumentI;
 import jalview.ws.params.ParamDatastoreI;
 import jalview.ws.params.WsParamSetI;
 import jalview.ws.seqfetcher.DbSourceProxy;
+import jalview.ws.slivkaws.SlivkaWSDiscoverer;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
@@ -141,18 +144,15 @@ import java.net.URL;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Deque;
-import java.util.Enumeration;
-import java.util.HashMap;
-import java.util.Hashtable;
+import java.util.HashSet;
 import java.util.List;
-import java.util.Map;
-import java.util.Scanner;
+import java.util.Set;
 import java.util.Vector;
 
+import javax.swing.ButtonGroup;
 import javax.swing.JCheckBoxMenuItem;
 import javax.swing.JEditorPane;
 import javax.swing.JFileChooser;
-import javax.swing.JFrame;
 import javax.swing.JInternalFrame;
 import javax.swing.JLayeredPane;
 import javax.swing.JMenu;
@@ -170,9 +170,6 @@ import javax.swing.SwingUtilities;
 public class AlignFrame extends GAlignFrame implements DropTargetListener,
         IProgressIndicator, AlignViewControllerGuiI, ColourChangeListener
 {
-
-  Map<String, Float> distribution = new HashMap<>(); // temporary
-
   public static final int DEFAULT_WIDTH = 700;
 
   public static final int DEFAULT_HEIGHT = 500;
@@ -185,10 +182,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   AlignViewport viewport;
 
   public AlignViewControllerI avc;
-  /*
-   * The selected HMM for this align frame
-   */
-  SequenceI selectedHMMSequence;
 
   List<AlignmentPanel> alignPanels = new ArrayList<>();
 
@@ -758,9 +751,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);
     }
@@ -773,7 +766,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);
     }
@@ -797,7 +790,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);
   }
 
@@ -898,7 +891,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());
@@ -992,10 +985,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     return progressBar.operationInProgress();
   }
 
+  /**
+   * Sets the text of the status bar. Note that setting a null or empty value
+   * will cause the status bar to be hidden, with possibly undesirable flicker
+   * of the screen layout.
+   */
   @Override
   public void setStatus(String text)
   {
-    statusBar.setText(text);
+    statusBar.setText(text == null || text.isEmpty() ? " " : text);
   }
 
   /*
@@ -1024,111 +1022,175 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   }
 
   @Override
-  public void hmmBuildSettings_actionPerformed()
+  public void hmmBuild_actionPerformed(boolean withDefaults)
   {
-    if (!(alignmentIsSufficient(1)))
+    if (!alignmentIsSufficient(1))
     {
       return;
     }
-    WsParamSetI set = new HMMERPreset();
-    List<ArgumentI> args = new ArrayList<>();
-    ParamDatastoreI store = new HMMERParamStore("hmmbuild");
-    WsJobParameters params = new WsJobParameters(new JFrame(), store, set,
-            args);
-    if (params.showRunDialog())
+
+    /*
+     * get default parameters, and optionally show a dialog
+     * to allow them to be modified
+     */
+    ParamDatastoreI store = HMMERParamStore.forBuild(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
     {
-      new Thread(new HMMBuild(this, params.getJobParams())).start();
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
     }
-    alignPanel.repaint();
-
+    new Thread(new HMMBuild(this, args)).start();
   }
 
   @Override
-  public void hmmAlignSettings_actionPerformed()
+  public void hmmAlign_actionPerformed(boolean withDefaults)
   {
     if (!(checkForHMM() && alignmentIsSufficient(2)))
     {
       return;
     }
-    WsParamSetI set = new HMMERPreset();
-    List<ArgumentI> args = new ArrayList<>();
-    ParamDatastoreI store = new HMMERParamStore("hmmalign");
-    WsJobParameters params = new WsJobParameters(new JFrame(), store, set,
-            args);
-    if (params.showRunDialog())
+
+    /*
+     * get default parameters, and optionally show a dialog
+     * to allow them to be modified
+     */
+    ParamDatastoreI store = HMMERParamStore.forAlign(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
     {
-      new Thread(new HMMAlign(this, params.getJobParams()))
-            .start();
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
     }
-    alignPanel.repaint();
+    new Thread(new HMMAlign(this, args)).start();
   }
 
   @Override
-  public void hmmSearchSettings_actionPerformed()
+  public void hmmSearch_actionPerformed(boolean withDefaults)
   {
     if (!checkForHMM())
     {
       return;
     }
-    WsParamSetI set = new HMMERPreset();
-    List<ArgumentI> args = new ArrayList<>();
-    ParamDatastoreI store = new HMMERParamStore("hmmsearch");
-    WsJobParameters params = new WsJobParameters(new JFrame(), store, set,
-            args);
-    if (params.showRunDialog())
-    {
-      new Thread(new HMMSearch(this, params.getJobParams()))
-            .start();
-    }
-    alignPanel.repaint();
-  }
 
-  @Override
-  public void hmmBuildRun_actionPerformed()
-  {
-    if (!alignmentIsSufficient(1))
-    {
-      return;
-    }
-    new Thread(new HMMBuild(this, null))
-            .start();
-  }
+    /*
+     * get default parameters, and (if requested) show 
+     * dialog to allow modification
+     */
+    ParamDatastoreI store = HMMERParamStore.forSearch(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
 
-  @Override
-  public void hmmAlignRun_actionPerformed()
-  {
-    if (!(checkForHMM() && alignmentIsSufficient(2)))
+    if (!withDefaults)
     {
-      return;
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
     }
-    new Thread(new HMMAlign(this, null)).start();
+    new Thread(new HMMSearch(this, args)).start();
+    alignPanel.repaint();
   }
-
+  
   @Override
-  public void hmmSearchRun_actionPerformed()
+  public void jackhmmer_actionPerformed(boolean withDefaults)
   {
-    if (!checkForHMM())
+    
+    /*
+     * get default parameters, and (if requested) show 
+     * dialog to allow modification
+     */
+    
+    ParamDatastoreI store = HMMERParamStore.forJackhmmer(viewport);
+    List<ArgumentI> args = store.getServiceParameters();
+
+    if (!withDefaults)
     {
-      return;
+      WsParamSetI set = new HMMERPreset();
+      WsJobParameters params = new WsJobParameters(store, set, args);
+      if (params.showRunDialog())
+      {
+        args = params.getJobParams();
+      }
+      else
+      {
+        return; // user cancelled
+      }
     }
-    new Thread(new HMMSearch(this, null)).start();
+    new Thread(new JackHMMER(this, args)).start();
+    alignPanel.repaint();
+    
   }
 
   /**
-   * Checks if the frame has a selected hidden Markov model
+   * Checks if the alignment has at least one hidden Markov model, if not shows
+   * a dialog advising to run hmmbuild or load an HMM profile
    * 
    * @return
    */
   private boolean checkForHMM()
   {
-    if (getSelectedHMM() == null)
+    if (viewport.getAlignment().getHmmSequences().isEmpty())
     {
       JOptionPane.showMessageDialog(this,
-              MessageManager.getString("warn.no_selected_hmm"));
+              MessageManager.getString("warn.no_hmm"));
       return false;
     }
     return true;
   }
+  
+  @Override
+  protected void filterByEValue_actionPerformed()
+  {
+    viewport.filterByEvalue(inputDouble("Enter E-Value Cutoff"));
+  }
+  
+  @Override
+  protected void filterByScore_actionPerformed()
+  {
+    viewport.filterByScore(inputDouble("Enter Bit Score Threshold"));
+  }
+  
+  private double inputDouble(String message)
+  {
+    String str = null;
+    Double d = null;
+    while(d == null || d <= 0)
+    {
+      str = JOptionPane.showInputDialog(this.alignPanel, message);
+      try
+      {
+        d = Double.valueOf(str);
+      }
+      catch (NumberFormatException e)
+      {
+      }
+    }
+    return d;
+  }
 
   /**
    * Checks if the alignment contains the required number of sequences.
@@ -1138,45 +1200,39 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
    */
   public boolean alignmentIsSufficient(int required)
   {
-    if (getViewport().getAlignment().getSequences().size() < required)
-    {
-      JOptionPane.showMessageDialog(this,
-              MessageManager.getString("warn.not_enough_sequences"));
-      return false;
-    }
-    return true;
+      if (getViewport().getSequenceSelection().length < required)
+      {
+        JOptionPane.showMessageDialog(this,
+                MessageManager.getString("label.not_enough_sequences"));
+        return false;
+      }
+      return true;
   }
 
+  /**
+   * Opens a file browser and adds the selected file, if in Fasta, Stockholm or
+   * Pfam format, to the list held under preference key "HMMSEARCH_DBS" (as a
+   * comma-separated list)
+   */
   @Override
   public void addDatabase_actionPerformed() throws IOException
   {
-    if (Cache.getProperty(Preferences.HMMSEARCH_DB_PATHS) == null)
+    if (Cache.getProperty(Preferences.HMMSEARCH_DBS) == null)
     {
       Cache.setProperty(Preferences.HMMSEARCH_DBS, "");
-      Cache.setProperty(Preferences.HMMSEARCH_DB_PATHS, "");
     }
 
     String path = openFileChooser(false);
-    if (new File(path).exists())
+    if (path != null && new File(path).exists())
     {
       IdentifyFile identifier = new IdentifyFile();
       FileFormatI format = identifier.identify(path, DataSourceType.FILE);
       if (format == FileFormat.Fasta || format == FileFormat.Stockholm
               || format == FileFormat.Pfam)
       {
-        String currentDbs = Cache.getProperty(Preferences.HMMSEARCH_DBS);
         String currentDbPaths = Cache
-                .getProperty(Preferences.HMMSEARCH_DB_PATHS);
-        currentDbPaths += " " + path;
-
-        String fileName = StringUtils.getLastToken(path, File.separator);
-        Scanner scanner = new Scanner(fileName).useDelimiter(".");
-        String name = scanner.next();
-        scanner.close();
-        currentDbs += " " + path; // TODO remove path from file name
-        scanner.close();
-
-        Cache.setProperty(Preferences.HMMSEARCH_DB_PATHS, currentDbPaths);
+                .getProperty(Preferences.HMMSEARCH_DBS);
+        currentDbPaths += Preferences.COMMA + path;
         Cache.setProperty(Preferences.HMMSEARCH_DBS, currentDbPaths);
       }
       else
@@ -1185,21 +1241,19 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 MessageManager.getString("warn.invalid_format"));
       }
     }
-    else
-    {
-      JOptionPane.showMessageDialog(this,
-              MessageManager.getString("warn.not_enough_sequences"));
-    }
   }
 
   /**
-   * Opens a file chooser
+   * Opens a file chooser, optionally restricted to selecting folders
+   * (directories) only. Answers the path to the selected file or folder, or
+   * null if none is chosen.
    * 
-   * @param forFolder
+   * @param
    * @return
    */
   protected String openFileChooser(boolean forFolder)
   {
+    // TODO duplicates GPreferences method - relocate to JalviewFileChooser?
     String choice = null;
     JFileChooser chooser = new JFileChooser();
     if (forFolder)
@@ -1379,7 +1433,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[]
@@ -1411,9 +1466,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();
@@ -1426,6 +1485,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();
+
       }
     }
 
@@ -2308,7 +2372,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     newGraphGroups.add(q, null);
                   }
                   newGraphGroups.set(newann.graphGroup,
-                          new Integer(++fgroup));
+                          Integer.valueOf(++fgroup));
                 }
                 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                         .intValue();
@@ -2355,7 +2419,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                     newGraphGroups.add(q, null);
                   }
                   newGraphGroups.set(newann.graphGroup,
-                          new Integer(++fgroup));
+                          Integer.valueOf(++fgroup));
                 }
                 newann.graphGroup = newGraphGroups.get(newann.graphGroup)
                         .intValue();
@@ -2630,15 +2694,12 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   @Override
   public void selectAllSequenceMenuItem_actionPerformed(ActionEvent e)
   {
-    SequenceGroup sg = new SequenceGroup();
-
-    for (int i = 0; i < viewport.getAlignment().getSequences().size(); i++)
-    {
-      sg.addSequence(viewport.getAlignment().getSequenceAt(i), false);
-    }
+    SequenceGroup sg = new SequenceGroup(
+            viewport.getAlignment().getSequences());
 
     sg.setEndRes(viewport.getAlignment().getWidth() - 1);
     viewport.setSelectionGroup(sg);
+    viewport.isSelectionGroupChanged(true);
     viewport.sendSelection();
     // JAL-2034 - should delegate to
     // alignPanel to decide if overview needs
@@ -2934,7 +2995,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     /*
      * Create a new AlignmentPanel (with its own, new Viewport)
      */
-    AlignmentPanel newap = new Jalview2XML().copyAlignPanel(alignPanel);
+    AlignmentPanel newap = new jalview.project.Jalview2XML()
+            .copyAlignPanel(alignPanel);
     if (!copyAnnotation)
     {
       /*
@@ -2946,10 +3008,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"));
     }
 
     /*
@@ -2959,6 +3021,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
@@ -2973,7 +3041,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();
@@ -3036,9 +3104,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());
         }
       }
     }
@@ -3121,7 +3189,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.setFollowHighlight(state);
     if (state)
     {
-      alignPanel.scrollToPosition(viewport.getSearchResults(), false);
+      alignPanel.scrollToPosition(viewport.getSearchResults());
     }
   }
 
@@ -3268,6 +3336,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     viewport.expandColSelection(sg, false);
     viewport.hideAllSelectedSeqs();
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -3292,6 +3361,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   public void hideSelColumns_actionPerformed(ActionEvent e)
   {
     viewport.hideSelectedColumns();
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, true);
     viewport.sendSelection();
   }
@@ -3313,7 +3383,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleAbove_actionPerformed(ActionEvent e)
   {
     viewport.setScaleAboveWrapped(scaleAbove.isSelected());
-    // TODO: do we actually need to update overview for scale above change ?
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3327,6 +3397,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleLeft_actionPerformed(ActionEvent e)
   {
     viewport.setScaleLeftWrapped(scaleLeft.isSelected());
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3340,6 +3411,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   protected void scaleRight_actionPerformed(ActionEvent e)
   {
     viewport.setScaleRightWrapped(scaleRight.isSelected());
+    alignPanel.updateLayout();
     alignPanel.paintAlignment(true, false);
   }
 
@@ -3493,6 +3565,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                 alignPanel.setOverviewPanel(null);
               };
             });
+    if (getKeyListeners().length > 0)
+    {
+      frame.addKeyListener(getKeyListeners()[0]);
+    }
 
     alignPanel.setOverviewPanel(overview);
   }
@@ -3557,6 +3633,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
      * otherwise set the chosen colour scheme (or null for 'None')
      */
     ColourSchemeI cs = ColourSchemes.getInstance().getColourScheme(name,
+            viewport,
             viewport.getAlignment(), viewport.getHiddenRepSequences());
     changeColour(cs);
   }
@@ -3711,6 +3788,28 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     alignPanel.paintAlignment(true, false);
   }
 
+  @Override
+  public void sortEValueMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByEValue(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+
+  @Override
+  public void sortBitScoreMenuItem_actionPerformed(ActionEvent e)
+  {
+    SequenceI[] oldOrder = viewport.getAlignment().getSequencesArray();
+    AlignmentSorter.sortByBitScore(viewport.getAlignment());
+    addHistoryItem(new OrderCommand("Group Sort", oldOrder,
+            viewport.getAlignment()));
+    alignPanel.paintAlignment(true, false);
+
+  }
+  
   /**
    * DOCUMENT ME!
    * 
@@ -3826,9 +3925,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;
@@ -3920,35 +4019,33 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     }
 
     if (viewport.getAlignment().getAlignmentAnnotation()
-            .hashCode() != _annotationScoreVectorHash)
+            .hashCode() == _annotationScoreVectorHash)
     {
-      sortByAnnotScore.removeAll();
-      // almost certainly a quicker way to do this - but we keep it simple
-      Hashtable scoreSorts = new Hashtable();
-      AlignmentAnnotation aann[];
-      for (SequenceI sqa : viewport.getAlignment().getSequences())
+      return;
+    }
+
+    sortByAnnotScore.removeAll();
+    Set<String> scoreSorts = new HashSet<>();
+    for (SequenceI sqa : viewport.getAlignment().getSequences())
+    {
+      AlignmentAnnotation[] anns = sqa.getAnnotation();
+      for (int i = 0; anns != null && i < anns.length; i++)
       {
-        aann = sqa.getAnnotation();
-        for (int i = 0; aann != null && i < aann.length; i++)
+        AlignmentAnnotation aa = anns[i];
+        if (aa != null && aa.hasScore() && aa.sequenceRef != null)
         {
-          if (aann[i].hasScore() && aann[i].sequenceRef != null)
-          {
-            scoreSorts.put(aann[i].label, aann[i].label);
-          }
+          scoreSorts.add(aa.label);
         }
       }
-      Enumeration labels = scoreSorts.keys();
-      while (labels.hasMoreElements())
-      {
-        addSortByAnnotScoreMenuItem(sortByAnnotScore,
-                (String) labels.nextElement());
-      }
-      sortByAnnotScore.setVisible(scoreSorts.size() > 0);
-      scoreSorts.clear();
-
-      _annotationScoreVectorHash = viewport.getAlignment()
-              .getAlignmentAnnotation().hashCode();
     }
+    for (String label : scoreSorts)
+    {
+      addSortByAnnotScoreMenuItem(sortByAnnotScore, label);
+    }
+    sortByAnnotScore.setVisible(!scoreSorts.isEmpty());
+
+    _annotationScoreVectorHash = viewport.getAlignment()
+            .getAlignmentAnnotation().hashCode();
   }
 
   /**
@@ -4327,7 +4424,7 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                       jws2servs.attachWSMenuEntry(webService, me);
                       for (Jws2Instance sv : jws2servs.getServices())
                       {
-                        if (sv.description.toLowerCase().contains("jpred"))
+                        if (sv.getName().toLowerCase().contains("jpred"))
                         {
                           for (JMenuItem jmi : legacyItems)
                           {
@@ -4347,6 +4444,15 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   }
                 }
                 build_urlServiceMenu(me.webService);
+
+
+                // TODO Mateusz - follow pattern for adding web service
+                // JMenuItems for slivka-based services
+
+                SlivkaWSDiscoverer slivkaDiscoverer = SlivkaWSDiscoverer.getInstance();
+                slivkaDiscoverer.attachWSMenuEntry(webService, me);
+
+
                 build_fetchdbmenu(webService);
                 for (JMenu item : wsmenu)
                 {
@@ -4489,14 +4595,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(
@@ -4525,7 +4631,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))
       {
@@ -4693,17 +4799,22 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
             int assocfiles = 0;
             if (filesmatched.size() > 0)
             {
-              if (Cache.getDefault("AUTOASSOCIATE_PDBANDSEQS", false)
-                      || JvOptionPane.showConfirmDialog(thisaf,
-                              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)
-
+              boolean autoAssociate = Cache
+                      .getDefault("AUTOASSOCIATE_PDBANDSEQS", false);
+              if (!autoAssociate)
+              {
+                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)
               {
                 for (Object[] fm : filesmatched)
                 {
@@ -4729,6 +4840,16 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                   alignPanel.paintAlignment(true, false);
                 }
               }
+              else
+              {
+                /*
+                 * add declined structures as sequences
+                 */
+                for (Object[] o : filesmatched)
+                {
+                  filesnotmatched.add((String) o[0]);
+                }
+              }
             }
             if (filesnotmatched.size() > 0)
             {
@@ -4983,7 +5104,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);
       }
@@ -5123,6 +5244,13 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
               @Override
               public void finished()
               {
+
+                for (FeatureSettingsModelI srcSettings : dbRefFetcher
+                        .getFeatureSettingsModels())
+                {
+
+                  alignPanel.av.mergeFeaturesStyle(srcSettings);
+                }
                 AlignFrame.this.setMenusForViewport();
               }
             });
@@ -5208,6 +5336,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
                                   @Override
                                   public void finished()
                                   {
+                                    FeatureSettingsModelI srcSettings = dassource[0]
+                                            .getFeatureColourScheme();
+                                    alignPanel.av.mergeFeaturesStyle(
+                                            srcSettings);
                                     AlignFrame.this.setMenusForViewport();
                                   }
                                 });
@@ -5500,7 +5632,8 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     {
       PaintRefresher.Refresh(this, viewport.getSequenceSetId());
       alignPanel.updateAnnotation();
-      alignPanel.paintAlignment(true, true);
+      alignPanel.paintAlignment(true,
+              viewport.needToUpdateStructureViews());
     }
   }
 
@@ -5521,6 +5654,10 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
   {
     if (avc.createGroup())
     {
+      if (applyAutoAnnotationSettings.isSelected())
+      {
+        alignPanel.updateAnnotation(true, false);
+      }
       alignPanel.alignmentChanged();
     }
   }
@@ -5611,7 +5748,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;
   }
 
   /**
@@ -5780,15 +5919,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);
@@ -5814,60 +5954,6 @@ public class AlignFrame extends GAlignFrame implements DropTargetListener,
     hmmerMenu.setEnabled(HmmerCommand.isHmmerAvailable());
   }
 
-  /**
-   * Returns the selected hidden Markov model.
-   * 
-   * @return
-   */
-  public HiddenMarkovModel getSelectedHMM()
-  {
-    if (selectedHMMSequence == null)
-    {
-      return null;
-    }
-    return selectedHMMSequence.getHMM();
-  }
-
-  /**
-   * Returns the selected hidden Markov model.
-   * 
-   * @return
-   */
-  public SequenceI getSelectedHMMSequence()
-  {
-    return selectedHMMSequence;
-  }
-
-  /**
-   * Sets the selected hidden Markov model
-   * 
-   * @param selectedHMM
-   */
-  public void setSelectedHMMSequence(SequenceI selectedHMM)
-  {
-    this.selectedHMMSequence = selectedHMM;
-    hmmAlign.setText(MessageManager.getString("label.hmmalign") + " to "
-            + selectedHMM.getHMM().getName());
-    hmmSearch.setText(MessageManager.getString("label.hmmsearch") + " with "
-            + selectedHMM.getHMM().getName());
-  }
-
-  @Override
-  public void hmmerMenu_actionPerformed(ActionEvent e)
-  {
-    SequenceGroup grp = getViewport().getSelectionGroup();
-    if (grp != null)
-    {
-      hmmBuild.setText(MessageManager.getString("label.hmmbuild") + " from "
-              + grp.getName());
-    }
-    else
-    {
-      hmmBuild.setText(MessageManager.getString("label.hmmbuild")
-              + " from Alignment");
-    }
-  }
-
   @Override
   protected void loadVcf_actionPerformed()
   {