Merge branch 'develop' into features/mchmmer
authorgmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 20 Feb 2018 14:32:36 +0000 (14:32 +0000)
committergmungoc <g.m.carstairs@dundee.ac.uk>
Tue, 20 Feb 2018 14:32:36 +0000 (14:32 +0000)
Conflicts:
resources/lang/Messages.properties
src/jalview/api/AlignViewportI.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceI.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GPreferences.java
src/jalview/schemes/ResidueProperties.java
src/jalview/viewmodel/AlignmentViewport.java

28 files changed:
1  2 
resources/lang/Messages.properties
src/jalview/analysis/AAFrequency.java
src/jalview/analysis/SeqsetUtils.java
src/jalview/api/AlignViewportI.java
src/jalview/appletgui/AlignFrame.java
src/jalview/appletgui/AlignViewport.java
src/jalview/datamodel/Alignment.java
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/datamodel/AlignmentI.java
src/jalview/datamodel/Sequence.java
src/jalview/datamodel/SequenceGroup.java
src/jalview/datamodel/SequenceI.java
src/jalview/gui/AlignFrame.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/AnnotationLabels.java
src/jalview/gui/PopupMenu.java
src/jalview/gui/Preferences.java
src/jalview/io/AlignFile.java
src/jalview/io/FileLoader.java
src/jalview/io/IdentifyFile.java
src/jalview/io/StockholmFile.java
src/jalview/jbgui/GAlignFrame.java
src/jalview/jbgui/GPreferences.java
src/jalview/renderer/AnnotationRenderer.java
src/jalview/renderer/ResidueShader.java
src/jalview/schemes/ResidueProperties.java
src/jalview/viewmodel/AlignmentViewport.java
src/jalview/workers/InformationThread.java

@@@ -1315,65 -1315,55 +1319,117 @@@ label.occupancy_descr = Number of align
  label.show_experimental = Enable experimental features
  label.show_experimental_tip = Enable any new and currently 'experimental' features (see Latest Release Notes for details)
  label.warning_hidden = Warning: {0} {1} is currently hidden
