Merge commit
[jalview.git] / src / jalview / viewmodel / AlignmentViewport.java
index 08b31fa..2cfc1e6 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2)
- * Copyright (C) 2014 The Jalview Authors
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
  * 
  * This file is part of Jalview.
  * 
@@ -25,10 +25,14 @@ import jalview.api.AlignCalcManagerI;
 import jalview.api.AlignViewportI;
 import jalview.api.AlignmentViewPanel;
 import jalview.api.FeaturesDisplayedI;
+import jalview.api.ViewStyleI;
+import jalview.commands.CommandI;
+import jalview.datamodel.AlignedCodonFrame;
 import jalview.datamodel.AlignmentAnnotation;
 import jalview.datamodel.AlignmentI;
 import jalview.datamodel.AlignmentView;
 import jalview.datamodel.Annotation;
+import jalview.datamodel.CigarArray;
 import jalview.datamodel.ColumnSelection;
 import jalview.datamodel.Sequence;
 import jalview.datamodel.SequenceCollectionI;
@@ -38,17 +42,25 @@ import jalview.schemes.Blosum62ColourScheme;
 import jalview.schemes.ColourSchemeI;
 import jalview.schemes.PIDColourScheme;
 import jalview.schemes.ResidueProperties;
+import jalview.structure.CommandListener;
+import jalview.structure.StructureSelectionManager;
+import jalview.structure.VamsasSource;
+import jalview.viewmodel.styles.ViewStyle;
 import jalview.workers.AlignCalcManager;
+import jalview.workers.ComplementConsensusThread;
 import jalview.workers.ConsensusThread;
 import jalview.workers.StrucConsensusThread;
 
 import java.awt.Color;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.BitSet;
+import java.util.Deque;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
+import java.util.Set;
 
 /**
  * base class holding visualization and analysis attributes and common logic for
@@ -57,152 +69,496 @@ import java.util.Vector;
  * @author jimp
  * 
  */
