Merge commit 'alpha/update_2_12_for_2_11_2_series_merge^2' into HEAD
[jalview.git] / src / jalview / viewmodel / AlignmentViewport.java
index 5a7a27f..345f08a 100644 (file)
@@ -22,7 +22,11 @@ package jalview.viewmodel;
 
 import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
 import jalview.analysis.Conservation;
+import jalview.analysis.TreeModel;
 import jalview.api.AlignCalcManagerI;
+import jalview.api.AlignCalcManagerI2;
+import jalview.api.AlignCalcWorkerI;
+import jalview.api.AlignExportSettingsI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeaturesDisplayedI;
@@ -30,10 +34,10 @@ import jalview.api.ViewStyleI;
 import jalview.commands.CommandI;
 import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
+import jalview.datamodel.AlignmentExportData;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
-import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.HiddenColumns;
 import jalview.datamodel.HiddenSequences;
@@ -55,8 +59,10 @@ import jalview.util.MappingUtils;
 import jalview.util.MessageManager;
 import jalview.viewmodel.styles.ViewStyle;
 import jalview.workers.AlignCalcManager;
+import jalview.workers.AlignCalcManager2;
 import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
+import jalview.workers.InformationThread;
 import jalview.workers.StrucConsensusThread;
 
 import java.awt.Color;
@@ -67,6 +73,7 @@ import java.util.BitSet;
 import java.util.Deque;
 import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Iterator;
 import java.util.List;
 import java.util.Map;
 
@@ -77,10 +84,12 @@ import java.util.Map;
  * @author jimp
  * 
  */
-public abstract class AlignmentViewport implements AlignViewportI,
-        CommandListener, VamsasSource
+public abstract class AlignmentViewport
+        implements AlignViewportI, CommandListener, VamsasSource
 {
-  final protected ViewportRanges ranges;
+  public static final String PROPERTY_ALIGNMENT = "alignment";
+  public static final String PROPERTY_SEQUENCE = "sequence";
+  protected ViewportRanges ranges;
 
   protected ViewStyleI viewStyle = new ViewStyle();
 
@@ -100,6 +109,27 @@ public abstract class AlignmentViewport implements AlignViewportI,
    * alignment displayed in the viewport. Please use get/setter
    */
   protected AlignmentI alignment;
+  
+  /*
+   * probably unused indicator that view is of a dataset rather than an
+   * alignment
+   */
+
+  protected boolean ignoreBelowBackGroundFrequencyCalculation = false;
+
+  protected boolean infoLetterHeight = false;
+
+  protected AlignmentAnnotation occupancy;
+  
+  /**
+   * results of alignment consensus analysis for visible portion of view
+   */
+  protected ProfilesI consensusProfiles;
+
+  /**
+   * HMM profile for the alignment
+   */
+  protected ProfilesI hmmProfiles;
 
   public AlignmentViewport(AlignmentI al)
   {
@@ -568,8 +598,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
     viewStyle.setSeqNameItalics(default1);
   }
 
-
-
   @Override
   public AlignmentI getAlignment()
   {
@@ -590,6 +618,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   protected boolean isDataset = false;
 
+  
   public void setDataset(boolean b)
   {
     isDataset = b;
@@ -604,14 +633,34 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
   protected ColumnSelection colSel = new ColumnSelection();
 
-  public boolean autoCalculateConsensus = true;
+  protected boolean autoCalculateConsensusAndConservation = true;
+
+  public boolean getAutoCalculateConsensusAndConservation()
+  { // BH 2019.07.24
+    return autoCalculateConsensusAndConservation;
+  }
+
+  public void setAutoCalculateConsensusAndConservation(boolean b)
+  {
+    autoCalculateConsensusAndConservation = b;
+  }
 
   protected boolean autoCalculateStrucConsensus = true;
 
+  public boolean getAutoCalculateStrucConsensus()
+  { // BH 2019.07.24
+    return autoCalculateStrucConsensus;
+  }
+
+  public void setAutoCalculateStrucConsensus(boolean b)
+  {
+    autoCalculateStrucConsensus = b;
+  }
   protected boolean ignoreGapsInConsensusCalculation = false;
 
   protected ResidueShaderI residueShading = new ResidueShader();
 
+  
   @Override
   public void setGlobalColourScheme(ColourSchemeI cs)
   {
@@ -643,6 +692,11 @@ public abstract class AlignmentViewport implements AlignViewportI,
       {
         residueShading.setConservation(hconservation);
       }
+      /*
+       * reset conservation flag in case just set to false if
+       * Conservation was null (calculation still in progress)
+       */
+      residueShading.setConservationApplied(getConservationSelected());
       residueShading.alignmentChanged(alignment, hiddenRepSequences);
     }
 
@@ -658,11 +712,12 @@ public abstract class AlignmentViewport implements AlignViewportI,
          * retain any colour thresholds per group while
          * changing choice of colour scheme (JAL-2386)
          */
-        sg.setColourScheme(cs);
+        sg.setColourScheme(
+                cs == null ? null : cs.getInstance(this, sg));
         if (cs != null)
         {
-          sg.getGroupColourScheme()
-                  .alignmentChanged(sg, hiddenRepSequences);
+          sg.getGroupColourScheme().alignmentChanged(sg,
+                  hiddenRepSequences);
         }
       }
     }
@@ -671,8 +726,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public ColourSchemeI getGlobalColourScheme()
   {
-    return residueShading == null ? null : residueShading
-            .getColourScheme();
+    return residueShading == null ? null : residueShading.getColourScheme();
   }
 
   @Override
@@ -681,6 +735,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return residueShading;
   }
 
