Merge branch 'develop' into trial_merge/JAL-1950 spike/JAL-1950_hmmer3client
authorJim Procter <jprocter@issues.jalview.org>
Mon, 21 Aug 2017 18:57:44 +0000 (19:57 +0100)
committerJim Procter <jprocter@issues.jalview.org>
Mon, 21 Aug 2017 18:57:44 +0000 (19:57 +0100)
 Conflicts:
src/jalview/gui/RestServiceEditorPane.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJobThread.java
Shmmr client definition refactored.
AnnotationColourGradient includes 'fade to grey' P-value+E-value shading

1  2 
src/jalview/datamodel/AlignmentAnnotation.java
src/jalview/gui/AlignViewport.java
src/jalview/gui/RestServiceEditorPane.java
src/jalview/schemes/AnnotationColourGradient.java
src/jalview/util/Comparison.java
src/jalview/ws/rest/RestClient.java
src/jalview/ws/rest/RestJobThread.java

@@@ -96,14 -96,13 +96,13 @@@ public class AlignmentAnnotatio
     * Updates the _rnasecstr field Determines the positions that base pair and
     * the positions of helices based on secondary structure from a Stockholm file
     * 
-    * @param RNAannot
+    * @param rnaAnnotation
     */
-   private void _updateRnaSecStr(CharSequence RNAannot)
+   private void _updateRnaSecStr(CharSequence rnaAnnotation)
    {
      try
      {
-       bps = Rna.getModeleBP(RNAannot);
-       _rnasecstr = Rna.getBasePairs(bps);
+       _rnasecstr = Rna.getHelixMap(rnaAnnotation);
        invalidrnastruc = -1;
      } catch (WUSSParseException px)
      {
      {
        return;
      }
-     Rna.HelixMap(_rnasecstr);
-     // setRNAStruc(RNAannot);
  
      if (_rnasecstr != null && _rnasecstr.length > 0)
      {
     */
    private Map<Integer, Annotation> sequenceMapping;
  
-   /** DOCUMENT ME!! */
+   /**
+    * lower range for quantitative data
+    */
    public float graphMin;
  
-   /** DOCUMENT ME!! */
+   /**
+    * Upper range for quantitative data
+    */
    public float graphMax;
  
    /**
      }
    }
  
-   // JBPNote: what does this do ?
-   public void ConcenStru(CharSequence RNAannot) throws WUSSParseException
-   {
-     bps = Rna.getModeleBP(RNAannot);
-   }
    /**
     * Creates a new AlignmentAnnotation object.
     * 
          firstChar = annotations[i].displayCharacter.charAt(0);
          // check to see if it looks like a sequence or is secondary structure
          // labelling.
-         if (annotations[i].secondaryStructure != ' '
-                 && !hasIcons
-                 &&
-                 // Uncomment to only catch case where
-                 // displayCharacter==secondary
-                 // Structure
-                 // to correctly redisplay SS annotation imported from Stockholm,
-                 // exported to JalviewXML and read back in again.
-                 // &&
-                 // annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
-                 firstChar != ' '
-                 && firstChar != '$'
-                 && firstChar != 0xCE
-                 && firstChar != '('
-                 && firstChar != '['
-                 && firstChar != '>'
-                 && firstChar != '{'
-                 && firstChar != 'A'
-                 && firstChar != 'B'
-                 && firstChar != 'C'
-                 && firstChar != 'D'
-                 && firstChar != 'E'
-                 && firstChar != 'F'
-                 && firstChar != 'G'
-                 && firstChar != 'H'
-                 && firstChar != 'I'
-                 && firstChar != 'J'
-                 && firstChar != 'K'
-                 && firstChar != 'L'
-                 && firstChar != 'M'
-                 && firstChar != 'N'
-                 && firstChar != 'O'
-                 && firstChar != 'P'
-                 && firstChar != 'Q'
-                 && firstChar != 'R'
-                 && firstChar != 'S'
-                 && firstChar != 'T'
-                 && firstChar != 'U'
-                 && firstChar != 'V'
-                 && firstChar != 'W'
-                 && firstChar != 'X'
-                 && firstChar != 'Y'
-                 && firstChar != 'Z'
+         if (annotations[i].secondaryStructure != ' ' && !hasIcons &&
+         // Uncomment to only catch case where
+         // displayCharacter==secondary
+         // Structure
+         // to correctly redisplay SS annotation imported from Stockholm,
+         // exported to JalviewXML and read back in again.
+         // &&
+         // annotations[i].displayCharacter.charAt(0)==annotations[i].secondaryStructure
+                 firstChar != ' ' && firstChar != '$' && firstChar != 0xCE
+                 && firstChar != '(' && firstChar != '[' && firstChar != '>'
+                 && firstChar != '{' && firstChar != 'A' && firstChar != 'B'
+                 && firstChar != 'C' && firstChar != 'D' && firstChar != 'E'
+                 && firstChar != 'F' && firstChar != 'G' && firstChar != 'H'
+                 && firstChar != 'I' && firstChar != 'J' && firstChar != 'K'
+                 && firstChar != 'L' && firstChar != 'M' && firstChar != 'N'
+                 && firstChar != 'O' && firstChar != 'P' && firstChar != 'Q'
+                 && firstChar != 'R' && firstChar != 'S' && firstChar != 'T'
+                 && firstChar != 'U' && firstChar != 'V' && firstChar != 'W'
+                 && firstChar != 'X' && firstChar != 'Y' && firstChar != 'Z'
                  && firstChar != '-'
                  && firstChar < jalview.schemes.ResidueProperties.aaIndex.length)
          {
      {
        return ((index + offset < 0) || (index + offset) >= max
                || annotations[index + offset] == null
-               || (annotations[index + offset].secondaryStructure <= ' ') ? ' '
-               : annotations[index + offset].displayCharacter == null
-                       || annotations[index + offset].displayCharacter
-                               .length() == 0 ? annotations[index + offset].secondaryStructure
-                       : annotations[index + offset].displayCharacter
-                               .charAt(0));
+               || (annotations[index + offset].secondaryStructure <= ' ')
+                       ? ' '
+                       : annotations[index + offset].displayCharacter == null
+                               || annotations[index
+                                       + offset].displayCharacter
+                                               .length() == 0
+                                                       ? annotations[index
+                                                               + offset].secondaryStructure
+                                                       : annotations[index
+                                                               + offset].displayCharacter
+                                                                       .charAt(0));
      }
  
      @Override
  
        for (int i = offset; i < mx; i++)
        {
-         string[i] = (annotations[i] == null || (annotations[i].secondaryStructure <= 32)) ? ' '
-                 : (annotations[i].displayCharacter == null
-                         || annotations[i].displayCharacter.length() == 0 ? annotations[i].secondaryStructure
-                         : annotations[i].displayCharacter.charAt(0));
+         string[i] = (annotations[i] == null
+                 || (annotations[i].secondaryStructure <= 32))
+                         ? ' '
+                         : (annotations[i].displayCharacter == null
+                                 || annotations[i].displayCharacter
+                                         .length() == 0
+                                                 ? annotations[i].secondaryStructure
+                                                 : annotations[i].displayCharacter
+                                                         .charAt(0));
        }
        return new String(string);
      }
      Annotation[] temp = new Annotation[endRes - startRes + 1];
      if (startRes < annotations.length)
      {
-       System.arraycopy(annotations, startRes, temp, 0, endRes - startRes
-               + 1);
+       System.arraycopy(annotations, startRes, temp, 0,
+               endRes - startRes + 1);
      }
      if (sequenceRef != null)
      {
    @Override
    public String toString()
    {
+     if (annotations == null)
+     {
+       return "";
+     }
      StringBuilder buffer = new StringBuilder(256);
  
      for (int i = 0; i < annotations.length; i++)
     * @param seqRef
     * @param startRes
     * @param alreadyMapped
 +   *          - annotation are at aligned columns
     */
    public void createSequenceMapping(SequenceI seqRef, int startRes,
            boolean alreadyMapped)
        {
          if (i + 1 < iSize)
          {
-           System.arraycopy(annotations, i + 1, annotations, i, iSize - i
-                   - 1);
+           System.arraycopy(annotations, i + 1, annotations, i,
+                   iSize - i - 1);
          }
          iSize--;
        }
      {
        if (sequenceRef != null)
        {
-         boolean rIsDs = sequenceRef.getDatasetSequence() == null, tIsDs = sequenceI
-                 .getDatasetSequence() == null;
+         boolean rIsDs = sequenceRef.getDatasetSequence() == null,
+                 tIsDs = sequenceI.getDatasetSequence() == null;
          if (sequenceRef != sequenceI
-                 && (rIsDs && !tIsDs && sequenceRef != sequenceI
-                         .getDatasetSequence())
-                 && (!rIsDs && tIsDs && sequenceRef.getDatasetSequence() != sequenceI)
-                 && (!rIsDs && !tIsDs && sequenceRef.getDatasetSequence() != sequenceI
-                         .getDatasetSequence())
+                 && (rIsDs && !tIsDs
+                         && sequenceRef != sequenceI.getDatasetSequence())
+                 && (!rIsDs && tIsDs
+                         && sequenceRef.getDatasetSequence() != sequenceI)
+                 && (!rIsDs && !tIsDs
+                         && sequenceRef.getDatasetSequence() != sequenceI
+                                 .getDatasetSequence())
                  && !sequenceRef.equals(sequenceI))
          {
            // if sequenceRef isn't intersecting with sequenceI
     * @param colSel
     */
    public AlignmentAnnotation(AlignmentAnnotation alignmentAnnotation,
-           ColumnSelection colSel)
+           HiddenColumns hidden)
    {
      this(alignmentAnnotation);
      if (annotations == null)
      {
        return;
      }
-     colSel.makeVisibleAnnotation(this);
+     hidden.makeVisibleAnnotation(this);
    }
  
    public void setPadGaps(boolean padgaps, char gapchar)
        throw new Error(
                "liftOver currently not implemented for transfer of annotation between different types of seqeunce");
      }
-     boolean mapIsTo = (sp2sq != null) ? (sp2sq.getTo() == sq || sp2sq
-             .getTo() == sq.getDatasetSequence()) : false;
+     boolean mapIsTo = (sp2sq != null)
+             ? (sp2sq.getTo() == sq
+                     || sp2sq.getTo() == sq.getDatasetSequence())
+             : false;
  
      // TODO build a better annotation element map and get rid of annotations[]
      Map<Integer, Annotation> mapForsq = new HashMap<Integer, Annotation>();
        {
          for (Entry<Integer, Annotation> ie : sequenceMapping.entrySet())
          {
-           Integer mpos = Integer.valueOf(mapIsTo ? sp2sq
-                   .getMappedPosition(ie.getKey()) : sp2sq.getPosition(ie
-                   .getKey()));
+           Integer mpos = Integer
+                   .valueOf(mapIsTo ? sp2sq.getMappedPosition(ie.getKey())
+                           : sp2sq.getPosition(ie.getKey()));
            if (mpos >= sq.getStart() && mpos <= sq.getEnd())
            {
              mapForsq.put(mpos, ie.getValue());
         * up to and excluding the target column; if the count is less
         * than 1, the opening bracket is unmatched, so return its match
         */
-       String closer = String.valueOf(Rna
-               .getMatchingClosingParenthesis(symbol));
+       String closer = String
+               .valueOf(Rna.getMatchingClosingParenthesis(symbol));
        String opener = String.valueOf(symbol);
        int count = 0;
        for (int j = col + 1; j < column; j++)
    {
      return counter++;
    }
+   /**
+    * 
+    * @return true for rows that have a range of values in their annotation set
+    */
+   public boolean isQuantitative()
+   {
+     return graphMin < graphMax;
+   }
  }
@@@ -22,7 -22,7 +22,7 @@@ package jalview.gui
  
  import jalview.analysis.AlignmentUtils;
  import jalview.analysis.AnnotationSorter.SequenceAnnotationOrder;
- import jalview.analysis.NJTree;
+ import jalview.analysis.TreeModel;
  import jalview.api.AlignViewportI;
  import jalview.api.AlignmentViewPanel;
  import jalview.api.FeatureColourI;
@@@ -35,15 -35,17 +35,17 @@@ import jalview.datamodel.AlignedCodonFr
  import jalview.datamodel.Alignment;
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.ColumnSelection;
+ import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.PDBEntry;
  import jalview.datamodel.SearchResults;
  import jalview.datamodel.SearchResultsI;
- import jalview.datamodel.Sequence;
  import jalview.datamodel.SequenceGroup;
  import jalview.datamodel.SequenceI;
+ import jalview.renderer.ResidueShader;
+ import jalview.schemes.ColourSchemeI;
  import jalview.schemes.ColourSchemeProperty;
+ import jalview.schemes.ResidueColourScheme;
  import jalview.schemes.UserColourScheme;
- import jalview.structure.CommandListener;
  import jalview.structure.SelectionSource;
  import jalview.structure.StructureSelectionManager;
  import jalview.structure.VamsasSource;
@@@ -54,6 -56,7 +56,7 @@@ import jalview.ws.params.AutoCalcSettin
  import java.awt.Container;
  import java.awt.Dimension;
  import java.awt.Font;
+ import java.awt.FontMetrics;
  import java.awt.Rectangle;
  import java.util.ArrayList;
  import java.util.Hashtable;
@@@ -61,7 -64,6 +64,6 @@@ import java.util.List
  import java.util.Vector;
  
  import javax.swing.JInternalFrame;
- import javax.swing.JOptionPane;
  
  /**
   * DOCUMENT ME!
   * @author $author$
   * @version $Revision: 1.141 $
   */
- public class AlignViewport extends AlignmentViewport implements
-         SelectionSource, CommandListener
+ public class AlignViewport extends AlignmentViewport
+         implements SelectionSource
  {
    Font font;
  
-   NJTree currentTree = null;
+   TreeModel currentTree = null;
  
    boolean cursorMode = false;
  
     */
    public AlignViewport(AlignmentI al)
    {
-     setAlignment(al);
+     super(al);
      init();
    }
  
  
    public AlignViewport(AlignmentI al, String seqsetid, String viewid)
    {
+     super(al);
      sequenceSetID = seqsetid;
      viewId = viewid;
      // TODO remove these once 2.4.VAMSAS release finished
      if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
      {
-       Cache.log.debug("Setting viewport's sequence set id : "
-               + sequenceSetID);
+       Cache.log.debug(
+               "Setting viewport's sequence set id : " + sequenceSetID);
      }
      if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
      {
        Cache.log.debug("Setting viewport's view id : " + viewId);
      }
-     setAlignment(al);
      init();
    }
  
    /**
     * @param hiddenColumns
     *          ColumnSelection
     */
-   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns)
+   public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns)
    {
-     setAlignment(al);
+     super(al);
      if (hiddenColumns != null)
      {
-       colSel = hiddenColumns;
+       al.setHiddenColumns(hiddenColumns);
      }
      init();
    }
     * @param seqsetid
     *          (may be null)
     */
-   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+   public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
            String seqsetid)
    {
      this(al, hiddenColumns, seqsetid, null);
     * @param viewid
     *          (may be null)
     */
-   public AlignViewport(AlignmentI al, ColumnSelection hiddenColumns,
+   public AlignViewport(AlignmentI al, HiddenColumns hiddenColumns,
            String seqsetid, String viewid)
    {
+     super(al);
      sequenceSetID = seqsetid;
      viewId = viewid;
      // TODO remove these once 2.4.VAMSAS release finished
      if (Cache.log != null && Cache.log.isDebugEnabled() && seqsetid != null)
      {
-       Cache.log.debug("Setting viewport's sequence set id : "
-               + sequenceSetID);
+       Cache.log.debug(
+               "Setting viewport's sequence set id : " + sequenceSetID);
      }
      if (Cache.log != null && Cache.log.isDebugEnabled() && viewId != null)
      {
        Cache.log.debug("Setting viewport's view id : " + viewId);
      }
-     setAlignment(al);
      if (hiddenColumns != null)
      {
-       colSel = hiddenColumns;
+       al.setHiddenColumns(hiddenColumns);
      }
      init();
    }
      setShowDBRefs(Cache.getDefault("SHOW_DBREFS_TOOLTIP", true));
      viewStyle.setSeqNameItalics(Cache.getDefault("ID_ITALICS", true));
      viewStyle.setWrapAlignment(Cache.getDefault("WRAP_ALIGNMENT", false));
-     viewStyle.setShowUnconserved(Cache
-             .getDefault("SHOW_UNCONSERVED", false));
+     viewStyle.setShowUnconserved(
+             Cache.getDefault("SHOW_UNCONSERVED", false));
      sortByTree = Cache.getDefault("SORT_BY_TREE", false);
      followSelection = Cache.getDefault("FOLLOW_SELECTIONS", true);
-     sortAnnotationsBy = SequenceAnnotationOrder.valueOf(Cache.getDefault(
-             Preferences.SORT_ANNOTATIONS,
-             SequenceAnnotationOrder.NONE.name()));
-     showAutocalculatedAbove = Cache.getDefault(
-             Preferences.SHOW_AUTOCALC_ABOVE, false);
-     viewStyle.setScaleProteinAsCdna(Cache.getDefault(
-             Preferences.SCALE_PROTEIN_TO_CDNA, true));
+     sortAnnotationsBy = SequenceAnnotationOrder
+             .valueOf(Cache.getDefault(Preferences.SORT_ANNOTATIONS,
+                     SequenceAnnotationOrder.NONE.name()));
+     showAutocalculatedAbove = Cache
+             .getDefault(Preferences.SHOW_AUTOCALC_ABOVE, false);
+     viewStyle.setScaleProteinAsCdna(
+             Cache.getDefault(Preferences.SCALE_PROTEIN_TO_CDNA, true));
    }
  
    void init()
    {
-     this.startRes = 0;
-     this.endRes = alignment.getWidth() - 1;
-     this.startSeq = 0;
-     this.endSeq = alignment.getHeight() - 1;
      applyViewProperties();
  
      String fontName = Cache.getDefault("FONT_NAME", "SansSerif");
  
      setFont(new Font(fontName, style, Integer.parseInt(fontSize)), true);
  
 -    alignment
 -            .setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(0));
 -
 +    if (Cache.getDefault("NORMALISE_GAPS", true))
 +    {
 +      alignment.setGapCharacter(Cache.getDefault("GAP_SYMBOL", "-").charAt(
 +              0));
 +    }
      // We must set conservation and consensus before setting colour,
      // as Blosum and Clustal require this to be done
      if (hconsensus == null && !isDataset)
                false);
        showGroupConsensus = Cache.getDefault("SHOW_GROUP_CONSENSUS", false);
        showConsensus = Cache.getDefault("SHOW_IDENTITY", true);
+       showOccupancy = Cache.getDefault(Preferences.SHOW_OCCUPANCY, true);
      }
      initAutoAnnotation();
-     String colourProperty = alignment.isNucleotide() ? Preferences.DEFAULT_COLOUR_NUC
+     String colourProperty = alignment.isNucleotide()
+             ? Preferences.DEFAULT_COLOUR_NUC
              : Preferences.DEFAULT_COLOUR_PROT;
-     String propertyValue = Cache.getProperty(colourProperty);
-     if (propertyValue == null)
+     String schemeName = Cache.getProperty(colourProperty);
+     if (schemeName == null)
      {
-       // fall back on this property for backwards compatibility
-       propertyValue = Cache.getProperty(Preferences.DEFAULT_COLOUR);
+       // only DEFAULT_COLOUR available in Jalview before 2.9
+       schemeName = Cache.getDefault(Preferences.DEFAULT_COLOUR,
+               ResidueColourScheme.NONE);
      }
-     if (propertyValue != null)
-     {
-       globalColourScheme = ColourSchemeProperty.getColour(alignment,
-               propertyValue);
+     ColourSchemeI colourScheme = ColourSchemeProperty
+             .getColourScheme(alignment, schemeName);
+     residueShading = new ResidueShader(colourScheme);
  
-       if (globalColourScheme instanceof UserColourScheme)
-       {
-         globalColourScheme = UserDefinedColours.loadDefaultColours();
-         ((UserColourScheme) globalColourScheme).setThreshold(0,
-                 isIgnoreGapsConsensus());
-       }
-       if (globalColourScheme != null)
-       {
-         globalColourScheme.setConsensus(hconsensus);
-       }
-     }
-   }
-   /**
-    * get the consensus sequence as displayed under the PID consensus annotation
-    * row.
-    * 
-    * @return consensus sequence as a new sequence object
-    */
-   public SequenceI getConsensusSeq()
-   {
-     if (consensus == null)
+     if (colourScheme instanceof UserColourScheme)
      {
-       updateConsensus(null);
+       residueShading = new ResidueShader(
+               UserDefinedColours.loadDefaultColours());
+       residueShading.setThreshold(0, isIgnoreGapsConsensus());
      }
-     if (consensus == null)
+     if (residueShading != null)
      {
-       return null;
+       residueShading.setConsensus(hconsensus);
      }
-     StringBuffer seqs = new StringBuffer();
-     for (int i = 0; i < consensus.annotations.length; i++)
-     {
-       if (consensus.annotations[i] != null)
-       {
-         if (consensus.annotations[i].description.charAt(0) == '[')
-         {
-           seqs.append(consensus.annotations[i].description.charAt(1));
-         }
-         else
-         {
-           seqs.append(consensus.annotations[i].displayCharacter);
-         }
-       }
-     }
-     SequenceI sq = new Sequence("Consensus", seqs.toString());
-     sq.setDescription("Percentage Identity Consensus "
-             + ((ignoreGapsInConsensusCalculation) ? " without gaps" : ""));
-     return sq;
    }
  
    boolean validCharWidth;
  
    /**
-    * update view settings with the given font. You may need to call
-    * alignPanel.fontChanged to update the layout geometry
-    * 
-    * @param setGrid
-    *          when true, charWidth/height is set according to font mentrics
+    * {@inheritDoc}
     */
+   @Override
    public void setFont(Font f, boolean setGrid)
    {
      font = f;
  
      Container c = new Container();
  
-     java.awt.FontMetrics fm = c.getFontMetrics(font);
-     int w = viewStyle.getCharWidth(), ww = fm.charWidth('M'), h = viewStyle
-             .getCharHeight();
      if (setGrid)
      {
+       FontMetrics fm = c.getFontMetrics(font);
+       int ww = fm.charWidth('M');
        setCharHeight(fm.getHeight());
        setCharWidth(ww);
      }
      super.setViewStyle(settingsForView);
      setFont(new Font(viewStyle.getFontName(), viewStyle.getFontStyle(),
              viewStyle.getFontSize()), false);
    }
  
    /**
     * @param tree
     *          DOCUMENT ME!
     */
-   public void setCurrentTree(NJTree tree)
+   public void setCurrentTree(TreeModel tree)
    {
      currentTree = tree;
    }
     * 
     * @return DOCUMENT ME!
     */
-   public NJTree getCurrentTree()
+   public TreeModel getCurrentTree()
    {
      return currentTree;
    }
      {
        end = alignment.getWidth();
      }
-     viscontigs = colSel.getVisibleContigs(start, end);
+     viscontigs = alignment.getHiddenColumns().getVisibleContigs(start, end);
      return viscontigs;
    }
  
    public void sendSelection()
    {
      jalview.structure.StructureSelectionManager
-             .getStructureSelectionManager(Desktop.instance).sendSelection(
-                     new SequenceGroup(getSelectionGroup()),
-                     new ColumnSelection(getColumnSelection()), this);
+             .getStructureSelectionManager(Desktop.instance)
+             .sendSelection(new SequenceGroup(getSelectionGroup()),
+                     new ColumnSelection(getColumnSelection()),
+                     new HiddenColumns(getAlignment().getHiddenColumns()),
+                     this);
    }
  
    /**
     */
    public AlignmentPanel getAlignPanel()
    {
-     AlignmentPanel[] aps = PaintRefresher.getAssociatedPanels(this
-             .getSequenceSetId());
+     AlignmentPanel[] aps = PaintRefresher
+             .getAssociatedPanels(this.getSequenceSetId());
      for (int p = 0; aps != null && p < aps.length; p++)
      {
        if (aps[p].av == this)
                      && pdb.getChainCode() != null)
              {
                if (pdbRefEntry.getChainCode().equalsIgnoreCase(
-                       pdb.getChainCode())
-                       && !choosenSeqs.contains(sq))
+                       pdb.getChainCode()) && !choosenSeqs.contains(sq))
                {
                  choosenSeqs.add(sq);
                  continue;
     * <ul>
     * <li>compute the equivalent edit on the mapped sequences</li>
     * <li>apply the mapped edit</li>
-    * <li>'apply' the source edit to the working copy of the source sequences</li>
+    * <li>'apply' the source edit to the working copy of the source
+    * sequences</li>
     * </ul>
     * 
     * @param command
        }
      }
  