-public abstract class AlignmentViewport implements AlignViewportI
+public abstract class AlignmentViewport implements AlignViewportI,
+        ViewStyleI, CommandListener, VamsasSource
 {
+  protected ViewStyleI viewStyle = new ViewStyle();
+
   /**
-   * alignment displayed in the viewport. Please use get/setter
+   * A viewport that hosts the cDna view of this (protein), or vice versa (if
+   * set).
    */
-  protected AlignmentI alignment;
+  AlignViewportI codingComplement = null;
 
-  protected String sequenceSetID;
+  FeaturesDisplayedI featuresDisplayed = null;
+
+  protected Deque<CommandI> historyList = new ArrayDeque<CommandI>();
+
+  protected Deque<CommandI> redoList = new ArrayDeque<CommandI>();
 
   /**
-   * probably unused indicator that view is of a dataset rather than an
-   * alignment
+   * @param name
+   * @see jalview.api.ViewStyleI#setFontName(java.lang.String)
    */
-  protected boolean isDataset = false;
+  public void setFontName(String name)
+  {
+    viewStyle.setFontName(name);
+  }
 
-  private Map<SequenceI, SequenceCollectionI> hiddenRepSequences;
+  /**
+   * @param style
+   * @see jalview.api.ViewStyleI#setFontStyle(int)
+   */
+  public void setFontStyle(int style)
+  {
+    viewStyle.setFontStyle(style);
+  }
 
-  protected ColumnSelection colSel = new ColumnSelection();
+  /**
+   * @param size
+   * @see jalview.api.ViewStyleI#setFontSize(int)
+   */
+  public void setFontSize(int size)
+  {
+    viewStyle.setFontSize(size);
+  }
 
-  public boolean autoCalculateConsensus = true;
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getFontStyle()
+   */
+  public int getFontStyle()
+  {
+    return viewStyle.getFontStyle();
+  }
 
-  protected boolean autoCalculateStrucConsensus = true;
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getFontName()
+   */
+  public String getFontName()
+  {
+    return viewStyle.getFontName();
+  }
 
-  protected boolean ignoreGapsInConsensusCalculation = false;
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getFontSize()
+   */
+  public int getFontSize()
+  {
+    return viewStyle.getFontSize();
+  }
 
-  protected ColourSchemeI globalColourScheme = null;
+  /**
+   * @param upperCasebold
+   * @see jalview.api.ViewStyleI#setUpperCasebold(boolean)
+   */
+  public void setUpperCasebold(boolean upperCasebold)
+  {
+    viewStyle.setUpperCasebold(upperCasebold);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isUpperCasebold()
+   */
+  public boolean isUpperCasebold()
+  {
+    return viewStyle.isUpperCasebold();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isSeqNameItalics()
+   */
+  public boolean isSeqNameItalics()
+  {
+    return viewStyle.isSeqNameItalics();
+  }
 
   /**
-   * gui state - changes to colour scheme propagated to all groups
+   * @param colourByReferenceSeq
+   * @see jalview.api.ViewStyleI#setColourByReferenceSeq(boolean)
    */
-  private boolean colourAppliesToAllGroups;
+  public void setColourByReferenceSeq(boolean colourByReferenceSeq)
+  {
+    viewStyle.setColourByReferenceSeq(colourByReferenceSeq);
+  }
 
   /**
-   * @param value
-   *          indicating if subsequent colourscheme changes will be propagated
-   *          to all groups
+   * @param b
+   * @see jalview.api.ViewStyleI#setColourAppliesToAllGroups(boolean)
    */
   public void setColourAppliesToAllGroups(boolean b)
   {
-    colourAppliesToAllGroups = b;
+    viewStyle.setColourAppliesToAllGroups(b);
   }
 
   /**
-   * 
-   * 
-   * @return flag indicating if colourchanges propagated to all groups
+   * @return
+   * @see jalview.api.ViewStyleI#getColourAppliesToAllGroups()
    */
   public boolean getColourAppliesToAllGroups()
   {
-    return colourAppliesToAllGroups;
+    return viewStyle.getColourAppliesToAllGroups();
   }
 
-  boolean abovePIDThreshold = false;
-
   /**
-   * GUI state
-   * 
-   * @return true if percent identity threshold is applied to shading
+   * @return
+   * @see jalview.api.ViewStyleI#getAbovePIDThreshold()
    */
   public boolean getAbovePIDThreshold()
   {
-    return abovePIDThreshold;
+    return viewStyle.getAbovePIDThreshold();
+  }
+
+  /**
+   * @param inc
+   * @see jalview.api.ViewStyleI#setIncrement(int)
+   */
+  public void setIncrement(int inc)
+  {
+    viewStyle.setIncrement(inc);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getIncrement()
+   */
+  public int getIncrement()
+  {
+    return viewStyle.getIncrement();
   }
 
   /**
-   * GUI state
-   * 
-   * 
    * @param b
-   *          indicate if percent identity threshold is applied to shading
+   * @see jalview.api.ViewStyleI#setConservationSelected(boolean)
    */
-  public void setAbovePIDThreshold(boolean b)
+  public void setConservationSelected(boolean b)
   {
-    abovePIDThreshold = b;
+    viewStyle.setConservationSelected(b);
   }
 
-  int threshold;
+  /**
+   * @param show
+   * @see jalview.api.ViewStyleI#setShowHiddenMarkers(boolean)
+   */
+  public void setShowHiddenMarkers(boolean show)
+  {
+    viewStyle.setShowHiddenMarkers(show);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getShowHiddenMarkers()
+   */
+  public boolean getShowHiddenMarkers()
+  {
+    return viewStyle.getShowHiddenMarkers();
+  }
+
+  /**
+   * @param b
+   * @see jalview.api.ViewStyleI#setScaleRightWrapped(boolean)
+   */
+  public void setScaleRightWrapped(boolean b)
+  {
+    viewStyle.setScaleRightWrapped(b);
+  }
+
+  /**
+   * @param b
+   * @see jalview.api.ViewStyleI#setScaleLeftWrapped(boolean)
+   */
+  public void setScaleLeftWrapped(boolean b)
+  {
+    viewStyle.setScaleLeftWrapped(b);
+  }
+
+  /**
+   * @param b
+   * @see jalview.api.ViewStyleI#setScaleAboveWrapped(boolean)
+   */
+  public void setScaleAboveWrapped(boolean b)
+  {
+    viewStyle.setScaleAboveWrapped(b);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getScaleLeftWrapped()
+   */
+  public boolean getScaleLeftWrapped()
+  {
+    return viewStyle.getScaleLeftWrapped();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getScaleAboveWrapped()
+   */
+  public boolean getScaleAboveWrapped()
+  {
+    return viewStyle.getScaleAboveWrapped();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getScaleRightWrapped()
+   */
+  public boolean getScaleRightWrapped()
+  {
+    return viewStyle.getScaleRightWrapped();
+  }
+
+  /**
+   * @param b
+   * @see jalview.api.ViewStyleI#setAbovePIDThreshold(boolean)
+   */
+  public void setAbovePIDThreshold(boolean b)
+  {
+    viewStyle.setAbovePIDThreshold(b);
+  }
 
   /**
-   * DOCUMENT ME!
-   * 
    * @param thresh
-   *          DOCUMENT ME!
+   * @see jalview.api.ViewStyleI#setThreshold(int)
    */
   public void setThreshold(int thresh)
   {
-    threshold = thresh;
+    viewStyle.setThreshold(thresh);
   }
 
   /**
-   * DOCUMENT ME!
-   * 
-   * @return DOCUMENT ME!
+   * @return
+   * @see jalview.api.ViewStyleI#getThreshold()
    */
   public int getThreshold()
   {
-    return threshold;
+    return viewStyle.getThreshold();
   }
 
-  int increment;
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getShowJVSuffix()
+   */
+  public boolean getShowJVSuffix()
+  {
+    return viewStyle.getShowJVSuffix();
+  }
 
   /**
-   * 
-   * @param inc
-   *          set the scalar for bleaching colourschemes according to degree of
-   *          conservation
+   * @param b
+   * @see jalview.api.ViewStyleI#setShowJVSuffix(boolean)
    */
-  public void setIncrement(int inc)
+  public void setShowJVSuffix(boolean b)
   {
-    increment = inc;
+    viewStyle.setShowJVSuffix(b);
   }
 
   /**
-   * GUI State
-   * 
-   * @return get scalar for bleaching colourschemes by conservation
+   * @param state
+   * @see jalview.api.ViewStyleI#setWrapAlignment(boolean)
    */
-  public int getIncrement()
+  public void setWrapAlignment(boolean state)
   {
-    return increment;
+    viewStyle.setWrapAlignment(state);
   }
 
-  boolean conservationColourSelected = false;
+  /**
+   * @param state
+   * @see jalview.api.ViewStyleI#setShowText(boolean)
+   */
+  public void setShowText(boolean state)
+  {
+    viewStyle.setShowText(state);
+  }
 
   /**
-   * GUI state
-   * 
-   * @return true if conservation based shading is enabled
+   * @param state
+   * @see jalview.api.ViewStyleI#setRenderGaps(boolean)
    */
-  public boolean getConservationSelected()
+  public void setRenderGaps(boolean state)
   {
-    return conservationColourSelected;
+    viewStyle.setRenderGaps(state);
   }
 
   /**
-   * GUI state
-   * 
-   * @param b
-   *          enable conservation based shading
+   * @return
+   * @see jalview.api.ViewStyleI#getColourText()
    */
-  public void setConservationSelected(boolean b)
+  public boolean getColourText()
+  {
+    return viewStyle.getColourText();
+  }
+
+  /**
+   * @param state
+   * @see jalview.api.ViewStyleI#setColourText(boolean)
+   */
+  public void setColourText(boolean state)
+  {
+    viewStyle.setColourText(state);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getWrapAlignment()
+   */
+  public boolean getWrapAlignment()
+  {
+    return viewStyle.getWrapAlignment();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getShowText()
+   */
+  public boolean getShowText()
+  {
+    return viewStyle.getShowText();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getWrappedWidth()
+   */
+  public int getWrappedWidth()
+  {
+    return viewStyle.getWrappedWidth();
+  }
+
+  /**
+   * @param w
+   * @see jalview.api.ViewStyleI#setWrappedWidth(int)
+   */
+  public void setWrappedWidth(int w)
+  {
+    viewStyle.setWrappedWidth(w);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getCharHeight()
+   */
+  public int getCharHeight()
+  {
+    return viewStyle.getCharHeight();
+  }
+
+  /**
+   * @param h
+   * @see jalview.api.ViewStyleI#setCharHeight(int)
+   */
+  public void setCharHeight(int h)
+  {
+    viewStyle.setCharHeight(h);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getCharWidth()
+   */
+  public int getCharWidth()
+  {
+    return viewStyle.getCharWidth();
+  }
+
+  /**
+   * @param w
+   * @see jalview.api.ViewStyleI#setCharWidth(int)
+   */
+  public void setCharWidth(int w)
+  {
+    viewStyle.setCharWidth(w);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getShowBoxes()
+   */
+  public boolean getShowBoxes()
+  {
+    return viewStyle.getShowBoxes();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getShowUnconserved()
+   */
+  public boolean getShowUnconserved()
   {
-    conservationColourSelected = b;
+    return viewStyle.getShowUnconserved();
+  }
+
+  /**
+   * @param showunconserved
+   * @see jalview.api.ViewStyleI#setShowUnconserved(boolean)
+   */
+  public void setShowUnconserved(boolean showunconserved)
+  {
+    viewStyle.setShowUnconserved(showunconserved);
+  }
+
+  /**
+   * @param default1
+   * @see jalview.api.ViewStyleI#setSeqNameItalics(boolean)
+   */
+  public void setSeqNameItalics(boolean default1)
+  {
+    viewStyle.setSeqNameItalics(default1);
+  }
+
+  /**
+   * @param selected
+   * @see jalview.api.ViewStyleI#setShowSeqFeaturesHeight(boolean)
+   */
+  public void setShowSeqFeaturesHeight(boolean selected)
+  {
+    viewStyle.setShowSeqFeaturesHeight(selected);
+  }
+
+  /**
+   * alignment displayed in the viewport. Please use get/setter
+   */
+  protected AlignmentI alignment;
+
+  @Override
+  public AlignmentI getAlignment()
+  {
+    return alignment;
   }
 
   @Override
+  public char getGapCharacter()
+  {
+    return alignment.getGapCharacter();
+  }
+
+  protected String sequenceSetID;
+
+  /**
+   * probably unused indicator that view is of a dataset rather than an
+   * alignment
+   */
+  protected boolean isDataset = false;
+
+  public void setDataset(boolean b)
+  {
+    isDataset = b;
+  }
+
+  public boolean isDataset()
+  {
+    return isDataset;
+  }
+
+
+  private Map<SequenceI, SequenceCollectionI> hiddenRepSequences;
+
+  protected ColumnSelection colSel = new ColumnSelection();
+
+  public boolean autoCalculateConsensus = true;
+
+  protected boolean autoCalculateStrucConsensus = true;
+
+  protected boolean ignoreGapsInConsensusCalculation = false;
+
+  protected ColourSchemeI globalColourScheme = null;
+
+
+  @Override
   public void setGlobalColourScheme(ColourSchemeI cs)
   {
     // TODO: logic refactored from AlignFrame changeColour -
@@ -221,7 +577,8 @@ public abstract class AlignmentViewport implements AlignViewportI
               || cs instanceof Blosum62ColourScheme)
       {
         recalc = true;
-        cs.setThreshold(threshold, ignoreGapsInConsensusCalculation);
+        cs.setThreshold(viewStyle.getThreshold(),
+                ignoreGapsInConsensusCalculation);
       }
       else
       {
@@ -248,12 +605,13 @@ public abstract class AlignmentViewport implements AlignViewportI
         if (getAbovePIDThreshold() || cs instanceof PIDColourScheme
                 || cs instanceof Blosum62ColourScheme)
         {
-          sg.cs.setThreshold(threshold, getIgnoreGapsConsensus());
+          sg.cs.setThreshold(viewStyle.getThreshold(),
+                  isIgnoreGapsConsensus());
           recalc = true;
         }
         else
         {
-          sg.cs.setThreshold(0, getIgnoreGapsConsensus());
+          sg.cs.setThreshold(0, isIgnoreGapsConsensus());
         }
 
         if (getConservationSelected())
@@ -287,6 +645,8 @@ public abstract class AlignmentViewport implements AlignViewportI
 
   protected AlignmentAnnotation consensus;
 
+  protected AlignmentAnnotation complementConsensus;
+
   protected AlignmentAnnotation strucConsensus;
 
   protected AlignmentAnnotation conservation;
@@ -303,6 +663,11 @@ public abstract class AlignmentViewport implements AlignViewportI
   protected Hashtable[] hconsensus = null;
 
   /**
+   * results of cDNA complement consensus visible portion of view
+   */
+  protected Hashtable[] hcomplementConsensus = null;
+
+  /**
    * results of secondary structure base pair consensus for visible portion of
    * view
    */
@@ -332,7 +697,12 @@ public abstract class AlignmentViewport implements AlignViewportI
   public void setSequenceConsensusHash(Hashtable[] hconsensus)
   {
     this.hconsensus = hconsensus;
+  }
 
+  @Override
+  public void setComplementConsensusHash(Hashtable[] hconsensus)
+  {
+    this.hcomplementConsensus = hconsensus;
   }
 
   @Override
@@ -342,6 +712,12 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   @Override
+  public Hashtable[] getComplementConsensusHash()
+  {
+    return hcomplementConsensus;
+  }
+
+  @Override
   public Hashtable[] getRnaStructureConsensusHash()
   {
     return hStrucConsensus;
@@ -367,9 +743,15 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   @Override
-  public AlignmentAnnotation getAlignmentConsensusAnnotation()
+  public AlignmentAnnotation getAlignmentConsensusAnnotation()
+  {
+    return consensus;
+  }
+
+  @Override
+  public AlignmentAnnotation getComplementConsensusAnnotation()
   {
-    return consensus;
+    return complementConsensus;
   }
 
   @Override
@@ -413,6 +795,20 @@ public abstract class AlignmentViewport implements AlignViewportI
     {
       calculator.registerWorker(new ConsensusThread(this, ap));
     }
+
+    /*
+     * A separate thread to compute cDNA consensus for a protein alignment
+     */
+    final AlignmentI al = this.getAlignment();
+    if (!al.isNucleotide() && al.getCodonFrames() != null
+            && !al.getCodonFrames().isEmpty())
+    {
+      if (calculator
+              .getRegisteredWorkersOfClass(ComplementConsensusThread.class) == null)
+      {
+        calculator.registerWorker(new ComplementConsensusThread(this, ap));
+      }
+    }
   }
 
   // --------START Structure Conservation
@@ -517,6 +913,7 @@ public abstract class AlignmentViewport implements AlignViewportI
       // annotation update method from alignframe to viewport
       this.showSequenceLogo = showSequenceLogo;
       calculator.updateAnnotationFor(ConsensusThread.class);
+      calculator.updateAnnotationFor(ComplementConsensusThread.class);
       calculator.updateAnnotationFor(StrucConsensusThread.class);
     }
     this.showSequenceLogo = showSequenceLogo;
@@ -577,11 +974,6 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   /**
-   * show non-conserved residues only
-   */
-  protected boolean showUnconserved = false;
-
-  /**
    * when set, updateAlignment will always ensure sequences are of equal length
    */
   private boolean padGaps = false;
@@ -591,24 +983,6 @@ public abstract class AlignmentViewport implements AlignViewportI
    */
   public boolean sortByTree = false;
 
-  public boolean getShowUnconserved()
-  {
-    return showUnconserved;
-  }
-
-  public void setShowUnconserved(boolean showunconserved)
-  {
-    showUnconserved = showunconserved;
-  }
-
-  /**
-   * @param showNonconserved
-   *          the showUnconserved to set
-   */
-  public void setShowunconserved(boolean displayNonconserved)
-  {
-    this.showUnconserved = displayNonconserved;
-  }
 
   /**
    * 
@@ -722,6 +1096,7 @@ public abstract class AlignmentViewport implements AlignViewportI
    */
   protected String viewId = null;
 
+  @Override
   public String getViewId()
   {
     if (viewId == null)
@@ -796,7 +1171,7 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   @Override
-  public boolean getIgnoreGapsConsensus()
+  public boolean isIgnoreGapsConsensus()
   {
     return ignoreGapsInConsensusCalculation;
   }
@@ -813,7 +1188,7 @@ public abstract class AlignmentViewport implements AlignViewportI
 
   protected boolean showConsensus = true;
 
-  Hashtable sequenceColours;
+  private Map<SequenceI, Color> sequenceColours = new HashMap<SequenceI, Color>();
 
   /**
    * Property change listener for changes in alignment
@@ -1050,9 +1425,6 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   @Override
-  public abstract void sendSelection();
-
-  @Override
   public void invertColumnSelection()
   {
     colSel.invertColumnSelection(0, alignment.getWidth());
@@ -1074,10 +1446,8 @@ public abstract class AlignmentViewport implements AlignViewportI
       AlignmentAnnotation[] annots = alignment.getAlignmentAnnotation();
       for (int i = 0; i < sequences.length; i++)
       {
-        sequences[i] = new Sequence(sequences[i], annots); // construct new
-        // sequence with
-        // subset of visible
-        // annotation
+        // construct new sequence with subset of visible annotation
+        sequences[i] = new Sequence(sequences[i], annots);
       }
     }
     else
@@ -1106,10 +1476,10 @@ public abstract class AlignmentViewport implements AlignViewportI
 
 
   @Override
-  public jalview.datamodel.CigarArray getViewAsCigars(
+  public CigarArray getViewAsCigars(
           boolean selectedRegionOnly)
   {
-    return new jalview.datamodel.CigarArray(alignment, colSel,
+    return new CigarArray(alignment, colSel,
             (selectedRegionOnly ? selectionGroup : null));
   }
 
@@ -1171,9 +1541,9 @@ public abstract class AlignmentViewport implements AlignViewportI
 
 
   @Override
-  public int[][] getVisibleRegionBoundaries(int min, int max)
+  public List<int[]> getVisibleRegionBoundaries(int min, int max)
   {
-    Vector regions = new Vector();
+    ArrayList<int[]> regions = new ArrayList<int[]>();
     int start = min;
     int end = max;
 
@@ -1197,7 +1567,7 @@ public abstract class AlignmentViewport implements AlignViewportI
         }
       }
 
-      regions.addElement(new int[]
+      regions.add(new int[]
       { start, end });
 
       if (colSel != null && colSel.hasHiddenColumns())
@@ -1209,10 +1579,7 @@ public abstract class AlignmentViewport implements AlignViewportI
 
     int[][] startEnd = new int[regions.size()][2];
 
-    regions.copyInto(startEnd);
-
-    return startEnd;
-
+    return regions;
   }
 
   @Override
@@ -1347,21 +1714,42 @@ public abstract class AlignmentViewport implements AlignViewportI
       {
         initRNAStructure();
       }
-      initConsensus();
+      consensus = new AlignmentAnnotation("Consensus", "PID",
+              new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
+      initConsensus(consensus);
+
+      initComplementConsensus();
     }
   }
 
-  private void initConsensus()
+  /**
+   * If this is a protein alignment and there are mappings to cDNA, add the cDNA
+   * consensus annotation.
+   */
+  protected void initComplementConsensus()
   {
+    if (!alignment.isNucleotide())
+    {
+      final Set<AlignedCodonFrame> codonMappings = alignment
+              .getCodonFrames();
+      if (codonMappings != null && !codonMappings.isEmpty())
+      {
+        complementConsensus = new AlignmentAnnotation("cDNA Consensus",
+                "PID for cDNA", new Annotation[1], 0f, 100f,
+                AlignmentAnnotation.BAR_GRAPH);
+        initConsensus(complementConsensus);
+      }
+    }
+  }
 
-    consensus = new AlignmentAnnotation("Consensus", "PID",
-            new Annotation[1], 0f, 100f, AlignmentAnnotation.BAR_GRAPH);
-    consensus.hasText = true;
-    consensus.autoCalculated = true;
+  private void initConsensus(AlignmentAnnotation aa)
+  {
+    aa.hasText = true;
+    aa.autoCalculated = true;
 
     if (showConsensus)
     {
-      alignment.addAnnotation(consensus);
+      alignment.addAnnotation(aa);
     }
   }
 
@@ -1423,57 +1811,57 @@ public abstract class AlignmentViewport implements AlignViewportI
   public int calcPanelHeight()
   {
     // setHeight of panels
-    AlignmentAnnotation[] aa = getAlignment().getAlignmentAnnotation();
+    AlignmentAnnotation[] anns = getAlignment().getAlignmentAnnotation();
     int height = 0;
     int charHeight = getCharHeight();
-    if (aa != null)
+    if (anns != null)
     {
       BitSet graphgrp = new BitSet();
-      for (int i = 0; i < aa.length; i++)
+      for (AlignmentAnnotation aa : anns)
       {
-        if (aa[i] == null)
+        if (aa == null)
         {
           System.err.println("Null annotation row: ignoring.");
           continue;
         }
-        if (!aa[i].visible)
+        if (!aa.visible)
         {
           continue;
         }
-        if (aa[i].graphGroup > -1)
+        if (aa.graphGroup > -1)
         {
-          if (graphgrp.get(aa[i].graphGroup))
+          if (graphgrp.get(aa.graphGroup))
           {
             continue;
           }
           else
           {
-            graphgrp.set(aa[i].graphGroup);
+            graphgrp.set(aa.graphGroup);
           }
         }
-        aa[i].height = 0;
+        aa.height = 0;
 
-        if (aa[i].hasText)
+        if (aa.hasText)
         {
-          aa[i].height += charHeight;
+          aa.height += charHeight;
         }
 
-        if (aa[i].hasIcons)
+        if (aa.hasIcons)
         {
-          aa[i].height += 16;
+          aa.height += 16;
         }
 
-        if (aa[i].graph > 0)
+        if (aa.graph > 0)
         {
-          aa[i].height += aa[i].graphHeight;
+          aa.height += aa.graphHeight;
         }
 
-        if (aa[i].height == 0)
+        if (aa.height == 0)
         {
-          aa[i].height = 20;
+          aa.height = 20;
         }
 
-        height += aa[i].height;
+        height += aa.height;
       }
     }
     if (height == 0)
@@ -1551,60 +1939,34 @@ public abstract class AlignmentViewport implements AlignViewportI
     }
     oldrfs.clear();
   }
-  /**
-   * show the reference sequence in the alignment view
-   */
-  private boolean displayReferenceSeq=false;
-  /**
-   * colour according to the reference sequence defined on the alignment
-   */
-  private boolean colourByReferenceSeq=false;
-
   @Override
   public boolean isDisplayReferenceSeq()
   {
-    return alignment.hasSeqrep() && displayReferenceSeq;
+    return alignment.hasSeqrep() && viewStyle.isDisplayReferenceSeq();
   }
 
   @Override
   public void setDisplayReferenceSeq(boolean displayReferenceSeq)
   {
-    this.displayReferenceSeq = displayReferenceSeq;
+    viewStyle.setDisplayReferenceSeq(displayReferenceSeq);
   }
 
+  @Override
   public boolean isColourByReferenceSeq()
   {
-    return alignment.hasSeqrep() && colourByReferenceSeq;
-  }
-
-  public void setColourByReferenceSeq(boolean colourByReferenceSeq)
-  {
-    this.colourByReferenceSeq = colourByReferenceSeq;
+    return alignment.hasSeqrep() && viewStyle.isColourByReferenceSeq();
   }
 
   @Override
   public Color getSequenceColour(SequenceI seq)
   {
-    Color sqc = Color.white;
-    if (sequenceColours != null)
-    {
-      sqc = (Color) sequenceColours.get(seq);
-      if (sqc == null)
-      {
-        sqc = Color.white;
-      }
-    }
-    return sqc;
+    Color sqc = sequenceColours.get(seq);
+    return (sqc == null ? Color.white : sqc);
   }
 
   @Override
   public void setSequenceColour(SequenceI seq, Color col)
   {
-    if (sequenceColours == null)
-    {
-      sequenceColours = new Hashtable();
-    }
-
     if (col == null)
     {
       sequenceColours.remove(seq);
@@ -1618,10 +1980,6 @@ public abstract class AlignmentViewport implements AlignViewportI
   @Override
   public void updateSequenceIdColours()
   {
-    if (sequenceColours == null)
-    {
-      sequenceColours = new Hashtable();
-    }
     for (SequenceGroup sg : alignment.getGroups())
     {
       if (sg.idColour != null)
@@ -1637,10 +1995,42 @@ public abstract class AlignmentViewport implements AlignViewportI
   @Override
   public void clearSequenceColours()
   {
-    sequenceColours = null;
+    sequenceColours.clear();
   };
 
-  FeaturesDisplayedI featuresDisplayed = null;
+  @Override
+  public AlignViewportI getCodingComplement()
+  {
+    return this.codingComplement;
+  }
+
+  /**
+   * Set this as the (cDna/protein) complement of the given viewport. Also
+   * ensures the reverse relationship is set on the given viewport.
+   */
+  @Override
+  public void setCodingComplement(AlignViewportI av)
+  {
+    if (this == av)
+    {
+      System.err.println("Ignoring recursive setCodingComplement request");
+    }
+    else
+    {
+      this.codingComplement = av;
+      // avoid infinite recursion!
+      if (av.getCodingComplement() != this)
+      {
+        av.setCodingComplement(this);
+      }
+    }
+  }
+
+  @Override
+  public boolean isNucleotide()
+  {
+    return getAlignment() == null ? false : getAlignment().isNucleotide();
+  }
 
   @Override
   public FeaturesDisplayedI getFeaturesDisplayed()
@@ -1661,11 +2051,6 @@ public abstract class AlignmentViewport implements AlignViewportI
   }
 
   /**
-   * display setting for showing/hiding sequence features on alignment view
-   */
-  boolean showSequenceFeatures = false;
-
-  /**
    * set the flag
    * 
    * @param b
@@ -1674,55 +2059,331 @@ public abstract class AlignmentViewport implements AlignViewportI
   @Override
   public void setShowSequenceFeatures(boolean b)
   {
-    showSequenceFeatures = b;
+    viewStyle.setShowSequenceFeatures(b);
   }
   @Override
   public boolean isShowSequenceFeatures()
   {
-    return showSequenceFeatures;
+    return viewStyle.isShowSequenceFeatures();
   }
 
-  boolean showSeqFeaturesHeight;
-
   @Override
   public void setShowSequenceFeaturesHeight(boolean selected)
   {
-    showSeqFeaturesHeight = selected;
+    viewStyle.setShowSeqFeaturesHeight(selected);
   }
 
   @Override
   public boolean isShowSequenceFeaturesHeight()
   {
-    return showSeqFeaturesHeight;
+    return viewStyle.isShowSequenceFeaturesHeight();
   }
 
-  private boolean showAnnotation = true;
-
-  private boolean rightAlignIds = false;
 
 
   @Override
   public void setShowAnnotation(boolean b)
   {
-    showAnnotation = b;
+    viewStyle.setShowAnnotation(b);
   }
 
   @Override
   public boolean isShowAnnotation()
   {
-    return showAnnotation;
+    return viewStyle.isShowAnnotation();
   }
 
   @Override
   public boolean isRightAlignIds()
   {
-    return rightAlignIds;
+    return viewStyle.isRightAlignIds();
   }
 
   @Override
   public void setRightAlignIds(boolean rightAlignIds)
   {
-    this.rightAlignIds = rightAlignIds;
+    viewStyle.setRightAlignIds(rightAlignIds);
+  }
+
+  @Override
+  public boolean getConservationSelected()
+  {
+    return viewStyle.getConservationSelected();
+  }
+
+  @Override
+  public void setShowBoxes(boolean state)
+  {
+    viewStyle.setShowBoxes(state);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getTextColour()
+   */
+  public Color getTextColour()
+  {
+    return viewStyle.getTextColour();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getTextColour2()
+   */
+  public Color getTextColour2()
+  {
+    return viewStyle.getTextColour2();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getThresholdTextColour()
+   */
+  public int getThresholdTextColour()
+  {
+    return viewStyle.getThresholdTextColour();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isConservationColourSelected()
+   */
+  public boolean isConservationColourSelected()
+  {
+    return viewStyle.isConservationColourSelected();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isRenderGaps()
+   */
+  public boolean isRenderGaps()
+  {
+    return viewStyle.isRenderGaps();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isShowColourText()
+   */
+  public boolean isShowColourText()
+  {
+    return viewStyle.isShowColourText();
+  }
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isShowSeqFeaturesHeight()
+   */
+  public boolean isShowSeqFeaturesHeight()
+  {
+    return viewStyle.isShowSeqFeaturesHeight();
+  }
+
+  /**
+   * @param conservationColourSelected
+   * @see jalview.api.ViewStyleI#setConservationColourSelected(boolean)
+   */
+  public void setConservationColourSelected(
+          boolean conservationColourSelected)
+  {
+    viewStyle.setConservationColourSelected(conservationColourSelected);
+  }
+
+  /**
+   * @param showColourText
+   * @see jalview.api.ViewStyleI#setShowColourText(boolean)
+   */
+  public void setShowColourText(boolean showColourText)
+  {
+    viewStyle.setShowColourText(showColourText);
+  }
+
+  /**
+   * @param textColour
+   * @see jalview.api.ViewStyleI#setTextColour(java.awt.Color)
+   */
+  public void setTextColour(Color textColour)
+  {
+    viewStyle.setTextColour(textColour);
+  }
+
+  /**
+   * @param thresholdTextColour
+   * @see jalview.api.ViewStyleI#setThresholdTextColour(int)
+   */
+  public void setThresholdTextColour(int thresholdTextColour)
+  {
+    viewStyle.setThresholdTextColour(thresholdTextColour);
+  }
+
+  /**
+   * @param textColour2
+   * @see jalview.api.ViewStyleI#setTextColour2(java.awt.Color)
+   */
+  public void setTextColour2(Color textColour2)
+  {
+    viewStyle.setTextColour2(textColour2);
+  }
+
+  @Override
+  public ViewStyleI getViewStyle()
+  {
+    return new ViewStyle(viewStyle);
+  }
+
+  @Override
+  public void setViewStyle(ViewStyleI settingsForView)
+  {
+    viewStyle = new ViewStyle(settingsForView);
+  }
+
+  @Override
+  public boolean sameStyle(ViewStyleI them)
+  {
+    return viewStyle.sameStyle(them);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#getIdWidth()
+   */
+  public int getIdWidth()
+  {
+    return viewStyle.getIdWidth();
+  }
+
+  /**
+   * @param i
+   * @see jalview.api.ViewStyleI#setIdWidth(int)
+   */
+  public void setIdWidth(int i)
+  {
+    viewStyle.setIdWidth(i);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isCentreColumnLabels()
+   */
+  public boolean isCentreColumnLabels()
+  {
+    return viewStyle.isCentreColumnLabels();
+  }
+
+  /**
+   * @param centreColumnLabels
+   * @see jalview.api.ViewStyleI#setCentreColumnLabels(boolean)
+   */
+  public void setCentreColumnLabels(boolean centreColumnLabels)
+  {
+    viewStyle.setCentreColumnLabels(centreColumnLabels);
   }
 
+  /**
+   * @param showdbrefs
+   * @see jalview.api.ViewStyleI#setShowDBRefs(boolean)
+   */
+  public void setShowDBRefs(boolean showdbrefs)
+  {
+    viewStyle.setShowDBRefs(showdbrefs);
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isShowDBRefs()
+   */
+  public boolean isShowDBRefs()
+  {
+    return viewStyle.isShowDBRefs();
+  }
+
+  /**
+   * @return
+   * @see jalview.api.ViewStyleI#isShowNPFeats()
+   */
+  public boolean isShowNPFeats()
+  {
+    return viewStyle.isShowNPFeats();
+  }
+
+  /**
+   * @param shownpfeats
+   * @see jalview.api.ViewStyleI#setShowNPFeats(boolean)
+   */
+  public void setShowNPFeats(boolean shownpfeats)
+  {
+    viewStyle.setShowNPFeats(shownpfeats);
+  }
+
+  public abstract StructureSelectionManager getStructureSelectionManager();
+
+  /**
+   * Add one command to the command history list.
+   * 
+   * @param command
+   */
+  public void addToHistoryList(CommandI command)
+  {
+    if (this.historyList != null)
+    {
+      this.historyList.push(command);
+      broadcastCommand(command, false);
+    }
+  }
+
+  protected void broadcastCommand(CommandI command, boolean undo)
+  {
+    getStructureSelectionManager().commandPerformed(command, undo, getVamsasSource());
+  }
+
+  /**
+   * Add one command to the command redo list.
+   * 
+   * @param command
+   */
+  public void addToRedoList(CommandI command)
+  {
+    if (this.redoList != null)
+    {
+      this.redoList.push(command);
+    }
+    broadcastCommand(command, true);
+  }
+
+  /**
+   * Clear the command redo list.
+   */
+  public void clearRedoList()
+  {
+    if (this.redoList != null)
+    {
+      this.redoList.clear();
+    }
+  }
+
+  public void setHistoryList(Deque<CommandI> list)
+  {
+    this.historyList = list;
+  }
+
+  public Deque<CommandI> getHistoryList()
+  {
+    return this.historyList;
+  }
+
+  public void setRedoList(Deque<CommandI> list)
+  {
+    this.redoList = list;
+  }
+
+  public Deque<CommandI> getRedoList()
+  {
+    return this.redoList;
+  }
+
+  @Override
+  public VamsasSource getVamsasSource()
+  {
+    return this;
+  }
 }