+  
   protected AlignmentAnnotation consensus;
 
   protected AlignmentAnnotation complementConsensus;
@@ -705,16 +760,17 @@ public abstract class AlignmentViewport implements AlignViewportI,
   /**
    * results of cDNA complement consensus visible portion of view
    */
-  protected Hashtable[] hcomplementConsensus = null;
+  protected Hashtable<String, Object>[] hcomplementConsensus = null;
 
   /**
    * results of secondary structure base pair consensus for visible portion of
    * view
    */
-  protected Hashtable[] hStrucConsensus = null;
+  protected Hashtable<String, Object>[] hStrucConsensus = null;
 
   protected Conservation hconservation = null;
 
+  
   @Override
   public void setConservation(Conservation cons)
   {
@@ -740,7 +796,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public void setComplementConsensusHash(Hashtable[] hconsensus)
+  public void setComplementConsensusHash(
+          Hashtable<String, Object>[] hconsensus)
   {
     this.hcomplementConsensus = hconsensus;
   }
@@ -752,19 +809,32 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public Hashtable[] getComplementConsensusHash()
+  public void setHmmProfiles(ProfilesI info)
+  {
+    hmmProfiles = info;
+  }
+
+  @Override
+  public ProfilesI getHmmProfiles()
+  {
+    return hmmProfiles;
+  }
+
+  @Override
+  public Hashtable<String, Object>[] getComplementConsensusHash()
   {
     return hcomplementConsensus;
   }
 
   @Override
-  public Hashtable[] getRnaStructureConsensusHash()
+  public Hashtable<String, Object>[] getRnaStructureConsensusHash()
   {
     return hStrucConsensus;
   }
 
   @Override
-  public void setRnaStructureConsensusHash(Hashtable[] hStrucConsensus)
+  public void setRnaStructureConsensusHash(
+          Hashtable<String, Object>[] hStrucConsensus)
   {
     this.hStrucConsensus = hStrucConsensus;
 
@@ -806,7 +876,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return strucConsensus;
   }
 
-  protected AlignCalcManagerI calculator = new AlignCalcManager();
+  protected AlignCalcManagerI2 calculator = new AlignCalcManager2();
 
   /**
    * trigger update of conservation annotation
@@ -816,15 +886,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
     // see note in mantis : issue number 8585
     if (alignment.isNucleotide()
             || (conservation == null && quality == null)
-            || !autoCalculateConsensus)
+            || !autoCalculateConsensusAndConservation)
     {
       return;
     }
-    if (calculator
-            .getRegisteredWorkersOfClass(jalview.workers.ConservationThread.class) == null)
+    if (calculator.getWorkersOfClass(
+            jalview.workers.ConservationThread.class).isEmpty())
     {
-      calculator.registerWorker(new jalview.workers.ConservationThread(
-              this, ap));
+      calculator.registerWorker(
+              new jalview.workers.ConservationThread(this, ap));
     }
   }
 
@@ -834,11 +904,11 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void updateConsensus(final AlignmentViewPanel ap)
   {
     // see note in mantis : issue number 8585
-    if (consensus == null || !autoCalculateConsensus)
+    if (consensus == null || !autoCalculateConsensusAndConservation)
     {
       return;
     }
-    if (calculator.getRegisteredWorkersOfClass(ConsensusThread.class) == null)
+    if (calculator.getWorkersOfClass(ConsensusThread.class).isEmpty())
     {
       calculator.registerWorker(new ConsensusThread(this, ap));
     }
@@ -869,16 +939,22 @@ public abstract class AlignmentViewport implements AlignViewportI,
       }
       if (doConsensus)
       {
-        if (calculator
-                .getRegisteredWorkersOfClass(ComplementConsensusThread.class) == null)
+        if (calculator.getWorkersOfClass(ComplementConsensusThread.class).isEmpty())
         {
-          calculator
-                  .registerWorker(new ComplementConsensusThread(this, ap));
+          calculator.registerWorker(new ComplementConsensusThread(this, ap));
         }
       }
     }
   }
 
+  @Override
+  public void initInformationWorker(final AlignmentViewPanel ap)
+  {
+    if (calculator.getWorkersOfClass(InformationThread.class).isEmpty())
+    {
+      calculator.registerWorker(new InformationThread(this, ap));
+    }
+  }
   // --------START Structure Conservation
   public void updateStrucConsensus(final AlignmentViewPanel ap)
   {
@@ -894,7 +970,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       return;
     }
-    if (calculator.getRegisteredWorkersOfClass(StrucConsensusThread.class) == null)
+    if (calculator.getWorkersOfClass(StrucConsensusThread.class).isEmpty())
     {
       calculator.registerWorker(new StrucConsensusThread(this, ap));
     }
@@ -913,7 +989,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       return false;
     }
-    if (calculator.workingInvolvedWith(alignmentAnnotation))
+    if (calculator.isWorkingWithAnnotation(alignmentAnnotation))
     {
       // System.err.println("grey out ("+alignmentAnnotation.label+")");
       return true;
@@ -941,14 +1017,20 @@ public abstract class AlignmentViewport implements AlignViewportI,
     strucConsensus = null;
     conservation = null;
     quality = null;
+    consensusProfiles = null;
     groupConsensus = null;
     groupConservation = null;
     hconsensus = null;
+    hconservation = null;
     hcomplementConsensus = null;
-    // colour scheme may hold reference to consensus
-    residueShading = null;
-    // TODO remove listeners from changeSupport?
+    gapcounts = null;
+    calculator.shutdown();
+    calculator = null;
+    residueShading = null; // may hold a reference to Consensus
     changeSupport = null;
+    ranges = null;
+    currentTree = null;
+    selectionGroup = null;
     setAlignment(null);
   }
 
@@ -961,7 +1043,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public AlignCalcManagerI getCalcManager()
+  public AlignCalcManagerI2 getCalcManager()
   {
     return calculator;
   }
@@ -992,6 +1074,21 @@ public abstract class AlignmentViewport implements AlignViewportI,
   protected boolean showConsensusHistogram = true;
 
   /**
+   * should hmm profile be rendered by default
+   */
+  protected boolean hmmShowSequenceLogo = false;
+
+  /**
+   * should hmm profile be rendered normalised to row height
+   */
+  protected boolean hmmNormaliseSequenceLogo = false;
+
+  /**
+   * should information histograms be rendered by default
+   */
+  protected boolean hmmShowHistogram = true;
+
+  /**
    * @return the showConsensusProfile
    */
   @Override
@@ -1001,6 +1098,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * @return the showInformationProfile
+   */
+  @Override
+  public boolean isShowHMMSequenceLogo()
+  {
+    return hmmShowSequenceLogo;
+  }
+
+  /**
    * @param showSequenceLogo
    *          the new value
    */
@@ -1011,13 +1117,30 @@ public abstract class AlignmentViewport implements AlignViewportI,
       // TODO: decouple settings setting from calculation when refactoring
       // annotation update method from alignframe to viewport
       this.showSequenceLogo = showSequenceLogo;
-      calculator.updateAnnotationFor(ConsensusThread.class);
-      calculator.updateAnnotationFor(ComplementConsensusThread.class);
-      calculator.updateAnnotationFor(StrucConsensusThread.class);
+      for (AlignCalcWorkerI worker : calculator.getWorkers())
+      {
+        if (worker.getClass().equals(ConsensusThread.class) ||
+                worker.getClass().equals(ComplementConsensusThread.class) ||
+                worker.getClass().equals(StrucConsensusThread.class))
+        {
+          worker.updateAnnotation();
+        }
+      }
     }
     this.showSequenceLogo = showSequenceLogo;
   }
 