+ label.overview_settings = Overview settings
+ label.ov_legacy_gap = Use legacy gap colouring (gaps are white)
+ label.gap_colour = Gap colour:
+ label.ov_show_hide_default = Show hidden regions when opening overview
+ label.hidden_colour = Hidden colour:
+ label.select_gap_colour = Select gap colour
+ label.select_hidden_colour = Select hidden colour
+ label.overview = Overview
+ label.reset_to_defaults = Reset to defaults
+ label.oview_calc = Recalculating overview...
+ label.feature_details = Feature details
+ label.matchCondition_contains = Contains
+ label.matchCondition_notcontains = Does not contain
+ label.matchCondition_matches = Matches
+ label.matchCondition_notmatches = Does not match
+ label.matchCondition_present = Is present
+ label.matchCondition_notpresent = Is not present
+ label.matchCondition_eq = =
+ label.matchCondition_ne = not =
+ label.matchCondition_lt = <
+ label.matchCondition_le = <=
+ label.matchCondition_gt = >
+ label.matchCondition_ge = >=
+ label.numeric_required = The value should be numeric
+ label.filter = Filter
+ label.filters = Filters
+ label.join_conditions = Join conditions with
+ label.score = Score
+ label.colour_by_label = Colour by label
+ label.variable_colour = Variable colour...
+ label.select_colour = Select colour
+ option.enable_disable_autosearch = When ticked, search is performed automatically
+ option.autosearch = Autosearch
+ label.retrieve_ids = Retrieve IDs
+ label.display_settings_for = Display settings for {0} features
+ label.simple = Simple
+ label.simple_colour = Simple Colour
+ label.colour_by_text = Colour by text
+ label.graduated_colour = Graduated Colour
+ label.by_text_of = By text of
+ label.by_range_of = By range of
+ label.filters_tooltip = Click to set or amend filters
+ label.or = Or
+ label.and = And
+ label.sequence_feature_colours = Sequence Feature Colours
+ label.best_quality = Best Quality
+ label.best_resolution = Best Resolution
+ label.most_protein_chain = Most Protein Chain
+ label.most_bound_molecules = Most Bound Molecules
+ label.most_polymer_residues = Most Polymer Residues
+ label.cached_structures = Cached Structures
+ label.free_text_search = Free Text Search
 +label.hmmalign = hmmalign
 +label.hmmbuild = hmmbuild
 +label.hmmbuild_group = Build HMM from Selected Group
 +label.group_hmmbuild = Build HMM from Group
 +label.hmmsearch = hmmsearch
 +label.hmmer_location = HMMER Binaries Installation Location
 +warn.null_hmm = Please ensure the alignment contains a hidden Markov model.
 +label.ignore_below_background_frequency = Ignore Below Background Frequency
 +label.information_description = Information content, measured in bits
 +warn.no_selected_hmm = Please select a hidden Markov model sequence.
 +label.select_hmm = Select HMM
 +warn.no_sequence_data = No sequence data found.
 +warn.empty_grp_or_alignment = An empty group or alignment was found.
 +label.no_sequences_found = No matching sequences, or an error occurred.
 +label.hmmer = HMMER
 +label.trim_termini = Trim Non-Matching Termini
 +label.trim_termini_desc = If true, non-matching regions on either end of the resulting alignment are removed.
 +label.no_of_sequences = Sequences Returned
 +label.freq_alignment = Use Alignment Background Frequencies
 +label.freq_uniprot = Use Uniprot Background Frequencies
 +label.hmmalign_label = hmmalign Options
 +label.hmmsearch_label = hmmsearch Options
 +label.hmmbuild_not_found = The hmmbuild binary was not found
 +label.hmmalign_not_found = The hmmalign binary was not found
 +label.hmmsearch_not_found = The hmmsearch binary was not found
 +warn.hmm_command_failed = hmm command not found
 +label.invalid_folder = Invalid Folder
 +label.folder_not_exists = HMMER binaries not found. \n Please enter the path to the HMMER binaries (if installed).
 +label.hmmer_installed = HMMER installed
 +label.hmmer_no_sequences_found = No sequences found
 +label.number_of_results = Number of Results to Return
 +label.auto_align_seqs = Automatically Align Fetched Sequences
 +label.use_accessions = Return Accessions
 +label.seq_e_value = Sequence E-value Cutoff
 +label.seq_score = Sequence Score Threshold
 +label.dom_e_value = Domain E-value Cutoff
 +label.dom_score = Domain Score Threshold
 +label.number_of_results_desc = The maximum number of results that hmmsearch will return
 +label.auto_align_seqs_desc = If true, all fetched sequences will be aligned to the hidden Markov model with which the search was performed
 +label.use_accessions_desc = If true, the accession number of each sequence is returned, rather than that sequences name
 +label.seq_e_value_desc = The E-value cutoff for returned sequences
 +label.seq_score_desc = The score threshold for returned sequences
 +label.dom_e_value_desc = The E-value cutoff for returned domains
 +label.dom_score_desc = The score threshold for returned domains
 +label.not_enough_sequences = There are not enough sequences to run {0}
 +label.add_database = Add Database
 +label.this_alignment = This alignment
 +warn.file_not_exists = File does not exist
 +warn.invalid_format = This is not a valid database file format. The current supported formats are Fasta, Stockholm and Pfam.
 +label.database_for_hmmsearch = The database hmmsearch will search through
 +label.use_reference = Use Reference Annotation
 +label.use_reference_desc = If true, hmmbuild will keep all columns defined as a reference position by the reference annotation
 +label.hmm_name = HMM Name
 +label.hmm_name_desc = The name given to the HMM.
 +warn.no_reference_annotation = No reference annotation found.
 +label.hmmbuild_for = Build HMM for
 +label.hmmbuild_for_desc = Build an HMM for the selected sequence groups.
 +label.alignment = Alignment
 +label.groups_and_alignment = All groups and alignment
 +label.groups = All groups
 +label.selected_group = Selected group
 +label.use_info_for_height = Use Information Content as Letter Height
Simple merge
Simple merge
@@@ -54,7 -54,7 +54,7 @@@ public interface AlignViewportI extend
     * 
     * @return
     */
--  public ViewportRanges getRanges();
++  ViewportRanges getRanges();
  
    /**
     * calculate the height for visible annotation, revalidating bounds where
@@@ -62,7 -62,7 +62,7 @@@
     * 
     * @return total height of annotation
     */
--  public int calcPanelHeight();
++  int calcPanelHeight();
  
    /**
     * Answers true if the viewport has at least one column selected
     * 
     * @return a copy of this view's current display settings
     */
--  public ViewStyleI getViewStyle();
++  ViewStyleI getViewStyle();
  
    /**
     * update the view's display settings with the given style set
     * 
     * @param settingsForView
     */
--  public void setViewStyle(ViewStyleI settingsForView);
++  void setViewStyle(ViewStyleI settingsForView);
  
    /**
     * Returns a viewport which holds the cDna for this (protein), or vice versa,
     */
    void setFollowHighlight(boolean b);
  
--  public void applyFeaturesStyle(FeatureSettingsModelI featureSettings);
++  void applyFeaturesStyle(FeatureSettingsModelI featureSettings);
  
    /**
     * check if current selection group is defined on the view, or is simply a
    @Override
    void setProteinFontAsCdna(boolean b);
  
 -  public abstract TreeModel getCurrentTree();
 +  void setSequenceInformationHashes(List<ProfilesI> info);
 +
 +  List<ProfilesI> getSequenceInformationHashes();
 +
 +  ProfilesI getSequenceInformationHash(int index);
 +
 +  List<AlignmentAnnotation> getInformationAnnotations();
 +
 +  AlignmentAnnotation getInformationAnnotation(int index);
 +
 +  void setSequenceInformationHash(ProfilesI info, int index);
 +
 +  /**
 +   * Initiates the information annotation for all uninitiated sequences.
 +   */
 +  void initInformation();
 +
 +  /**
 +   * Updates all information annotations.
 +   * 
 +   * @param ap
 +   */
 +  void updateInformation(AlignmentViewPanel ap);
 +
 +  boolean isInfoLetterHeight();
 +