-     setEndSeq(getAlignment().getHeight());
+     ranges.setEndSeq(getAlignment().getHeight());
      firePropertyChange("alignment", null, getAlignment().getSequences());
    }
  
     */
    protected boolean openLinkedAlignment(AlignmentI al, String title)
    {
-     String[] options = new String[] {
-         MessageManager.getString("action.no"),
+     String[] options = new String[] { MessageManager.getString("action.no"),
          MessageManager.getString("label.split_window"),
          MessageManager.getString("label.new_window"), };
      final String question = JvSwingUtils.wrapTooltip(true,
      AlignFrame newAlignFrame = new AlignFrame(al, AlignFrame.DEFAULT_WIDTH,
              AlignFrame.DEFAULT_HEIGHT);
      newAlignFrame.setTitle(title);
-     newAlignFrame.statusBar.setText(MessageManager.formatMessage(
-             "label.successfully_loaded_file", new Object[] { title }));
+     newAlignFrame.statusBar.setText(MessageManager
+             .formatMessage("label.successfully_loaded_file", new Object[]
+             { title }));
  
      // TODO if we want this (e.g. to enable reload of the alignment from file),
      // we will need to add parameters to the stack.
  
      try
      {
-       newAlignFrame.setMaximum(jalview.bin.Cache.getDefault(
-               "SHOW_FULLSCREEN", false));
+       newAlignFrame.setMaximum(
+               jalview.bin.Cache.getDefault("SHOW_FULLSCREEN", false));
      } catch (java.beans.PropertyVetoException ex)
      {
      }
       * is protein, the mappings to cDNA will be registered with
       * StructureSelectionManager as a side-effect.
       */
-     AlignFrame copyMe = new AlignFrame(complement,
-             AlignFrame.DEFAULT_WIDTH, AlignFrame.DEFAULT_HEIGHT);
+     AlignFrame copyMe = new AlignFrame(complement, AlignFrame.DEFAULT_WIDTH,
+             AlignFrame.DEFAULT_HEIGHT);
      copyMe.setTitle(getAlignPanel().alignFrame.getTitle());
  
      AlignmentI al = newAlignFrame.viewport.getAlignment();
        // TODO would like next line without cast but needs more refactoring...
        final AlignmentPanel complementPanel = ((AlignViewport) getCodingComplement())
                .getAlignPanel();
-       complementPanel.setDontScrollComplement(true);
+       complementPanel.setToScrollComplementPanel(false);
        complementPanel.scrollToCentre(sr, verticalOffset);
+       complementPanel.setToScrollComplementPanel(true);
      }
    }
  
@@@ -241,8 -241,8 +241,8 @@@ public class RestServiceEditorPane exte
    protected void iprmsAdd_actionPerformed(ActionEvent e)
    {
      RestInputParamEditDialog dialog = new RestInputParamEditDialog(this,
-             currentservice, "param"
-                     + (1 + currentservice.getInputParams().size()));
+             currentservice,
+             "param" + (1 + currentservice.getInputParams().size()));
      if (dialog.wasUpdated())
      {
        currentservice.getInputParams().put(dialog.current.token,
                MessageManager.getString("label.select_return_type"));
        for (final JvDataType type : JvDataType.values())
        {
-         popup.add(new JMenuItem(type.name())).addActionListener(
-                 new ActionListener()
+         popup.add(new JMenuItem(type.name()))
+                 .addActionListener(new ActionListener()
                  {
  
                    @Override
        currentservice.addResultDatatype(JvDataType.ANNOTATION);
      }
      initGuiWith(currentservice);
-     rdata.setSelectedIndex(p == -1 ? currentservice.getResultDataTypes()
-             .size() - 1 : p + 1);
+     rdata.setSelectedIndex(
+             p == -1 ? currentservice.getResultDataTypes().size() - 1
+                     : p + 1);
    }
  
    @Override
      StringBuffer warnings = new StringBuffer();
      for (String its : _iparam)
      {
-       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]").matcher(
-               its);
+       Matcher mtch = Pattern.compile("(\\S+)\\s(\\S+):\\[(.+)]")
+               .matcher(its);
        if (mtch.find())
        {
-         if (!RestServiceDescription.parseTypeString(mtch.group(2) + ":"
-                 + mtch.group(3), mtch.group(1), mtch.group(2),
-                 mtch.group(3), inputTypes, warnings))
+         if (!RestServiceDescription.parseTypeString(
+                 mtch.group(2) + ":" + mtch.group(3), mtch.group(1),
+                 mtch.group(2), mtch.group(3), inputTypes, warnings))
          {
-           System.err
-                   .println("IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"
+           System.err.println(
+                   "IMPLEMENTATION PROBLEM: Cannot parse RestService input parameter string '"
                            + its + "'" + "\n" + warnings);
          }
        }
      }
-     char gc = gapChar.getSelectedItem() == null ? ' ' : ((String) gapChar
-             .getSelectedItem()).charAt(0);
+     char gc = gapChar.getSelectedItem() == null ? ' '
+             : ((String) gapChar.getSelectedItem()).charAt(0);
      RestServiceDescription newService = new RestServiceDescription(
-             (String) action.getSelectedItem(), descr.getText().trim(), name
-                     .getText().trim(), url.getText().trim(), urlsuff
-                     .getText().trim(), inputTypes, hSeparable.isSelected(),
+             (String) action.getSelectedItem(), descr.getText().trim(),
+             name.getText().trim(), url.getText().trim(),
+             urlsuff.getText().trim(), inputTypes, hSeparable.isSelected(),
              vSeparable.isSelected(), gc);
  
      if (newService.isValid())
          } catch (Throwable x)
          {
  
-           System.err
-                   .println("IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"
+           System.err.println(
+                   "IMPLEMENTATION PROBLEM: Cannot parse RestService output parameter string '"
                            + its + "'" + "\n" + warnings);
          }
        }
      }
      else
      {
-       System.err
-               .println("IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"
+       System.err.println(
+               "IMPLEMENTATION PROBLEM: Restservice generated from GUI is invalid\n"
                        + warnings);
  
      }
              }
              else
              {
-               parseRes.setText(MessageManager
-                       .formatMessage(
-                               "label.parsing_failed_syntax_errors_shown_below_param",
-                               new String[] { rsd.getInvalidMessage() }));
+               parseRes.setText(MessageManager.formatMessage(
+                       "label.parsing_failed_syntax_errors_shown_below_param",
+                       new String[]
+                       { rsd.getInvalidMessage() }));
                parseWarnings.setVisible(true);
              }
            } catch (Throwable e)
            {
              e.printStackTrace();
-             parseRes.setText(MessageManager
-                     .formatMessage(
-                             "label.parsing_failed_unrecoverable_exception_thrown_param",
-                             new String[] { e.toString() }));
+             parseRes.setText(MessageManager.formatMessage(
+                     "label.parsing_failed_unrecoverable_exception_thrown_param",
+                     new String[]
+                     { e.toString() }));
              parseWarnings.setVisible(true);
            }
          }
              final Thread runner = Thread.currentThread();
              JFrame df = new JFrame();
              df.getContentPane().setLayout(new BorderLayout());
 -            df.getContentPane().add((nulserv = !nulserv)
 -                    ? new RestServiceEditorPane(jalview.ws.rest.RestClient
 -                            .makeShmmrRestClient().getRestDescription())
 -                    : new RestServiceEditorPane(), BorderLayout.CENTER);
 +            df.getContentPane().add(
 +                    (nulserv = !nulserv) ? new RestServiceEditorPane(
 +                            jalview.ws.rest.clientdefs.ShmrRestClient
 +                                    .makeShmmrRestClient()
 +                                    .getRestDescription())
 +                            : new RestServiceEditorPane(),
 +                    BorderLayout.CENTER);
              df.setBounds(100, 100, 600, 400);
              df.addComponentListener(new ComponentListener()
              {
  
        }
      };