+  public void setShowHMMSequenceLogo(boolean showHMMSequenceLogo)
+  {
+    if (showHMMSequenceLogo != this.hmmShowSequenceLogo)
+    {
+      this.hmmShowSequenceLogo = showHMMSequenceLogo;
+      // TODO: updateAnnotation if description (tooltip) will show
+      // profile in place of information content?
+      // calculator.updateAnnotationFor(InformationThread.class);
+    }
+    this.hmmShowSequenceLogo = showHMMSequenceLogo;
+  }
   /**
    * @param showConsensusHistogram
    *          the showConsensusHistogram to set
@@ -1028,6 +1151,14 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * @param showInformationHistogram
+   */
+  public void setShowInformationHistogram(boolean showInformationHistogram)
+  {
+    this.hmmShowHistogram = showInformationHistogram;
+  }
+
+  /**
    * @return the showGroupConservation
    */
   public boolean isShowGroupConservation()
@@ -1073,6 +1204,17 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   /**
+   * 
+   * @return flag to indicate if the information content histogram should be
+   *         rendered by default
+   */
+  @Override
+  public boolean isShowInformationHistogram()
+  {
+    return this.hmmShowHistogram;
+  }
+
+  /**
    * when set, updateAlignment will always ensure sequences are of equal length
    */
   private boolean padGaps = false;