++  abstract TreeModel getCurrentTree();
 -  public abstract void setCurrentTree(TreeModel tree);
++  abstract void setCurrentTree(TreeModel tree);
  }
Simple merge
Simple merge
@@@ -1494,4 -1473,70 +1473,68 @@@ public class AlignmentAnnotatio
      return graphMin < graphMax;
    }
  
+   public static Iterable<AlignmentAnnotation> findAnnotations(
+           Iterable<AlignmentAnnotation> list, SequenceI seq, String calcId,
+           String label)
+   {
 -
 -    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
++    List<AlignmentAnnotation> aa = new ArrayList<>();
+     for (AlignmentAnnotation ann : list)
+     {
+       if ((calcId == null || (ann.getCalcId() != null
+               && ann.getCalcId().equals(calcId)))
+               && (seq == null || (ann.sequenceRef != null
+                       && ann.sequenceRef == seq))
+               && (label == null
+                       || (ann.label != null && ann.label.equals(label))))
+       {
+         aa.add(ann);
+       }
+     }
+     return aa;
+   }
+   /**
+    * Answer true if any annotation matches the calcId passed in (if not null).
+    * 
+    * @param list
+    *          annotation to search
+    * @param calcId
+    * @return
+    */
+   public static boolean hasAnnotation(List<AlignmentAnnotation> list,
+           String calcId)
+   {
+     if (calcId != null && !"".equals(calcId))
+     {
+       for (AlignmentAnnotation a : list)
+       {
+         if (a.getCalcId() == calcId)
+         {
+           return true;
+         }
+       }
+     }
+     return false;
+   }
+   public static Iterable<AlignmentAnnotation> findAnnotation(
+           List<AlignmentAnnotation> list, String calcId)
+   {
 -
+     List<AlignmentAnnotation> aa = new ArrayList<>();
+     if (calcId == null)
+     {
+       return aa;
+     }
+     for (AlignmentAnnotation a : list)
+     {
+       if (a.getCalcId() == calcId || (a.getCalcId() != null
+               && calcId != null && a.getCalcId().equals(calcId)))
+       {
+         aa.add(a);
+       }
+     }
+     return aa;
+   }
  }