-     JPanel pane = new JPanel(new BorderLayout()), okcancel = new JPanel(
-             new FlowLayout());
+     JPanel pane = new JPanel(new BorderLayout()),
+             okcancel = new JPanel(new FlowLayout());
      pane.add(this, BorderLayout.CENTER);
      okcancel.add(jvd.ok);
      okcancel.add(jvd.cancel);
@@@ -27,6 -27,8 +27,8 @@@ import jalview.datamodel.Annotation
  import jalview.datamodel.GraphLine;
  import jalview.datamodel.SequenceCollectionI;
  import jalview.datamodel.SequenceI;
+ import jalview.renderer.AnnotationRenderer;
+ import jalview.util.Comparison;
  
  import java.awt.Color;
  import java.util.IdentityHashMap;
@@@ -34,31 -36,31 +36,41 @@@ import java.util.Map
  
  public class AnnotationColourGradient extends FollowerColourScheme
  {
 +  /**
 +   * map positional scores to transparency rather than colour
 +   */
 +  boolean positionToTransparency = true;
 +
 +  /**
 +   * compute shade based on annotation row score
 +   */
 +  boolean perLineScore = true;
 +
    public static final int NO_THRESHOLD = -1;
  
    public static final int BELOW_THRESHOLD = 0;
  
    public static final int ABOVE_THRESHOLD = 1;
  
-   public AlignmentAnnotation annotation;
+   private final AlignmentAnnotation annotation;
  
-   int aboveAnnotationThreshold = -1;
+   private final int aboveAnnotationThreshold;
  
    public boolean thresholdIsMinMax = false;
  
-   GraphLine annotationThreshold;
+   private GraphLine annotationThreshold;
  
-   float r1, g1, b1, rr, gg, bb;
+   private int redMin;
+   private int greenMin;
+   private int blueMin;
+   private int redRange;
+   private int greenRange;
+   private int blueRange;
  
    private boolean predefinedColours = false;
  
     */
    private boolean noGradient = false;
  
-   IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
+   private IdentityHashMap<SequenceI, AlignmentAnnotation> seqannot = null;
  
    @Override
-   public ColourSchemeI applyTo(AnnotatedCollectionI sg,
+   public ColourSchemeI getInstance(AnnotatedCollectionI sg,
            Map<SequenceI, SequenceCollectionI> hiddenRepSequences)
    {
      AnnotationColourGradient acg = new AnnotationColourGradient(annotation,
-             colourScheme, aboveAnnotationThreshold);
+             getColourScheme(), aboveAnnotationThreshold);
      acg.thresholdIsMinMax = thresholdIsMinMax;
      acg.annotationThreshold = (annotationThreshold == null) ? null
              : new GraphLine(annotationThreshold);
-     acg.r1 = r1;
-     acg.g1 = g1;
-     acg.b1 = b1;
-     acg.rr = rr;
-     acg.gg = gg;
-     acg.bb = bb;
+     acg.redMin = redMin;
+     acg.greenMin = greenMin;
+     acg.blueMin = blueMin;
+     acg.redRange = redRange;
+     acg.greenRange = greenRange;
+     acg.blueRange = blueRange;
      acg.predefinedColours = predefinedColours;
      acg.seqAssociated = seqAssociated;
      acg.noGradient = noGradient;
 +    acg.positionToTransparency = positionToTransparency;
 +    acg.perLineScore = perLineScore;
      return acg;
    }
  
    {
      if (originalColour instanceof AnnotationColourGradient)
      {
-       colourScheme = ((AnnotationColourGradient) originalColour).colourScheme;
+       setColourScheme(((AnnotationColourGradient) originalColour)
+               .getColourScheme());
      }
      else
      {
-       colourScheme = originalColour;
+       setColourScheme(originalColour);
      }
  
      this.annotation = annotation;
        annotationThreshold = annotation.threshold;
      }
      // clear values so we don't get weird black bands...
-     r1 = 254;
-     g1 = 254;
-     b1 = 254;
-     rr = 0;
-     gg = 0;
-     bb = 0;
+     redMin = 254;
+     greenMin = 254;
+     blueMin = 254;
+     redRange = 0;
+     greenRange = 0;
+     blueRange = 0;
  
      noGradient = true;
      checkLimits();
        annotationThreshold = annotation.threshold;
      }
  