@@ -1183,8 +1325,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
   {
     if (sequenceSetID != null)
     {
-      System.err
-              .println("Warning - overwriting a sequenceSetId for a viewport!");
+      System.err.println(
+              "Warning - overwriting a sequenceSetId for a viewport!");
     }
     sequenceSetID = new String(newid);
   }
@@ -1228,7 +1370,16 @@ public abstract class AlignmentViewport implements AlignViewportI,
                 ignoreGapsInConsensusCalculation);
       }
     }
+  }
+
+  public void setIgnoreBelowBackground(boolean b, AlignmentViewPanel ap)
+  {
+    ignoreBelowBackGroundFrequencyCalculation = b;
+  }
 
+  public void setInfoLetterHeight(boolean b, AlignmentViewPanel ap)
+  {
+    infoLetterHeight = b;
   }
 
   private long sgrouphash = -1, colselhash = -1;
@@ -1261,21 +1412,22 @@ public abstract class AlignmentViewport implements AlignViewportI,
    * checks current colsel against record of last hash value, and optionally
    * updates record.
    * 
-   * @param b
+   * @param updateHash
    *          update the record of last hash value
    * @return true if colsel changed since last call (when b is true)
    */
-  public boolean isColSelChanged(boolean b)
+  public boolean isColSelChanged(boolean updateHash)
   {
     int hc = (colSel == null || colSel.isEmpty()) ? -1 : colSel.hashCode();
     if (hc != -1 && hc != colselhash)
     {
-      if (b)
+      if (updateHash)
       {
         colselhash = hc;
       }
       return true;
     }
+    notifySequence();
     return false;
   }
 
@@ -1285,6 +1437,17 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return ignoreGapsInConsensusCalculation;
   }
 
+  @Override
+  public boolean isIgnoreBelowBackground()
+  {
+    return ignoreBelowBackGroundFrequencyCalculation;
+  }
+
+  @Override
+  public boolean isInfoLetterHeight()
+  {
+    return infoLetterHeight;
+  }
   // property change stuff
   // JBPNote Prolly only need this in the applet version.
   private PropertyChangeSupport changeSupport = new PropertyChangeSupport(
@@ -1330,24 +1493,12 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void removePropertyChangeListener(
           java.beans.PropertyChangeListener listener)
   {
-    changeSupport.removePropertyChangeListener(listener);
+    if (changeSupport != null)
+    {
+      changeSupport.removePropertyChangeListener(listener);
+    }
   }
 
-  /**
-   * Property change listener for changes in alignment
-   * 
-   * @param prop
-   *          DOCUMENT ME!
-   * @param oldvalue
-   *          DOCUMENT ME!
-   * @param newvalue
-   *          DOCUMENT ME!
-   */
-  public void firePropertyChange(String prop, Object oldvalue,
-          Object newvalue)
-  {
-    changeSupport.firePropertyChange(prop, oldvalue, newvalue);
-  }
 
   // common hide/show column stuff
 
@@ -1401,8 +1552,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
         selectionGroup = new SequenceGroup();
         selectionGroup.setEndRes(alignment.getWidth() - 1);
       }
-      List<SequenceI> tmp = alignment.getHiddenSequences().showAll(
-              hiddenRepSequences);
+      List<SequenceI> tmp = alignment.getHiddenSequences()
+              .showAll(hiddenRepSequences);
       for (SequenceI seq : tmp)
       {
         selectionGroup.addSequence(seq, false);
@@ -1413,9 +1564,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
       ranges.setStartEndSeq(startSeq, endSeq + tmp.size());
 
-      firePropertyChange("alignment", null, alignment.getSequences());
       // used to set hasHiddenRows/hiddenRepSequences here, after the property
       // changed event
+      notifySequence();
       sendSelection();
     }
   }