Simple merge
@@@ -473,7 -444,7 +461,7 @@@ public class Sequence extends ASequenc
    @Override
    public Vector<PDBEntry> getAllPDBEntries()
    {
--    return pdbIds == null ? new Vector<PDBEntry>() : pdbIds;
++    return pdbIds == null ? new Vector<>() : pdbIds;
    }
  
    /**
        return null;
      }
  
-     Vector subset = new Vector();
-     Enumeration e = annotation.elements();
 -    Vector<AlignmentAnnotation> subset = new Vector<AlignmentAnnotation>();
++    Vector<AlignmentAnnotation> subset = new Vector<>();
+     Enumeration<AlignmentAnnotation> e = annotation.elements();
      while (e.hasMoreElements())
      {
-       AlignmentAnnotation ann = (AlignmentAnnotation) e.nextElement();
+       AlignmentAnnotation ann = e.nextElement();
        if (ann.label != null && ann.label.equals(label))
        {
          subset.addElement(ann);
      }
    }
  
 +  @Override
 +  public HiddenMarkovModel getHMM()
 +  {
 +    return hmm;
 +  }
 +
 +  @Override
 +  public void setHMM(HiddenMarkovModel hmm)
 +  {
 +    this.hmm = hmm;
 +  }
 +
 +  @Override
 +  public void updateHMMMapping()
 +  {
 +    int node = 1;
 +    int column = 0;
 +    hmm.emptyNodeLookup();
 +    for (char residue : sequence)
 +    {
 +      if (!Comparison.isGap(residue))
 +      {
 +        hmm.setAlignmentColumn(node, column);
 +        node++;
 +      }
 +      column++;
 +    }
 +  }
 +
 +  /**
 +   * Maps the HMM sequence to the reference annotation.
 +   * 
 +   * @param rf
 +   */
 +  @Override
 +  public void mapToReference(AlignmentAnnotation rf)
 +  {
 +    if (this.isHMMConsensusSequence)
 +    {
 +      int node = 1;
 +      hmm.emptyNodeLookup();
 +      for (int i = 0; i < getLength(); i++)
 +      {
 +        if (rf.annotations[i].displayCharacter.equals("x")
 +                || rf.annotations[i].displayCharacter.equals("X"))
 +        {
 +          if (i < hmm.getNodeAlignmentColumn(node))
 +          {
 +            this.deleteChars(i, hmm.getNodeAlignmentColumn(node));
 +            updateHMMMapping();
 +          }
 +          else if (i > hmm.getNodeAlignmentColumn(node))
 +          {
 +            int length = i - hmm.getNodeAlignmentColumn(node);
 +            this.insertCharAt(hmm.getNodeAlignmentColumn(node), length,
 +                    '-');
 +            updateHMMMapping();
 +          }
 +          node++;
 +        }
 +      }
 +    }
 +  }
 +
 +  @Override
 +  public boolean isHMMConsensusSequence()
 +  {
 +    return isHMMConsensusSequence;
 +  }
 +
 +  @Override
 +  public void setIsHMMConsensusSequence(boolean isHMMConsensusSequence)
 +  {
 +    this.isHMMConsensusSequence = isHMMConsensusSequence;
 +  }
 +
 +  @Override
 +  public boolean hasHMMAnnotation()
 +  {
 +    return hasInfo;
 +  }
 +
 +  @Override
 +  public void setHasInfo(boolean status)
 +  {
 +    hasInfo = true;
 +  }
 +
 +  @Override
 +  public int getPreviousPosition()
 +  {
 +    return previousPosition;
 +  }
 +
 +  @Override
 +  public void setPreviousPosition(int previousPosition)
 +  {
 +    this.previousPosition = previousPosition;
 +  }
 +
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public List<SequenceFeature> findFeatures(int fromColumn, int toColumn,
+           String... types)
+   {
+     int startPos = findPosition(fromColumn - 1); // convert base 1 to base 0
+     int endPos = fromColumn == toColumn ? startPos
+             : findPosition(toColumn - 1);
+     List<SequenceFeature> result = getFeatures().findFeatures(startPos,
+             endPos, types);
+     /*
+      * if end column is gapped, endPos may be to the right, 
+      * and we may have included adjacent or enclosing features;
+      * remove any that are not enclosing, non-contact features
+      */
+     boolean endColumnIsGapped = toColumn > 0 && toColumn <= sequence.length
+             && Comparison.isGap(sequence[toColumn - 1]);
+     if (endPos > this.end || endColumnIsGapped)
+     {
+       ListIterator<SequenceFeature> it = result.listIterator();
+       while (it.hasNext())
+       {
+         SequenceFeature sf = it.next();
+         int sfBegin = sf.getBegin();
+         int sfEnd = sf.getEnd();
+         int featureStartColumn = findIndex(sfBegin);
+         if (featureStartColumn > toColumn)
+         {
+           it.remove();
+         }
+         else if (featureStartColumn < fromColumn)
+         {
+           int featureEndColumn = sfEnd == sfBegin ? featureStartColumn
+                   : findIndex(sfEnd);
+           if (featureEndColumn < fromColumn)
+           {
+             it.remove();
+           }
+           else if (featureEndColumn > toColumn && sf.isContactFeature())
+           {
+             /*
+              * remove an enclosing feature if it is a contact feature
+              */
+             it.remove();
+           }
+         }
+       }
+     }
+     return result;
+   }
+   /**
+    * Invalidates any stale cursors (forcing recalculation) by incrementing the
+    * token that has to match the one presented by the cursor
+    */
+   @Override
+   public void sequenceChanged()
+   {
+     changeCount++;
+   }
+   /**
+    * {@inheritDoc}
+    */
+   @Override
+   public int replace(char c1, char c2)
+   {
+     if (c1 == c2)
+     {
+       return 0;
+     }
+     int count = 0;
+     synchronized (sequence)
+     {
+       for (int c = 0; c < sequence.length; c++)
+       {
+         if (sequence[c] == c1)
+         {
+           sequence[c] = c2;
+           count++;
+         }
+       }
+     }
+     if (count > 0)
+     {
+       sequenceChanged();
+     }
+     return count;
+   }
  }
@@@ -25,10 -25,12 +25,13 @@@ import jalview.analysis.Conservation
  import jalview.renderer.ResidueShader;
  import jalview.renderer.ResidueShaderI;
  import jalview.schemes.ColourSchemeI;
 +import jalview.util.MessageManager;
  
  import java.awt.Color;
+ import java.beans.PropertyChangeListener;
+ import java.beans.PropertyChangeSupport;
  import java.util.ArrayList;
+ import java.util.Arrays;
  import java.util.List;
  import java.util.Map;
  
@@@ -482,26 -487,60 +491,76 @@@ public interface SequenceI extends ASeq
     */
    public List<DBRefEntry> getPrimaryDBRefs();
  
 +  public void updateHMMMapping();
 +
 +  boolean isHMMConsensusSequence();
 +
 +  void setIsHMMConsensusSequence(boolean isHMMConsensusSequence);
 +
 +  boolean hasHMMAnnotation();
 +
 +  void setHasInfo(boolean status);
 +
 +  int getPreviousPosition();
 +
 +  void setPreviousPosition(int previousPosition);
 +
    /**
+    * Returns a (possibly empty) list of sequence features that overlap the given
+    * alignment column range, optionally restricted to one or more specified
+    * feature types. If the range is all gaps, then features which enclose it are
+    * included (but not contact features).
+    * 
+    * @param fromCol
+    *          start column of range inclusive (1..)
+    * @param toCol
+    *          end column of range inclusive (1..)
+    * @param types
+    *          optional feature types to restrict results to
+    * @return
+    */
+   List<SequenceFeature> findFeatures(int fromCol, int toCol, String... types);
+   /**
+    * Method to call to indicate that the sequence (characters or alignment/gaps)
+    * has been modified. Provided to allow any cursors on residue/column
+    * positions to be invalidated.
+    */
+   void sequenceChanged();
+   
+   /**
     * 
     * @return BitSet corresponding to index [0,length) where Comparison.isGap()
     *         returns true.
     */
    BitSet getInsertionsAsBits();
  
 +  void mapToReference(AlignmentAnnotation rf);