-     r1 = minColour.getRed();
-     g1 = minColour.getGreen();
-     b1 = minColour.getBlue();
+     redMin = minColour.getRed();
+     greenMin = minColour.getGreen();
+     blueMin = minColour.getBlue();
  
-     rr = maxColour.getRed() - r1;
-     gg = maxColour.getGreen() - g1;
-     bb = maxColour.getBlue() - b1;
+     redRange = maxColour.getRed() - redMin;
+     greenRange = maxColour.getGreen() - greenMin;
+     blueRange = maxColour.getBlue() - blueMin;
  
      noGradient = false;
      checkLimits();
          seqannot = new IdentityHashMap<SequenceI, AlignmentAnnotation>();
        }
        // resolve the context containing all the annotation for the sequence
-       AnnotatedCollectionI alcontext = alignment instanceof AlignmentI ? alignment
+       AnnotatedCollectionI alcontext = alignment instanceof AlignmentI
+               ? alignment
                : alignment.getContext();
 -      boolean f = true, rna = false;
 -      for (AlignmentAnnotation alan : alcontext
 -              .findAnnotation(annotation.getCalcId()))
 +      boolean f = true, sf = true, rna = false;
 +      long plcount = 0, ancount = 0;
 +      for (AlignmentAnnotation alan : alcontext.findAnnotation(annotation
 +              .getCalcId()))
        {
          if (alan.sequenceRef != null
-                 && (alan.label != null && annotation != null && alan.label
-                         .equals(annotation.label)))
+                 && (alan.label != null && annotation != null
+                         && alan.label.equals(annotation.label)))
          {
 +          ancount++;
            if (!rna && alan.isRNA())
            {
              rna = true;
              aamin = alan.graphMin;
            }
            f = false;
 +          if (alan.score == alan.score)
 +          {
 +            if (sf || alan.score < plmin)
 +            {
 +              plmin = alan.score;
 +            }
 +            if (sf || alan.score > plmax)
 +            {
 +              plmax = alan.score;
 +            }
 +            sf = false;
 +            plcount++;
 +          }
          }
        }
 +      if (plcount > 0 && plcount == ancount)
 +      {
 +        perLineScore = plcount == ancount;
 +        aamax=plmax;
 +      }
        if (rna)
        {
          ColourSchemeProperty.initRnaHelicesShading(1 + (int) aamax);
      }
    }
  
 -  float aamin = 0f, aamax = 0f;
 +  /**
 +   * positional annotation max/min
 +   */
 +  double aamin = 0.0, aamax = 0.0;
 +
 +  /**
 +   * per line score max/min
 +   */
 +  double plmin = Double.NaN, plmax = Double.NaN;
  