@@ -1425,8 +1576,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
     int startSeq = ranges.getStartSeq();
     int endSeq = ranges.getEndSeq();
 
-    List<SequenceI> tmp = alignment.getHiddenSequences().showSequence(
-            index, hiddenRepSequences);
+    List<SequenceI> tmp = alignment.getHiddenSequences().showSequence(index,
+            hiddenRepSequences);
     if (tmp.size() > 0)
     {
       if (selectionGroup == null)
@@ -1443,7 +1594,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
       ranges.setStartEndSeq(startSeq, endSeq + tmp.size());
 
-      firePropertyChange("alignment", null, alignment.getSequences());
+      notifyAlignment();
       sendSelection();
     }
   }
@@ -1477,7 +1628,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
         setSequenceAnnotationsVisible(seq[i], false);
       }
       ranges.setStartSeq(startSeq);
-      firePropertyChange("alignment", null, alignment.getSequences());
+      notifyAlignment();
     }
   }
 
@@ -1506,8 +1657,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
     }
 
     int gsize = selectionGroup.getSize();
-    SequenceI[] hseqs = selectionGroup.getSequences().toArray(
-            new SequenceI[gsize]);
+    SequenceI[] hseqs = selectionGroup.getSequences()
+            .toArray(new SequenceI[gsize]);
 
     hideSequence(hseqs);
     setSelectionGroup(null);