++
+   /**
+    * Replaces every occurrence of c1 in the sequence with c2 and returns the
+    * number of characters changed
+    * 
+    * @param c1
+    * @param c2
+    */
 -  public int replace(char c1, char c2);
++  int replace(char c1, char c2);
+   /**
+    * Answers the GeneLociI, or null if not known
+    * 
+    * @return
+    */
+   GeneLociI getGeneLoci();
+   /**
+    * Sets the mapping to gene loci for the sequence
+    * 
+    * @param speciesId
+    * @param assemblyId
+    * @param chromosomeId
+    * @param map
+    */
+   void setGeneLoci(String speciesId, String assemblyId,
+           String chromosomeId, MapList map);
  }
@@@ -183,13 -164,7 +184,11 @@@ public class AlignFrame extends GAlignF
  
    AlignViewport viewport;
  
-   ViewportRanges vpRanges;
    public AlignViewControllerI avc;
 +  /*
 +   * The selected HMM for this align frame
 +   */
 +  SequenceI selectedHMMSequence;
  
    List<AlignmentPanel> alignPanels = new ArrayList<>();
  
      }
    }
  
 +  /**
 +   * Sets the status of the HMMER menu
 +   */
 +  public void updateHMMERStatus()
 +  {
 +    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()
+   {
+     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
@@@ -22,7 -22,7 +22,6 @@@ package jalview.gui
  
  import jalview.analysis.AlignmentUtils;
  import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
--import jalview.analysis.TreeModel;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.api.FeatureColourI;
@@@ -1119,13 -1035,4 +1095,11 @@@ public class AlignViewport extends Alig
      }
      fr.setTransparency(featureSettings.getTransparency());
    }
 +
 +  @Override
 +  public boolean isNormaliseHMMSequenceLogo()
 +  {
 +    return normaliseHMMSequenceLogo;
 +  }
 +
  }
Simple merge
@@@ -354,25 -359,8 +360,25 @@@ public class PopupMenu extends JPopupMe
        });
        add(menuItem);
  
 +      if (sequence.isHMMConsensusSequence())
 +      {
 +        JMenuItem selectHMM = new JCheckBoxMenuItem();
 +        selectHMM.setText(MessageManager.getString("label.select_hmm"));
 +        selectHMM.addActionListener(new ActionListener()
 +        {
 +
 +          @Override
 +          public void actionPerformed(ActionEvent e)
 +          {
 +            selectHMM_actionPerformed(e);
 +          }
 +        });
 +        add(selectHMM);
 +      }
 +
 +