-   public String getAnnotation()
+   public AlignmentAnnotation getAnnotation()
    {
-     return annotation.label;
+     return annotation;
    }
  
    public int getAboveThreshold()
  
    public Color getMinColour()
    {
-     return new Color((int) r1, (int) g1, (int) b1);
+     return new Color(redMin, greenMin, blueMin);
    }
  
    public Color getMaxColour()
    {
-     return new Color((int) (r1 + rr), (int) (g1 + gg), (int) (b1 + bb));
+     return new Color(redMin + redRange, greenMin + greenRange,
+             blueMin + blueRange);
    }
  
    /**
    }
  
    /**
-    * DOCUMENT ME!
+    * Returns the colour for a given character and position in a sequence
     * 
-    * @param n
-    *          DOCUMENT ME!
+    * @param c
+    *          the residue character
     * @param j
-    *          DOCUMENT ME!
-    * 
-    * @return DOCUMENT ME!
+    *          the aligned position
+    * @param seq
+    *          the sequence
+    * @return
     */
    @Override
    public Color findColour(char c, int j, SequenceI seq)
    {
-     Color currentColour = Color.white;
-     AlignmentAnnotation annotation = (seqAssociated && seqannot != null ? seqannot
-             .get(seq) : this.annotation);
-     if (annotation == null)
+     /*
+      * locate the annotation we are configured to colour by
+      */
+     AlignmentAnnotation ann = (seqAssociated && seqannot != null
+             ? seqannot.get(seq)
+             : this.annotation);
+     /*
+      * if gap or no annotation at position, no colour (White)
+      */
+     if (ann == null || ann.annotations == null
+             || j >= ann.annotations.length || ann.annotations[j] == null
+             || Comparison.isGap(c))
+     {
+       return Color.white;
+     }
+     Annotation aj = ann.annotations[j];
+     // 'use original colours' => colourScheme != null
+     // -> look up colour to be used
+     // predefined colours => preconfigured shading
+     // -> only use original colours reference if thresholding enabled &
+     // minmax exists
+     // annotation.hasIcons => null or black colours replaced with glyph
+     // colours
+     // -> reuse original colours if present
+     // -> if thresholding enabled then return colour on non-whitespace glyph
+     /*
+      * if threshold applies, and annotation fails the test - no colour (white)
+      */
+     if (annotationThreshold != null)
+     {
+       if ((aboveAnnotationThreshold == ABOVE_THRESHOLD
+               && aj.value < annotationThreshold.value)
+               || (aboveAnnotationThreshold == BELOW_THRESHOLD
+                       && aj.value > annotationThreshold.value))
+       {
+         return Color.white;
+       }
+     }
+     /*
+      * If 'use original colours' then return the colour of the annotation
+      * at the aligned position - computed using the background colour scheme
+      */
+     if (predefinedColours && aj.colour != null
+             && !aj.colour.equals(Color.black))
      {
-       return currentColour;
+       return aj.colour;
      }
-     if ((threshold == 0) || aboveThreshold(c, j))
+     Color result = Color.white;
+     if (ann.hasIcons && ann.graph == AlignmentAnnotation.NO_GRAPH)
      {
-       if (annotation.annotations != null
-               && j < annotation.annotations.length
-               && annotation.annotations[j] != null
-               && !jalview.util.Comparison.isGap(c))
+       /*
+        * secondary structure symbol colouring
+        */
+       if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
+               && aj.secondaryStructure != '-')
        {
-         Annotation aj = annotation.annotations[j];
-         // 'use original colours' => colourScheme != null
-         // -> look up colour to be used
-         // predefined colours => preconfigured shading
-         // -> only use original colours reference if thresholding enabled &
-         // minmax exists
-         // annotation.hasIcons => null or black colours replaced with glyph
-         // colours
-         // -> reuse original colours if present
-         // -> if thresholding enabled then return colour on non-whitespace glyph
-         if (aboveAnnotationThreshold == NO_THRESHOLD
-                 || (annotationThreshold != null && (aboveAnnotationThreshold == ABOVE_THRESHOLD ? aj.value >= annotationThreshold.value
-                         : aj.value <= annotationThreshold.value)))
+         if (getColourScheme() != null)
          {
-           if (predefinedColours && aj.colour != null
-                   && !aj.colour.equals(Color.black))
-           {
-             currentColour = aj.colour;
-           }
-           else if (annotation.hasIcons
-                   && annotation.graph == AlignmentAnnotation.NO_GRAPH)
-           {
-             if (aj.secondaryStructure > ' ' && aj.secondaryStructure != '.'
-                     && aj.secondaryStructure != '-')
-             {
-               if (colourScheme != null)
-               {
-                 currentColour = colourScheme.findColour(c, j, seq);
-               }
-               else
-               {
-                 if (annotation.isRNA())
-                 {
-                   currentColour = ColourSchemeProperty.rnaHelices[(int) aj.value];
-                 }
-                 else
-                 {
-                   currentColour = annotation.annotations[j].secondaryStructure == 'H' ? jalview.renderer.AnnotationRenderer.HELIX_COLOUR
-                           : annotation.annotations[j].secondaryStructure == 'E' ? jalview.renderer.AnnotationRenderer.SHEET_COLOUR
-                                   : jalview.renderer.AnnotationRenderer.STEM_COLOUR;
-                 }
-               }
-             }
-             else
-             {
-               //
-               return Color.white;
-             }
-           }
-           else if (noGradient)
+           result = getColourScheme().findColour(c, j, seq, null, 0f);
+         }
+         else
+         {
+           if (ann.isRNA())
            {
-             if (colourScheme != null)
-             {
-               currentColour = colourScheme.findColour(c, j, seq);
-             }
-             else
-             {
-               if (aj.colour != null)
-               {
-                 currentColour = aj.colour;
-               }
-             }
+             result = ColourSchemeProperty.rnaHelices[(int) aj.value];
            }
            else
            {
-             currentColour = shadeCalculation(annotation, j);
+             result = ann.annotations[j].secondaryStructure == 'H'
+                     ? AnnotationRenderer.HELIX_COLOUR
+                     : ann.annotations[j].secondaryStructure == 'E'
+                             ? AnnotationRenderer.SHEET_COLOUR
+                             : AnnotationRenderer.STEM_COLOUR;
            }
          }
-         if (conservationColouring)
+       }
+       else
+       {
+         return Color.white;
+       }
+     }
+     else if (noGradient)
+     {
+       if (getColourScheme() != null)
+       {
+         result = getColourScheme().findColour(c, j, seq, null, 0f);
+       }
+       else
+       {
+         if (aj.colour != null)
          {
-           currentColour = applyConservation(currentColour, j);
+           result = aj.colour;
          }
        }
      }
-     return currentColour;
+     else
+     {
+       result = shadeCalculation(ann, j);
+     }
+     return result;
    }
  
-   private Color shadeCalculation(AlignmentAnnotation annotation, int j)
+   /**
+    * Returns a graduated colour for the annotation at the given column. If there
+    * is a threshold value, and it is used as the top/bottom of the colour range,
+    * and the value satisfies the threshold condition, then a colour
+    * proportionate to the range from the threshold is calculated. For all other
+    * cases, a colour proportionate to the annotation's min-max range is
+    * calulated. Note that thresholding is _not_ done here (a colour is computed
+    * even if threshold is not passed).
+    * 
+    * @param ann
+    * @param col
+    * @return
+    */
+   Color shadeCalculation(AlignmentAnnotation ann, int col)
    {
-     // calculate a shade
      float range = 1f;
-     if (thresholdIsMinMax
-             && annotation.threshold != null
+     float value = ann.annotations[col].value;
+     if (thresholdIsMinMax && ann.threshold != null
              && aboveAnnotationThreshold == ABOVE_THRESHOLD
-             && annotation.annotations[j].value >= annotation.threshold.value)
+             && value >= ann.threshold.value)
      {
-       range = (annotation.annotations[j].value - annotation.threshold.value)
-               / (annotation.graphMax - annotation.threshold.value);
+       range = (value - ann.threshold.value)
+               / (ann.graphMax - ann.threshold.value);
      }
-     else if (thresholdIsMinMax && annotation.threshold != null
+     else if (thresholdIsMinMax && ann.threshold != null
              && aboveAnnotationThreshold == BELOW_THRESHOLD
-             && annotation.annotations[j].value >= annotation.graphMin)
+             && value <= ann.threshold.value)
      {
-       range = (annotation.annotations[j].value - annotation.graphMin)
-               / (annotation.threshold.value - annotation.graphMin);
+       range = (value - ann.graphMin) / (ann.threshold.value - ann.graphMin);
      }
      else
      {
-       if (annotation.graphMax != annotation.graphMin)
+       if (ann.graphMax != ann.graphMin)
        {
-         range = (annotation.annotations[j].value - annotation.graphMin)
-                 / (annotation.graphMax - annotation.graphMin);
+         range = (value - ann.graphMin) / (ann.graphMax - ann.graphMin);
        }
        else
        {
          range = 0f;
        }
      }
 -    int dr = (int) (redRange * range + redMin);
 -    int dg = (int) (greenRange * range + greenMin);
 -    int db = (int) (blueRange * range + blueMin);
 -
 -    return new Color(dr, dg, db);
 +    // midtr sets the ceiling for bleaching out the shading
 +    int trans = 0, midtr = 239;
 +    if (perLineScore)
 +    {
 +      trans = (int) ((1f - range) * midtr);
 +      range = (float) ((annotation.score - plmin) / (plmax - aamin));
 +    }
 +    int dr = (int) (rr * range + r1), dg = (int) (gg * range + g1), db = (int) (bb
 +            * range + b1);
 +    if (annotation.score == annotation.score && positionToTransparency)
 +    {
 +      return new Color(Math.min(dr + trans, midtr), Math.min(dg
 +              + trans, midtr), Math.min(db + trans, midtr));
 +    }
 +    else
 +    {
 +      return new Color(dr, dg, db);
 +    }
    }
  
    public boolean isPredefinedColours()
    {
      seqAssociated = sassoc;
    }