@@ -1597,8 +1748,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   public boolean isHiddenRepSequence(SequenceI seq)
   {
-    return (hiddenRepSequences != null && hiddenRepSequences
-            .containsKey(seq));
+    return (hiddenRepSequences != null
+            && hiddenRepSequences.containsKey(seq));
   }
 
   /**
@@ -1616,14 +1767,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
   @Override
   public int adjustForHiddenSeqs(int alignmentIndex)
   {
-    return alignment.getHiddenSequences().adjustForHiddenSeqs(
-            alignmentIndex);
+    return alignment.getHiddenSequences()
+            .adjustForHiddenSeqs(alignmentIndex);
   }
 
   @Override
   public void invertColumnSelection()
   {
     colSel.invertColumnSelection(0, alignment.getWidth(), alignment);
+    isColSelChanged(true);
   }
 
   @Override
@@ -1669,13 +1821,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
   }
 
   @Override
-  public CigarArray getViewAsCigars(boolean selectedRegionOnly)
-  {
-    return new CigarArray(alignment, alignment.getHiddenColumns(),
-            (selectedRegionOnly ? selectionGroup : null));
-  }
-
-  @Override
   public jalview.datamodel.AlignmentView getAlignmentView(
           boolean selectedOnly)
   {
@@ -1687,10 +1832,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
           boolean selectedOnly, boolean markGroups)
   {
     return new AlignmentView(alignment, alignment.getHiddenColumns(),
-            selectionGroup, alignment.getHiddenColumns() != null
+            selectionGroup,
+            alignment.getHiddenColumns() != null
                     && alignment.getHiddenColumns().hasHiddenColumns(),
-            selectedOnly,
-            markGroups);
+            selectedOnly, markGroups);
   }
 
   @Override
@@ -1736,8 +1881,12 @@ public abstract class AlignmentViewport implements AlignViewportI,
     if (alignment.getHiddenColumns() != null
             && alignment.getHiddenColumns().hasHiddenColumns())
     {
-      selection = alignment.getHiddenColumns().getVisibleSequenceStrings(
-              start, end, seqs);
+      for (i = 0; i < iSize; i++)
+      {
+        Iterator<int[]> blocks = alignment.getHiddenColumns()
+                .getVisContigsIterator(start, end + 1, false);
+        selection[i] = seqs[i].getSequenceStringFromIterator(blocks);
+      }
     }
     else
     {
@@ -1764,10 +1913,10 @@ public abstract class AlignmentViewport implements AlignViewportI,
       {
         if (start == 0)
         {
-          start = hidden.adjustForHiddenColumns(start);
+          start = hidden.visibleToAbsoluteColumn(start);
         }
 
-        end = hidden.getHiddenBoundaryRight(start);
+        end = hidden.getNextHiddenBoundary(false, start);
         if (start == end)
         {
           end = max;
@@ -1782,12 +1931,12 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
       if (hidden != null && hidden.hasHiddenColumns())
       {
-        start = hidden.adjustForHiddenColumns(end);
-        start = hidden.getHiddenBoundaryLeft(start) + 1;
+        start = hidden.visibleToAbsoluteColumn(end);
+        start = hidden.getNextHiddenBoundary(true, start) + 1;
       }
     } while (end < max);
 
-    int[][] startEnd = new int[regions.size()][2];
+    // int[][] startEnd = new int[regions.size()][2];
 
     return regions;
   }
@@ -1805,13 +1954,13 @@ public abstract class AlignmentViewport implements AlignViewportI,
         AlignmentAnnotation clone = new AlignmentAnnotation(annot);
         if (selectedOnly && selectionGroup != null)
         {
-          alignment.getHiddenColumns().makeVisibleAnnotation(
-                  selectionGroup.getStartRes(),
-                  selectionGroup.getEndRes(), clone);
+          clone.makeVisibleAnnotation(
+                  selectionGroup.getStartRes(), selectionGroup.getEndRes(),
+                  alignment.getHiddenColumns());
         }
         else
         {
-          alignment.getHiddenColumns().makeVisibleAnnotation(clone);
+          clone.makeVisibleAnnotation(alignment.getHiddenColumns());
         }
         ala.add(clone);
       }
@@ -1844,11 +1993,11 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       alignment.padGaps();
     }
-    if (autoCalculateConsensus)
+    if (autoCalculateConsensusAndConservation)
     {
       updateConsensus(ap);
     }
-    if (hconsensus != null && autoCalculateConsensus)
+    if (hconsensus != null && autoCalculateConsensusAndConservation)
     {
       updateConservation(ap);
     }
@@ -1878,7 +2027,6 @@ public abstract class AlignmentViewport implements AlignViewportI,
 
     updateAllColourSchemes();
     calculator.restartWorkers();
-    // alignment.adjustSequenceAnnotations();
   }
 
   /**
@@ -1996,8 +2144,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
     {
       gapcounts = new AlignmentAnnotation("Occupancy",
               MessageManager.getString("label.occupancy_descr"),
-              new Annotation[1], 0f,
-              alignment.getHeight(), AlignmentAnnotation.BAR_GRAPH);
+              new Annotation[1], 0f, alignment.getHeight(),
+              AlignmentAnnotation.BAR_GRAPH);
       gapcounts.hasText = true;
       gapcounts.autoCalculated = true;
       gapcounts.scaleColLabel = true;
@@ -2015,8 +2163,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
       {
         conservation = new AlignmentAnnotation("Conservation",
                 MessageManager.formatMessage("label.conservation_descr",
-                        getConsPercGaps()), new Annotation[1],
-                0f, 11f, AlignmentAnnotation.BAR_GRAPH);
+                        getConsPercGaps()),
+                new Annotation[1], 0f, 11f, AlignmentAnnotation.BAR_GRAPH);
         conservation.hasText = true;
         conservation.autoCalculated = true;
         alignment.addAnnotation(conservation);
@@ -2137,12 +2285,15 @@ public abstract class AlignmentViewport implements AlignViewportI,
     boolean showprf = isShowSequenceLogo();
     boolean showConsHist = isShowConsensusHistogram();
     boolean normLogo = isNormaliseSequenceLogo();
+    boolean showHMMPrf = isShowHMMSequenceLogo();
+    boolean showInfoHist = isShowInformationHistogram();
+    boolean normHMMLogo = isNormaliseHMMSequenceLogo();
 
     /**
      * TODO reorder the annotation rows according to group/sequence ordering on
      * alignment
      */
-    boolean sortg = true;
+    // boolean sortg = true;
 
     // remove old automatic annotation
     // add any new annotation
@@ -2174,6 +2325,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
           sg.setshowSequenceLogo(showprf);
           sg.setShowConsensusHistogram(showConsHist);
           sg.setNormaliseSequenceLogo(normLogo);
+          sg.setShowHMMSequenceLogo(showHMMPrf);
+          sg.setShowInformationHistogram(showInfoHist);
+          sg.setNormaliseHMMSequenceLogo(normHMMLogo);
         }
         if (conv)
         {
@@ -2252,7 +2406,7 @@ public abstract class AlignmentViewport implements AlignViewportI,
   public void clearSequenceColours()
   {
     sequenceColours.clear();
-  };
+  }
 
   @Override
   public AlignViewportI getCodingComplement()