-       if (ap.av.getSelectionGroup() != null
-               && ap.av.getSelectionGroup().getSize() > 1)
+       if (alignPanel.av.getSelectionGroup() != null
+               && alignPanel.av.getSelectionGroup().getSize() > 1)
        {
          menuItem = new JMenuItem(MessageManager
                  .formatMessage("label.represent_group_with", new Object[]
          buildGroupURLMenu(sg, groupLinks);
        }
        // Add a 'show all structures' for the current selection
-       Hashtable<String, PDBEntry> pdbe = new Hashtable<>(),
-               reppdb = new Hashtable<>();
 -      Hashtable<String, PDBEntry> pdbe = new Hashtable<>(), reppdb = new Hashtable<>();
++      Hashtable<String, PDBEntry> pdbe = new Hashtable<>();
++      Hashtable<String, PDBEntry> reppdb = new Hashtable<>();
        SequenceI sqass = null;
-       for (SequenceI sq : ap.av.getSequenceSelection())
+       for (SequenceI sq : alignPanel.av.getSequenceSelection())
        {
          Vector<PDBEntry> pes = sq.getDatasetSequence().getAllPDBEntries();
          if (pes != null && pes.size() > 0)
@@@ -679,39 -656,16 +704,49 @@@ public class Preferences extends GPrefe
              maxColour.getBackground());
  
      /*
 +     * Save HMMER settings
 +     */
 +    Cache.applicationProperties.setProperty("TRIM_TERMINI",
 +            Boolean.toString(hmmrTrimTermini.isSelected()));
 +    Cache.applicationProperties.setProperty("USE_UNIPROT",
 +            Boolean.toString(hmmerBackgroundUniprot.isSelected()));
 +    Cache.applicationProperties.setProperty("SEQUENCES_TO_KEEP",
 +            hmmerSequenceCount.getText());
 +    Cache.applicationProperties.setProperty(HMMER_PATH,
 +            hmmerPath.getText());
 +    AlignFrame[] frames = Desktop.getAlignFrames();
 +    if (frames != null && frames.length > 0)
 +    {
 +      for (AlignFrame f : frames)
 +      {
 +        f.updateHMMERStatus();
 +      }
 +    }
 +    
 +    hmmrTrimTermini.setSelected(Cache.getDefault("TRIM_TERMINI", false));
 +    if (Cache.getDefault("USE_UNIPROT", false))
 +    {
 +      hmmerBackgroundUniprot.setSelected(true);
 +    }
 +    else
 +    {
 +      hmmerBackgroundAlignment.setSelected(true);
 +    }
 +    hmmerSequenceCount
 +            .setText(Cache.getProperty("SEQUENCES_TO_KEEP"));
 +    hmmerPath.setText(Cache.getProperty(HMMER_PATH));
 +
 +    /*
+      * Save Overview settings
+      */
+     Cache.setColourProperty(GAP_COLOUR, gapColour.getBackground());
+     Cache.setColourProperty(HIDDEN_COLOUR, hiddenColour.getBackground());
+     Cache.applicationProperties.setProperty(USE_LEGACY_GAP,
+             Boolean.toString(useLegacyGap.isSelected()));
+     Cache.applicationProperties.setProperty(SHOW_OV_HIDDEN_AT_START,
+             Boolean.toString(showHiddenAtStart.isSelected()));
+     /*
       * Save Structure settings
       */
      Cache.applicationProperties.setProperty(ADD_TEMPFACT_ANN,
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1368,16 -1307,19 +1370,26 @@@ public class GAlignFrame extends JInter
        @Override
        public void actionPerformed(ActionEvent e)
        {
 -        associatedData_actionPerformed(e);
 +        try
 +        {
 +          associatedData_actionPerformed(e);
 +        } catch (IOException | InterruptedException e1)
 +        {
 +          // TODO Auto-generated catch block
 +          e1.printStackTrace();
 +        }
        }
      });
+     loadVcf = new JMenuItem(MessageManager.getString("label.load_vcf_file"));
+     loadVcf.setToolTipText(MessageManager.getString("label.load_vcf"));
+     loadVcf.addActionListener(new ActionListener()
+     {
+       @Override
+       public void actionPerformed(ActionEvent e)
+       {
+         loadVcf_actionPerformed();
+       }
+     });
      autoCalculate.setText(
              MessageManager.getString("label.autocalculate_consensus"));
      autoCalculate.setState(
      fileMenu.add(exportAnnotations);
      fileMenu.add(loadTreeMenuItem);
      fileMenu.add(associatedData);
+     fileMenu.add(loadVcf);
      fileMenu.addSeparator();
      fileMenu.add(closeMenuItem);
 -
 +  
      pasteMenu.add(pasteNew);
      pasteMenu.add(pasteThis);
      editMenu.add(undoMenuItem);
      // selectMenu.add(listenToViewSelections);
    }
  
 +  public void hmmerMenu_actionPerformed(ActionEvent e)
 +  {
 +
 +  }
 +
 +  /**
 +   * Constructs the entries on the HMMER menu (does not add them to the menu).
 +   */
 +  protected void initHMMERMenu()
 +  {
 +    hmmAlign = new JMenu(MessageManager.getString("label.hmmalign"));
 +    hmmAlignSettings = new JMenuItem(
 +            MessageManager.getString("label.edit_settings_and_run"));
 +    hmmAlignRun = new JMenuItem(MessageManager.formatMessage(
 +            "label.action_with_default_settings", "hmmalign"));
 +    hmmAlign.add(hmmAlignSettings);
 +    hmmAlign.add(hmmAlignRun);
 +    hmmBuild = new JMenu(MessageManager.getString("label.hmmbuild"));
 +    hmmBuildSettings = new JMenuItem(
 +            MessageManager.getString("label.edit_settings_and_run"));
 +    hmmBuildRun = new JMenuItem(MessageManager.formatMessage(
 +            "label.action_with_default_settings", "hmmbuild"));
 +    hmmBuild.add(hmmBuildSettings);
 +    hmmBuild.add(hmmBuildRun);
 +    hmmSearch = new JMenu(MessageManager.getString("label.hmmsearch"));
 +    hmmSearchSettings = new JMenuItem(
 +            MessageManager.getString("label.edit_settings_and_run"));
 +    hmmSearchRun = new JMenuItem(MessageManager.formatMessage(
 +            "label.action_with_default_settings", "hmmsearch"));
 +    addDatabase = new JMenuItem(
 +            MessageManager.getString("label.add_database"));
 +    hmmSearch.add(hmmSearchSettings);
 +    hmmSearch.add(hmmSearchRun);
 +    hmmSearch.add(addDatabase);
 +  }
 +
+   protected void loadVcf_actionPerformed()
+   {
+   }
    /**
     * Constructs the entries on the Colour menu (but does not add them to the
     * menu).
Simple merge
@@@ -3141,17 -2938,15 +3143,28 @@@ public abstract class AlignmentViewpor
      return sq;
    }
  
 +  public boolean hasReferenceAnnotation()
 +  {
 +    AlignmentAnnotation[] annots = this.alignment.getAlignmentAnnotation();
 +    for (AlignmentAnnotation annot : annots)
 +    {
 +      if ("RF".equals(annot.label) || annot.label.contains("Reference"))
 +      {
 +        return true;
 +      }
 +    }
 +    return false;
 +  }
 +
+   @Override
+   public void setCurrentTree(TreeModel tree)
+   {
+     currentTree = tree;
+   }
+   @Override
+   public TreeModel getCurrentTree()
+   {
+     return currentTree;
+   }
  }
index 2abfc69,0000000..8f8dac5
mode 100644,000000..100644
--- /dev/null
@@@ -1,250 -1,0 +1,236 @@@
 +package jalview.workers;
 +
 +import jalview.analysis.AAFrequency;
 +import jalview.api.AlignViewportI;
 +import jalview.api.AlignmentViewPanel;
 +import jalview.datamodel.AlignmentAnnotation;
 +import jalview.datamodel.AlignmentI;
 +import jalview.datamodel.Annotation;
 +import jalview.datamodel.HiddenMarkovModel;
 +import jalview.datamodel.ProfilesI;
 +import jalview.datamodel.SequenceI;
 +import jalview.renderer.ResidueShaderI;
 +
 +import java.util.List;
 +
 +public class InformationThread extends AlignCalcWorker
 +{
-   
++
 +  Float max = 0f;
-   
++
 +  /**
 +   * Constructor for information thread.
 +   * 
 +   * @param alignViewport
 +   * @param alignPanel
 +   */
 +  public InformationThread(AlignViewportI alignViewport,
-             AlignmentViewPanel alignPanel)
++          AlignmentViewPanel alignPanel)
++  {
++    super(alignViewport, alignPanel);
++  }
++
++  @Override
++  public void run()
++  {
++    if (calcMan.isPending(this))
 +    {
-       super(alignViewport, alignPanel);
++      return;
 +    }
++    calcMan.notifyStart(this);
++    long started = System.currentTimeMillis();
 +
-     @Override
-     public void run()
++    List<AlignmentAnnotation> information = getInformationAnnotations();
++    try
 +    {
-       if (calcMan.isPending(this))
++      if ((information == null) || calcMan.isPending(this))
 +      {
++        calcMan.workerComplete(this);
 +        return;
 +      }
-       calcMan.notifyStart(this);
-       long started = System.currentTimeMillis();
-     List<AlignmentAnnotation> information = getInformationAnnotations();
-       try
++      while (!calcMan.notifyWorking(this))
 +      {
-       if ((information == null) || calcMan.isPending(this))
-         {
-           calcMan.workerComplete(this);
-           return;
-         }
-         while (!calcMan.notifyWorking(this))
-         {
-           // System.err.println("Thread
++        // System.err.println("Thread
 +        // (Information"+Thread.currentThread().getName()+") Waiting around.");
-           try
-           {
-             if (ap != null)
-             {
-               ap.paintAlignment(false);
-             }
-             Thread.sleep(200);
-           } catch (Exception ex)
++        try
++        {
++          if (ap != null)
 +          {
-             ex.printStackTrace();
++            ap.paintAlignment(false, false);
 +          }
-         }
-         if (alignViewport.isClosed())
++          Thread.sleep(200);
++        } catch (Exception ex)
 +        {
-           abortAndDestroy();
-           return;
++          ex.printStackTrace();
 +        }
-         AlignmentI alignment = alignViewport.getAlignment();
++      }
++      if (alignViewport.isClosed())
++      {
++        abortAndDestroy();
++        return;
++      }
++      AlignmentI alignment = alignViewport.getAlignment();
 +
-         int aWidth = -1;
++      int aWidth = -1;
 +
-         if (alignment == null || (aWidth = alignment.getWidth()) < 0)
-         {
-           calcMan.workerComplete(this);
-           return;
-         }
++      if (alignment == null || (aWidth = alignment.getWidth()) < 0)
++      {
++        calcMan.workerComplete(this);
++        return;
++      }
 +
 +      eraseInformation(aWidth);
 +      computeInformation(alignment);
-         updateResultAnnotation(true);
++      updateResultAnnotation(true);
 +
-         if (ap != null)
-         {
-           ap.paintAlignment(true);
-         }
-       } catch (OutOfMemoryError error)
++      if (ap != null)
 +      {
-         calcMan.disableWorker(this);
++        ap.paintAlignment(true, true);
++      }
++    } catch (OutOfMemoryError error)
++    {
++      calcMan.disableWorker(this);
 +      ap.raiseOOMWarning("calculating information", error);
 +    } finally
 +    {
 +      calcMan.workerComplete(this);
-       }
 +    }