+   public boolean isThresholdIsMinMax()
+   {
+     return thresholdIsMinMax;
+   }
+   public void setThresholdIsMinMax(boolean minMax)
+   {
+     this.thresholdIsMinMax = minMax;
+   }
+   @Override
+   public String getSchemeName()
+   {
+     return "Annotation";
+   }
+   @Override
+   public boolean isSimple()
+   {
+     return false;
+   }
  }
@@@ -34,14 -34,15 +34,15 @@@ public class Compariso
  
    private static final int TO_UPPER_CASE = 'a' - 'A';
  
-   private static final char GAP_SPACE = ' ';
+   public static final char GAP_SPACE = ' ';
  
-   private static final char GAP_DOT = '.';
+   public static final char GAP_DOT = '.';
  
-   private static final char GAP_DASH = '-';
+   public static final char GAP_DASH = '-';
  
-   public static final String GapChars = new String(new char[] { GAP_SPACE,
-       GAP_DOT, GAP_DASH });
+   public static final String GapChars = new String(
+           new char[]
+           { GAP_SPACE, GAP_DOT, GAP_DASH });
  
    /**
     * DOCUMENT ME!
@@@ -71,7 -72,8 +72,8 @@@
     *          int
     * @return float
     */
-   public static float compare(SequenceI ii, SequenceI jj, int start, int end)
+   public static float compare(SequenceI ii, SequenceI jj, int start,
+           int end)
    {
      String si = ii.getSequenceAsString();
      String sj = jj.getSequenceAsString();
@@@ -97,8 -99,8 +99,8 @@@
      {
        for (int j = 0; j < jlen; j++)
        {
-         if (si.substring(start + j, start + j + 1).equals(
-                 sj.substring(start + j, start + j + 1)))
+         if (si.substring(start + j, start + j + 1)
+                 .equals(sj.substring(start + j, start + j + 1)))
          {
            match++;
          }
      {
        for (int j = 0; j < jlen; j++)
        {
-         if (si.substring(start + j, start + j + 1).equals(
-                 sj.substring(start + j, start + j + 1)))
+         if (si.substring(start + j, start + j + 1)
+                 .equals(sj.substring(start + j, start + j + 1)))
          {
            match++;
          }
     * @param s2
     *          SequenceI
     * @return float
+    * @deprecated use PIDModel.computePID()
     */
+   @Deprecated
    public final static float PID(String seq1, String seq2)
    {
      return PID(seq1, seq2, 0, seq1.length());
    static final int caseShift = 'a' - 'A';
  
    // Another pid with region specification
-   public final static float PID(String seq1, String seq2, int start, int end)
+   /**
+    * @deprecated use PIDModel.computePID()
+    */
+   @Deprecated
+   public final static float PID(String seq1, String seq2, int start,
+           int end)
    {
      return PID(seq1, seq2, start, end, true, false);
    }
     * @param ungappedOnly
     *          - if true - only count PID over ungapped columns
     * @return
+    * @deprecated use PIDModel.computePID()
     */
+   @Deprecated
    public final static float PID(String seq1, String seq2, int start,
            int end, boolean wcGaps, boolean ungappedOnly)
    {
     */
    public static final boolean isGap(char c)
    {
 -    return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE) ? true : false;
 +    return (c == GAP_DASH || c == GAP_DOT || c == GAP_SPACE);
    }
  
    /**
      {
        return false;
      }
-     char[][] letters = new char[seqs.length][];
-     for (int i = 0; i < seqs.length; i++)
-     {
-       if (seqs[i] != null)
-       {
-         char[] sequence = seqs[i].getSequence();
-         if (sequence != null)
-         {
-           letters[i] = sequence;
-         }
-       }
-     }
  
-     return areNucleotide(letters);
-   }
-   /**
-    * Answers true if more than 85% of the sequence residues (ignoring gaps) are
-    * A, G, C, T or U, else false. This is just a heuristic guess and may give a
-    * wrong answer (as AGCT are also amino acid codes).
-    * 
-    * @param letters
-    * @return
-    */
-   static final boolean areNucleotide(char[][] letters)
-   {
      int ntCount = 0;
      int aaCount = 0;
-     for (char[] seq : letters)
+     for (SequenceI seq : seqs)
      {
        if (seq == null)
        {
        }
        // TODO could possibly make an informed guess just from the first sequence
        // to save a lengthy calculation
-       for (char c : seq)
+       int len = seq.getLength();
+       for (int i = 0; i < len; i++)
        {
+         char c = seq.getCharAt(i);
          if (isNucleotide(c))
          {
            ntCount++;
          flattened.add(s);
        }
      }
-     final SequenceI[] oneDArray = flattened.toArray(new SequenceI[flattened
-             .size()]);
+     final SequenceI[] oneDArray = flattened
+             .toArray(new SequenceI[flattened.size()]);
      return isNucleotide(oneDArray);
    }
  
@@@ -28,14 -28,15 +28,14 @@@ import jalview.gui.AlignmentPanel
  import jalview.gui.Desktop;
  import jalview.gui.JvOptionPane;
  import jalview.gui.WebserviceInfo;
 -import jalview.io.packed.DataProvider.JvDataType;
  import jalview.util.MessageManager;
  import jalview.ws.WSClient;
  import jalview.ws.WSClientI;
  import jalview.ws.WSMenuEntryProviderI;
 +import jalview.ws.rest.clientdefs.ShmrRestClient;
  
  import java.awt.event.ActionEvent;
  import java.awt.event.ActionListener;
 -import java.util.Hashtable;
  import java.util.Vector;
  
  import javax.swing.JMenu;
@@@ -47,8 -48,8 +47,8 @@@ import javax.swing.event.MenuListener
   * @author JimP
   * 
   */
- public class RestClient extends WSClient implements WSClientI,
-         WSMenuEntryProviderI
+ public class RestClient extends WSClient
+         implements WSClientI, WSMenuEntryProviderI
  {
    RestServiceDescription service;
  
@@@ -96,9 -97,9 +96,9 @@@
  
    public void setWebserviceInfo(boolean headless)
    {
-     WebServiceJobTitle = MessageManager.formatMessage(
-             "label.webservice_job_title", new String[] {
-                 service.details.Action, service.details.Name });
+     WebServiceJobTitle = MessageManager
+             .formatMessage("label.webservice_job_title", new String[]
+             { service.details.Action, service.details.Name });
      WebServiceName = service.details.Name;
      WebServiceReference = "No reference - go to url for more info";
      if (service.details.description != null)
      }
      if (!headless)
      {
-       wsInfo = new WebserviceInfo(WebServiceJobTitle, WebServiceName + "\n"
-               + WebServiceReference, true);
+       wsInfo = new WebserviceInfo(WebServiceJobTitle,
+               WebServiceName + "\n" + WebServiceReference, true);
        wsInfo.setRenderAsHtml(true);
      }
  
            final AlignFrame alignFrame)
    {
      JMenuItem submit = new JMenuItem(service.details.Name);
-     submit.setToolTipText(MessageManager.formatMessage(
-             "label.rest_client_submit", new String[] {
-                 service.details.Action, service.details.Name }));
+     submit.setToolTipText(MessageManager
+             .formatMessage("label.rest_client_submit", new String[]
+             { service.details.Action, service.details.Name }));
      submit.addActionListener(new ActionListener()
      {
  
          {
            // intersect groups with selected region
            _input = new AlignmentView(av.getAlignment(),
-                   av.getColumnSelection(), av.getSelectionGroup(),
-                   av.hasHiddenColumns(), true, true);
+                   av.getAlignment().getHiddenColumns(),
+                   av.getSelectionGroup(), av.hasHiddenColumns(), true,
+                   true);
            viewTitle = MessageManager.formatMessage(
-                   "label.select_visible_region_of",
-                   new String[] {
-                       (av.hasHiddenColumns() ? MessageManager
-                               .getString("label.visible") : ""),
+                   "label.select_visible_region_of", new String[]
+                   { (av.hasHiddenColumns()
+                           ? MessageManager.getString("label.visible")
+                           : ""),
                        af.getTitle() });
          }
          else
          {
            // use selected region to partition alignment
            _input = new AlignmentView(av.getAlignment(),
-                   av.getColumnSelection(), av.getSelectionGroup(),
-                   av.hasHiddenColumns(), false, true);
+                   av.getAlignment().getHiddenColumns(),
+                   av.getSelectionGroup(), av.hasHiddenColumns(), false,
+                   true);
          }
          viewTitle = MessageManager.formatMessage(
-                 "label.select_unselect_visible_regions_from",
-                 new String[] {
-                     (av.hasHiddenColumns() ? MessageManager
-                             .getString("label.visible") : ""),
+                 "label.select_unselect_visible_regions_from", new String[]
+                 { (av.hasHiddenColumns()
+                         ? MessageManager.getString("label.visible")
+                         : ""),
                      af.getTitle() });
        }
        else
        {
          // just take selected region intersection
          _input = new AlignmentView(av.getAlignment(),
-                 av.getColumnSelection(), av.getSelectionGroup(),
-                 av.hasHiddenColumns(), true, true);
+                 av.getAlignment().getHiddenColumns(),
+                 av.getSelectionGroup(), av.hasHiddenColumns(), true, true);
          viewTitle = MessageManager.formatMessage(
-                 "label.select_visible_region_of",
-                 new String[] {
-                     (av.hasHiddenColumns() ? MessageManager
-                             .getString("label.visible") : ""),
+                 "label.select_visible_region_of", new String[]
+                 { (av.hasHiddenColumns()
+                         ? MessageManager.getString("label.visible")
+                         : ""),
                      af.getTitle() });
        }
      }
      {
        // standard alignment view without selection present
        _input = new AlignmentView(av.getAlignment(),
-               av.getColumnSelection(), null, av.hasHiddenColumns(), false,
-               true);
+               av.getAlignment().getHiddenColumns(), null,
+               av.hasHiddenColumns(), false, true);
        viewTitle = ""
-               + (av.hasHiddenColumns() ? (new StringBuffer(" ")
-                       .append(MessageManager
-                               .getString("label.visible_region_of"))
-                       .toString()) : "") + af.getTitle();
+               + (av.hasHiddenColumns()
+                       ? (new StringBuffer(" ")
+                               .append(MessageManager
+                                       .getString("label.visible_region_of"))
+                               .toString())
+                       : "")
+               + af.getTitle();
      }
  
      RestJobThread jobsthread = new RestJobThread(this);
      else
      {
        // TODO: try to tell the user why the job couldn't be started.
-       JvOptionPane
-               .showMessageDialog(
-                       Desktop.desktop,
-                       (jobsthread.hasWarnings() ? jobsthread.getWarnings()
-                               : MessageManager
-                                       .getString("label.job_couldnt_be_started_check_input")),
-                       MessageManager
-                               .getString("label.unable_start_web_service_analysis"),
-                       JvOptionPane.WARNING_MESSAGE);
+       JvOptionPane.showMessageDialog(Desktop.desktop,
+               (jobsthread.hasWarnings() ? jobsthread.getWarnings()
+                       : MessageManager.getString(
+                               "label.job_couldnt_be_started_check_input")),
+               MessageManager
+                       .getString("label.unable_start_web_service_analysis"),
+               JvOptionPane.WARNING_MESSAGE);
      }
    }
  
 -  public static RestClient makeShmmrRestClient()
 -  {
 -    String action = "Analysis",
 -            description = "Sequence Harmony and Multi-Relief (Brandt et al. 2010)",
 -            name = MessageManager.getString("label.multiharmony");
 -    Hashtable<String, InputType> iparams = new Hashtable<String, InputType>();
 -    jalview.ws.rest.params.JobConstant toolp;
 -    // toolp = new jalview.ws.rest.JobConstant("tool","jalview");
 -    // iparams.put(toolp.token, toolp);
 -    // toolp = new jalview.ws.rest.params.JobConstant("mbjob[method]","shmr");
 -    // iparams.put(toolp.token, toolp);
 -    // toolp = new
 -    // jalview.ws.rest.params.JobConstant("mbjob[description]","step 1");
 -    // iparams.put(toolp.token, toolp);
 -    // toolp = new jalview.ws.rest.params.JobConstant("start_search","1");
 -    // iparams.put(toolp.token, toolp);
 -    // toolp = new jalview.ws.rest.params.JobConstant("blast","0");
 -    // iparams.put(toolp.token, toolp);
 -
 -    jalview.ws.rest.params.Alignment aliinput = new jalview.ws.rest.params.Alignment();
 -    // SHMR server has a 65K limit for content pasted into the 'ali' parameter,
 -    // so we always upload our files.
 -    aliinput.token = "ali_file";
 -    aliinput.writeAsFile = true;
 -    iparams.put(aliinput.token, aliinput);
 -    jalview.ws.rest.params.SeqGroupIndexVector sgroups = new jalview.ws.rest.params.SeqGroupIndexVector();
 -    sgroups.setMinsize(2);
 -    sgroups.min = 2;// need at least two group defined to make a partition
 -    iparams.put("groups", sgroups);
 -    sgroups.token = "groups";
 -    sgroups.sep = " ";
 -    RestServiceDescription shmrService = new RestServiceDescription(action,
 -            description, name,
 -            "http://zeus.few.vu.nl/programs/shmrwww/index.php?tool=jalview", // ?tool=jalview&mbjob[method]=shmr&mbjob[description]=step1",
 -            "?tool=jalview", iparams, true, false, '-');
 -    // a priori knowledge of the data returned from the service
 -    shmrService.addResultDatatype(JvDataType.ANNOTATION);
 -    return new RestClient(shmrService);
 -  }
 -
    public AlignmentPanel recoverAlignPanelForView()
    {
      AlignmentPanel[] aps = Desktop
        try
        {
          for (RestServiceDescription descr : RestServiceDescription
 -                .parseDescriptions(
 -                        jalview.bin.Cache.getDefault(RSBS_SERVICES,
 -                                makeShmmrRestClient().service.toString())))
 +                .parseDescriptions(jalview.bin.Cache.getDefault(
 +                        RSBS_SERVICES,
 +                        ShmrRestClient.makeShmmrRestClient().service.toString())))
          {
            services.add(descr.toString());
          }
        } catch (Exception ex)
        {
-         System.err
-                 .println("Serious - RSBS descriptions in user preferences are corrupt!");
+         System.err.println(
+                 "Serious - RSBS descriptions in user preferences are corrupt!");
          ex.printStackTrace();
        }
  
@@@ -26,7 -26,7 +26,7 @@@ import jalview.datamodel.AlignmentAnnot
  import jalview.datamodel.AlignmentI;
  import jalview.datamodel.AlignmentOrder;
  import jalview.datamodel.Annotation;
- import jalview.datamodel.ColumnSelection;
+ import jalview.datamodel.HiddenColumns;
  import jalview.datamodel.SequenceGroup;
  import jalview.datamodel.SequenceI;
  import jalview.gui.AlignFrame;
@@@ -59,6 -59,8 +59,6 @@@ import org.apache.http.client.methods.H
  import org.apache.http.entity.mime.HttpMultipartMode;
  import org.apache.http.entity.mime.MultipartEntity;
  import org.apache.http.impl.client.DefaultHttpClient;
 -import org.apache.http.protocol.BasicHttpContext;
 -import org.apache.http.protocol.HttpContext;
  import org.apache.http.util.EntityUtils;
  
  public class RestJobThread extends AWSThread
@@@ -88,8 -90,8 +88,8 @@@
      {
        jobs = new RestJob[1];
        jobs[0] = new RestJob(0, this,
-               restClient._input.getVisibleAlignment(restClient.service
-                       .getGapCharacter()),
+               restClient._input.getVisibleAlignment(
+                       restClient.service.getGapCharacter()),
                restClient._input.getVisibleContigs());
        // need a function to get a range on a view/alignment and return both
        // annotation, groups and selection subsetted to just that region.
      {
        int[] viscontig = restClient._input.getVisibleContigs();
        AlignmentI[] viscontigals = restClient._input
-               .getVisibleContigAlignments(restClient.service
-                       .getGapCharacter());
+               .getVisibleContigAlignments(
+                       restClient.service.getGapCharacter());
        if (viscontigals != null && viscontigals.length > 0)
        {
          jobs = new RestJob[viscontigals.length];
    protected void doHttpReq(Stage stg, RestJob rj, String postUrl)
            throws Exception
    {
 -    StringBuffer respText = new StringBuffer();
 -    // con.setContentHandlerFactory(new
 -    // jalview.ws.io.mime.HttpContentHandler());
      HttpRequestBase request = null;
      String messages = "";
      if (stg == Stage.SUBMIT)
        {
          if (input.getValue().validFor(rj))
          {
-           postentity.addPart(input.getKey(), input.getValue()
-                   .formatForInput(rj));
+           postentity.addPart(input.getKey(),
+                   input.getValue().formatForInput(rj));
          }
          else
          {
      {
        DefaultHttpClient httpclient = new DefaultHttpClient();
  
 -      HttpContext localContext = new BasicHttpContext();
        HttpResponse response = null;
        try
        {
          Cache.log.debug("Processing result set.");
          processResultSet(rj, response, request);
          break;
 +
        case 202:
 -        rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
 -                + "<a href=" + rj.getJobId() + "\">" + rj.getJobId()
 -                + "</a><br>";
 -        rj.running = true;
 +        markJobAsRunning(rj);
          break;
 +
 +      case 201:
 +        // Created - redirect may be present. Fallthrough to 302
        case 302:
 -        Header[] loc;
 -        if (!rj.isSubmitted()
 -                && (loc = response
 -                        .getHeaders(HTTPConstants.HEADER_LOCATION)) != null
 -                && loc.length > 0)
 -        {
 -          if (loc.length > 1)
 -          {
 -            Cache.log.warn("Ignoring additional " + (loc.length - 1)
 -                    + " location(s) provided in response header ( next one is '"
 -                    + loc[1].getValue() + "' )");
 -          }
 -          rj.setJobId(loc[0].getValue());
 -          rj.setSubmitted(true);
 -        }
 +        extractJobId(rj, response);
          completeStatus(rj, response);
          break;
        case 500:
 -        // Failed.
 -        rj.setSubmitted(true);
 -        rj.setAllowedServerExceptions(0);
 -        rj.setSubjobComplete(true);
 -        rj.error = true;
 -        rj.running = false;
 -        completeStatus(rj, response,
 -                "" + getStage(stg) + "failed. Reason below:\n");
 +        markAsFailed(rj, response);
 +        completeStatus(rj, response, "" + getStage(stg)
 +                + "failed. Reason below:\n");
          break;
        default:
          // Some other response. Probably need to pop up the content in a window.
          rj.setSubmitted(true);
          try
          {
-           completeStatus(
-                   rj,
-                   response,
-                   ""
-                           + getStage(stg)
-                           + " resulted in an unexpected server response.<br/>Url concerned was <a href=\""
-                           + request.getURI()
-                           + "\">"
-                           + request.getURI()
-                           + "</a><br/>Filtered response content below:<br/>");
+           completeStatus(rj, response, "" + getStage(stg)
+                   + " resulted in an unexpected server response.<br/>Url concerned was <a href=\""
+                   + request.getURI() + "\">" + request.getURI()
+                   + "</a><br/>Filtered response content below:<br/>");
          } catch (IOException e)
          {
            Cache.log.debug("IOException when consuming unhandled response",
      }
    }
  
 +  private void markAsFailed(RestJob rj, HttpResponse response)
 +  {
 +    // Failed.
 +    rj.setSubmitted(true);
 +    rj.setAllowedServerExceptions(0);
 +    rj.setSubjobComplete(true);
 +    rj.error = true;
 +    rj.running = false;
 +  }
 +
 +  /**
 +   * set the jobRunning flag and post a link to the physical result page encoded
 +   * in rj.getJobId()
 +   * 
 +   * @param rj
 +   */
 +  private void markJobAsRunning(RestJob rj)
 +  {
 +    rj.statMessage = "<br>Job submitted successfully. Results available at this URL:\n"
 +            + "<a href="
 +            + rj.getJobId()
 +            + "\">"
 +            + rj.getJobId()
 +            + "</a><br>";
 +    rj.running = true;
 +  }
 +
 +  /**
 +   * extract the job ID URL from the redirect page. Does nothing if job is
 +   * already running.
 +   * 
 +   * @param rj
 +   * @param response
 +   */
 +  private void extractJobId(RestJob rj, HttpResponse response)
 +  {
 +    Header[] loc;
 +    if (!rj.isSubmitted())
 +    {
 +
 +      // redirect URL - typical for IBIVU type jobs.
 +      if ((loc = response.getHeaders(HTTPConstants.HEADER_LOCATION)) != null
 +              && loc.length > 0)
 +      {
 +        if (loc.length > 1)
 +        {
 +          Cache.log
 +                  .warn("Ignoring additional "
 +                          + (loc.length - 1)
 +                          + " location(s) provided in response header ( next one is '"
 +                          + loc[1].getValue() + "' )");
 +        }
 +        rj.setJobId(loc[0].getValue());
 +        rj.setSubmitted(true);
 +      }
 +    }
 +  }
 +
    /**
     * job has completed. Something valid should be available from con
     * 
  
          } catch (Error ex)
          {
-           Cache.log.warn("Failed to finish parsing data for job "
-                   + rj.getJobId());
+           Cache.log.warn(
+                   "Failed to finish parsing data for job " + rj.getJobId());
            ex.printStackTrace();
          } catch (Exception ex)
          {
-           Cache.log.warn("Failed to finish parsing data for job "
-                   + rj.getJobId());
+           Cache.log.warn(
+                   "Failed to finish parsing data for job " + rj.getJobId());
            ex.printStackTrace();
          } finally
          {
            rj.error = true;
            rj.statMessage = "Error whilst parsing data for this job.<br>URL for job response is :<a href=\""
-                   + rj.resSet.getUrl()
-                   + "\">"
-                   + rj.resSet.getUrl()
+                   + rj.resSet.getUrl() + "\">" + rj.resSet.getUrl()
                    + "</a><br>";
          }
        }
      // total number of distinct alignment sets generated by job set.
      int numAlSets = 0, als = 0;
      List<AlignmentI> destAls = new ArrayList<AlignmentI>();
-     List<jalview.datamodel.ColumnSelection> destColsel = new ArrayList<jalview.datamodel.ColumnSelection>();
+     List<jalview.datamodel.HiddenColumns> destColsel = new ArrayList<jalview.datamodel.HiddenColumns>();
      List<List<NewickFile>> trees = new ArrayList<List<NewickFile>>();
  
      do
            RestJob rj = (RestJob) jobs[nrj];
            int contigs[] = input.getVisibleContigs();
            AlignmentI destAl = null;
-           jalview.datamodel.ColumnSelection destCs = null;
+           jalview.datamodel.HiddenColumns destHCs = null;
            // Resolve destAl for this data.
            if (als == 0 && rj.isInputContextModified())
            {
                if (!restClient.isAlignmentModified() && merge)
                {
                  destAl = restClient.av.getAlignment();
-                 destCs = restClient.av.getColumnSelection();
-                 resultDest
-                         .add(restClient.isShowResultsInNewView() ? AddDataTo.newView
-                                 : AddDataTo.currentView);
+                 destHCs = restClient.av.getAlignment().getHiddenColumns();
+                 resultDest.add(restClient.isShowResultsInNewView()
+                         ? AddDataTo.newView
+                         : AddDataTo.currentView);
                  destPanels.add(restClient.recoverAlignPanelForView());
                }
                else
                  newAlignment = true;
                  // recreate the input alignment data
                  Object[] idat = input
-                         .getAlignmentAndColumnSelection(gapCharacter);
+                         .getAlignmentAndHiddenColumns(gapCharacter);
                  destAl = new Alignment((SequenceI[]) idat[0]);
-                 destCs = (ColumnSelection) idat[1];
+                 destHCs = (HiddenColumns) idat[1];
                  resultDest.add(AddDataTo.newAlignment);
                  // but do not add to the alignment panel list - since we need to
                  // create a whole new alignFrame set.
                }
                destAls.add(destAl);
-               destColsel.add(destCs);
+               destColsel.add(destHCs);
              }
            }
            else
                {
                  // TODO: decide if multiple multiple alignments returned by
                  // non-vseparable services are allowed.
-                 Cache.log
-                         .warn("dealing with multiple alignment products returned by non-vertically separable service.");
+                 Cache.log.warn(
+                         "dealing with multiple alignment products returned by non-vertically separable service.");
                }
                // recover reference to last alignment created for this rest frame
                // ready for extension
                destAl = destAls.get(als);
-               destCs = destColsel.get(als);
+               destHCs = destColsel.get(als);
              }
              else
              {
                  newview = input.getUpdatedView(rseqs, orders, gapCharacter);
                }
                destAl = new Alignment((SequenceI[]) newview[0]);
-               destCs = (ColumnSelection) newview[1];
+               destHCs = (HiddenColumns) newview[1];
                newAlignment = true;
                // TODO create alignment from result data with propagated
                // references.
                destAls.add(destAl);
-               destColsel.add(destCs);
+               destColsel.add(destHCs);
                resultDest.add(AddDataTo.newAlignment);
                throw new Error(
-                       MessageManager
-                               .getString("error.implementation_error")
+                       MessageManager.getString("error.implementation_error")
                                + "TODO: ");
              }
            }
                      }
                      else
                      {
-                       Cache.log
-                               .warn("Couldn't resolve original sequence for new sequence.");
+                       Cache.log.warn(
+                               "Couldn't resolve original sequence for new sequence.");
                      }
                    }
                    if (sg.hasSeqrep())
                  {
                    // adjust boundaries of recovered group w.r.t. new group being
                    // merged on to original alignment.
-                   int start = sg.getStartRes() + contigs[ncnt], end = sg
-                           .getEndRes() + contigs[ncnt];
+                   int start = sg.getStartRes() + contigs[ncnt],
+                           end = sg.getEndRes() + contigs[ncnt];
                    if (start < exsg.getStartRes())
                    {
                      exsg.setStartRes(start);
                    grass = groupNames.get(alan[nrj][an].groupRef.getName());
                    if (grass == null)
                    {
-                     Cache.log
-                             .error("Couldn't relocate group referemce for group "
+                     Cache.log.error(
+                             "Couldn't relocate group referemce for group "
                                      + alan[nrj][an].groupRef.getName());
                    }
                  }
                    visan.sequenceRef = sqass;
                    visAlAn.add(visan);
                  }
-                 if (contigs[ncnt] + alan[nrj][an].annotations.length > visan.annotations.length)
+                 if (contigs[ncnt]
+                         + alan[nrj][an].annotations.length > visan.annotations.length)
                  {
                    // increase width of annotation row
                    Annotation[] newannv = new Annotation[contigs[ncnt]
                {
                  // TODO: process each newick file, lifting over sequence refs to
                  // current alignment, if necessary.
-                 Cache.log
-                         .error("Tree recovery from restjob not yet implemented.");
+                 Cache.log.error(
+                         "Tree recovery from restjob not yet implemented.");
                }
              }
            }
      for (AddDataTo action : resultDest)
      {
        AlignmentI destal;
-       ColumnSelection destcs;
-       String alTitle = MessageManager.formatMessage(
-               "label.webservice_job_title_on", new String[] {
-                   restClient.service.details.Action,
+       HiddenColumns destcs;
+       String alTitle = MessageManager
+               .formatMessage("label.webservice_job_title_on", new String[]
+               { restClient.service.details.Action,
                    restClient.service.details.Name, restClient.viewTitle });
        switch (action)
        {
          destcs = destColsel.get(als);
          destaf = new AlignFrame(destal, destcs, AlignFrame.DEFAULT_WIDTH,
                  AlignFrame.DEFAULT_HEIGHT);
-         PaintRefresher.Refresh(destaf, destaf.getViewport()
-                 .getSequenceSetId());
+         PaintRefresher.Refresh(destaf,
+                 destaf.getViewport().getSequenceSetId());
          // todo transfer any feature settings and colouring
          /*
           * destaf.getFeatureRenderer().transferSettings(this.featureSettings);
            {
              if (start + width < end)
              {
-               blocks[c][s] = sequenceIs[s].getSubSequence(start, start
-                       + width);
+               blocks[c][s] = sequenceIs[s].getSubSequence(start,
+                       start + width);
              }
              else
              {