@@ -2496,8 +2650,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
     viewStyle = new ViewStyle(settingsForView);
     if (residueShading != null)
     {
-      residueShading.setConservationApplied(settingsForView
-              .isConservationColourSelected());
+      residueShading.setConservationApplied(
+              settingsForView.isConservationColourSelected());
     }
   }
 
@@ -2665,7 +2819,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
     return sortAnnotationsBy;
   }
 
-  public void setSortAnnotationsBy(SequenceAnnotationOrder sortAnnotationsBy)
+  public void setSortAnnotationsBy(
+          SequenceAnnotationOrder sortAnnotationsBy)
   {
     this.sortAnnotationsBy = sortAnnotationsBy;
   }
@@ -2704,6 +2859,30 @@ public abstract class AlignmentViewport implements AlignViewportI,
     viewStyle.setProteinFontAsCdna(b);
   }
 
+  @Override
+  public void setShowComplementFeatures(boolean b)
+  {
+    viewStyle.setShowComplementFeatures(b);
+  }
+
+  @Override
+  public boolean isShowComplementFeatures()
+  {
+    return viewStyle.isShowComplementFeatures();
+  }
+
+  @Override
+  public void setShowComplementFeaturesOnTop(boolean b)
+  {
+    viewStyle.setShowComplementFeaturesOnTop(b);
+  }
+
+  @Override
+  public boolean isShowComplementFeaturesOnTop()
+  {
+    return viewStyle.isShowComplementFeaturesOnTop();
+  }
+
   /**
    * @return true if view should scroll to show the highlighted region of a
    *         sequence
@@ -2743,8 +2922,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
       return 0;
     }
     boolean iAmProtein = !getAlignment().isNucleotide();
-    AlignmentI proteinAlignment = iAmProtein ? getAlignment() : complement
-            .getAlignment();
+    AlignmentI proteinAlignment = iAmProtein ? getAlignment()
+            : complement.getAlignment();
     if (proteinAlignment == null)
     {
       return 0;
@@ -2775,7 +2954,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
      */
     int lastSeq = alignment.getHeight() - 1;
     List<AlignedCodonFrame> seqMappings = null;
-    for (int seqNo = ranges.getStartSeq(); seqNo < lastSeq; seqNo++, seqOffset++)
+    for (int seqNo = ranges
+            .getStartSeq(); seqNo <= lastSeq; seqNo++, seqOffset++)
     {
       sequence = getAlignment().getSequenceAt(seqNo);
       if (hiddenSequences != null && hiddenSequences.isHidden(sequence))
@@ -2786,9 +2966,9 @@ public abstract class AlignmentViewport implements AlignViewportI,
       {
         continue;
       }
-      seqMappings = MappingUtils
-              .findMappingsForSequenceAndOthers(sequence, mappings,
-                      getCodingComplement().getAlignment().getSequences());
+      seqMappings = MappingUtils.findMappingsForSequenceAndOthers(sequence,
+              mappings,
+              getCodingComplement().getAlignment().getSequences());
       if (!seqMappings.isEmpty())
       {
         break;
@@ -2871,6 +3051,8 @@ public abstract class AlignmentViewport implements AlignViewportI,
    */
   private SearchResultsI searchResults = null;
 
+  protected TreeModel currentTree = null;
+
   @Override
   public boolean hasSearchResults()
   {
@@ -2923,10 +3105,224 @@ public abstract class AlignmentViewport implements AlignViewportI,
         }
       }
     }