++  }
 +
-     /**
++  /**
 +   * Clear out any existing information annotations
 +   * 
 +   * @param aWidth
 +   *          the width (number of columns) of the annotated alignment
 +   */
 +  protected void eraseInformation(int aWidth)
-     {
++  {
 +
 +    List<AlignmentAnnotation> information = getInformationAnnotations();
 +    for (AlignmentAnnotation info : information)
 +    {
 +      info.annotations = new Annotation[aWidth];
 +    }
-     }
++  }
 +
-     /**
++  /**
 +   * Computes the profiles from a HMM for an alignment.
 +   * 
 +   * @param alignment
 +   */
 +  protected void computeInformation(AlignmentI alignment)
-     {
-       int width = alignment.getWidth();
++  {
++    int width = alignment.getWidth();
 +    List<SequenceI> hmmSeqs = alignment.getHMMConsensusSequences(false);
 +    int index = 0;
 +
 +    for (SequenceI seq : hmmSeqs)
 +    {
 +      HiddenMarkovModel hmm = seq.getHMM();
 +      ProfilesI hinformation = AAFrequency.calculateHMMProfiles(hmm, width,
 +              0, width, true, alignViewport.isIgnoreBelowBackground(),
 +              alignViewport.isInfoLetterHeight());
 +      alignViewport.setSequenceInformationHash(hinformation, index);
 +      // setColourSchemeInformation(hinformation);
 +      index++;
 +    }
-     }
++  }
 +
-     /**
++  /**
 +   * gets the sequences on the alignment on the viewport.
 +   * 
 +   * @return
 +   */
-     protected SequenceI[] getSequences()
-     {
-       return alignViewport.getAlignment().getSequencesArray();
-     }
++  protected SequenceI[] getSequences()
++  {
++    return alignViewport.getAlignment().getSequencesArray();
++  }
 +
 +  protected void setColourSchemeInformation(ProfilesI information)
++  {
++    ResidueShaderI cs = alignViewport.getResidueShading();
++    if (cs != null)
 +    {
-       ResidueShaderI cs = alignViewport.getResidueShading();
-       if (cs != null)
-       {
 +      cs.setInformation(information);
-       }
 +    }
++  }
 +
-     /**
++  /**
 +   * Get the Information annotation for the alignment
 +   * 
 +   * @return
 +   */
 +  protected List<AlignmentAnnotation> getInformationAnnotations()
-     {
++  {
 +    return alignViewport.getInformationAnnotations();
-     }
++  }
 +
-     /**
-      * Get the Gap annotation for the alignment
-      * 
-      * @return
-      */
-     protected AlignmentAnnotation getGapAnnotation()
-     {
-       return alignViewport.getAlignmentGapAnnotation();
-     }
++  /**
++   * Get the Gap annotation for the alignment
++   * 
++   * @return
++   */
++  protected AlignmentAnnotation getGapAnnotation()
++  {
++    return alignViewport.getAlignmentGapAnnotation();
++  }
 +
-     /**
++  /**
 +   * update the information annotation from the sequence profile data using
 +   * current visualization settings.
 +   */
-     @Override
-     public void updateAnnotation()
-     {
-       updateResultAnnotation(false);
-     }
++  @Override
++  public void updateAnnotation()
++  {
++    updateResultAnnotation(false);
++  }
 +
 +  /**
 +   * Derives the information content for an information annotation.
 +   * 
 +   * @param immediate
 +   */
-     public void updateResultAnnotation(boolean immediate)
-     {
++  public void updateResultAnnotation(boolean immediate)
++  {
 +    List<AlignmentAnnotation> annots = getInformationAnnotations();
 +    int index = 0;
 +    for (AlignmentAnnotation information : annots)
 +    {
 +      ProfilesI hinformation = (ProfilesI) getSequenceInformation(index);
 +      if (immediate || !calcMan.isWorking(this) && information != null
-             && hinformation != null)
++              && hinformation != null)
 +      {
 +        deriveInformation(information, hinformation);
 +      }
 +      index++;
-       }
 +    }
++  }
 +
-     /**
++  /**
 +   * Convert the computed information data into the desired annotation for
 +   * display.
 +   * 
 +   * @param informationAnnotation
 +   *          the annotation to be populated
 +   * @param hinformation
 +   *          the computed information data
 +   */
 +  protected void deriveInformation(
 +          AlignmentAnnotation informationAnnotation, ProfilesI hinformation)
-     {
-       long nseq = getSequences().length;
++  {
++    long nseq = getSequences().length;
 +    max = AAFrequency.completeInformation(informationAnnotation,
 +            hinformation, hinformation.getStartColumn(),
 +            hinformation.getEndColumn() + 1, nseq, max);
-     }
++  }
 +
-     /**
++  /**
 +   * Get the information data stored on the viewport.
 +   * 
 +   * @return
 +   */
 +  protected Object getSequenceInformation(int index)
-     {
-     // TODO convert ComplementInformationThread to use Profile
++  {
 +    return alignViewport.getSequenceInformationHash(index);
-     }
 +  }
++}