-  
+
     SequenceI sq = new Sequence("Consensus", seqs.toString());
     sq.setDescription("Percentage Identity Consensus "
             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
     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;
+  }
+
+  @Override
+  public AlignmentExportData getAlignExportData(AlignExportSettingsI options)
+  {
+    AlignmentI alignmentToExport = null;
+    String[] omitHidden = null;
+    alignmentToExport = null;
+
+    if (hasHiddenColumns() && !options.isExportHiddenColumns())
+    {
+      omitHidden = getViewAsString(false,
+              options.isExportHiddenSequences());
+    }
+
+    int[] alignmentStartEnd = new int[2];
+    if (hasHiddenRows() && options.isExportHiddenSequences())
+    {
+      alignmentToExport = getAlignment().getHiddenSequences()
+              .getFullAlignment();
+    }
+    else
+    {
+      alignmentToExport = getAlignment();
+    }
+    alignmentStartEnd = getAlignment().getHiddenColumns()
+            .getVisibleStartAndEndIndex(alignmentToExport.getWidth());
+    AlignmentExportData ed = new AlignmentExportData(alignmentToExport,
+            omitHidden, alignmentStartEnd);
+    return ed;
+  }
+  
+  @Override
+  public boolean isNormaliseSequenceLogo()
+  {
+    return normaliseSequenceLogo;
+  }
+
+  public void setNormaliseSequenceLogo(boolean state)
+  {
+    normaliseSequenceLogo = state;
+  }
+
+  @Override
+  public boolean isNormaliseHMMSequenceLogo()
+  {
+    return hmmNormaliseSequenceLogo;
+  }
+
+  public void setNormaliseHMMSequenceLogo(boolean state)
+  {
+    hmmNormaliseSequenceLogo = state;
+  }
+  /**
+   * flag set to indicate if structure views might be out of sync with sequences
+   * in the alignment
+   */
+
+  private boolean needToUpdateStructureViews = false;
+
+  @Override
+  public boolean isUpdateStructures()
+  {
+    return needToUpdateStructureViews;
+  }
+
+  @Override
+  public void setUpdateStructures(boolean update)
+  {
+    needToUpdateStructureViews = update;
+  }
+
+  @Override
+  public boolean needToUpdateStructureViews()
+  {
+    boolean update = needToUpdateStructureViews;
+    needToUpdateStructureViews = false;
+    return update;
+  }
+
+  @Override
+  public void addSequenceGroup(SequenceGroup sequenceGroup)
+  {
+    alignment.addGroup(sequenceGroup);
+
+    Color col = sequenceGroup.idColour;
+    if (col != null)
+    {
+      col = col.brighter();
+
+      for (SequenceI sq : sequenceGroup.getSequences())
+      {
+        setSequenceColour(sq, col);
+      }
+    }
+
+    if (codingComplement != null)
+    {
+      SequenceGroup mappedGroup = MappingUtils
+              .mapSequenceGroup(sequenceGroup, this, codingComplement);
+      if (mappedGroup.getSequences().size() > 0)
+      {
+        codingComplement.getAlignment().addGroup(mappedGroup);
+
+        if (col != null)
+        {
+          for (SequenceI seq : mappedGroup.getSequences())
+          {
+            codingComplement.setSequenceColour(seq, col);
+          }
+        }
+      }
+      // propagate the structure view update flag according to our own setting
+      codingComplement.setUpdateStructures(needToUpdateStructureViews);
+    }
+  }
+
+  @Override
+  public Iterator<int[]> getViewAsVisibleContigs(boolean selectedRegionOnly)
+  {
+    int start = 0;
+    int end = 0;
+    if (selectedRegionOnly && selectionGroup != null)
+    {
+      start = selectionGroup.getStartRes();
+      end = selectionGroup.getEndRes() + 1;
+    }
+    else
+    {
+      end = alignment.getWidth();
+    }
+    return (alignment.getHiddenColumns().getVisContigsIterator(start, end,
+            false));
+  }
+  /**
+   * Filters out sequences with an eValue higher than the specified value. The
+   * filtered sequences are hidden or deleted. Sequences with no eValues are also
+   * filtered out.
+   * 
+   * @param eValue
+   * @param delete
+   */
+  public void filterByEvalue(double eValue)
+  {
+    for (SequenceI seq : alignment.getSequencesArray())
+    {
+      if ((seq.getAnnotation("Search Scores") == null
+              || seq.getAnnotation("Search Scores")[0].getEValue() > eValue)
+              && seq.getHMM() == null)
+      {
+        hideSequence(new SequenceI[] { seq });
+      }
+    }
+  }
+
+  /**
+   * Filters out sequences with an score lower than the specified value. The
+   * filtered sequences are hidden or deleted.
+   * 
+   * @param score
+   * @param delete
+   */
+  public void filterByScore(double score)
+  {
+    for (SequenceI seq : alignment.getSequencesArray())
+    {
+      if ((seq.getAnnotation("Search Scores") == null
+              || seq.getAnnotation("Search Scores")[0]
+                      .getBitScore() < score)
+              && seq.getHMM() == null)
+      {
+        hideSequence(new SequenceI[] { seq });
+      }
+    }
+  }  
+
+  /**
+   * Notify TreePanel and AlignmentPanel of some sort of alignment change.
+   */
+  public void notifyAlignment()
+  {
+    changeSupport.firePropertyChange(PROPERTY_ALIGNMENT, null, alignment.getSequences());
+  }
+  
+  /**
+   * Notify AlignmentPanel of a sequence column selection or visibility changes.
+   */
+  public void notifySequence()
+  {
+    changeSupport.firePropertyChange(PROPERTY_SEQUENCE, null, null);
+  }
 }