JAL-2371 CollectionColourScheme renamed ResidueShader and moved to
[jalview.git] / src / jalview / datamodel / SequenceGroup.java
index dec4fa4..a1579c5 100755 (executable)
@@ -1,6 +1,6 @@
 /*
- * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8.2b1)
- * 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.
  * 
@@ -22,15 +22,14 @@ package jalview.datamodel;
 
 import jalview.analysis.AAFrequency;
 import jalview.analysis.Conservation;
+import jalview.renderer.ResidueShader;
+import jalview.renderer.ResidueShaderI;
 import jalview.schemes.ColourSchemeI;
-import jalview.schemes.ResidueProperties;
 
 import java.awt.Color;
 import java.util.ArrayList;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Map;
-import java.util.Vector;
 
 /**
  * Collects a set contiguous ranges on a set of sequences
@@ -46,8 +45,6 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   Conservation conserve;
 
-  Vector aaFrequency;
-
   boolean displayBoxes = true;
 
   boolean displayText = true;
@@ -74,10 +71,12 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * Colourscheme applied to group if any
    */
-  public ColourSchemeI cs;
+  public ResidueShaderI cs;
 
+  // start column (base 0)
   int startRes = 0;
 
+  // end column (base 0)
   int endRes = 0;
 
   public Color outlineColour = Color.black;
@@ -119,6 +118,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   public SequenceGroup()
   {
     groupName = "JGroup:" + this.hashCode();
+    cs = new ResidueShader();
   }
 
   /**
@@ -139,12 +139,13 @@ public class SequenceGroup implements AnnotatedCollectionI
           ColourSchemeI scheme, boolean displayBoxes, boolean displayText,
           boolean colourText, int start, int end)
   {
+    this();
     this.sequences = sequences;
     this.groupName = groupName;
     this.displayBoxes = displayBoxes;
     this.displayText = displayText;
     this.colourText = colourText;
-    this.cs = scheme;
+    this.cs = new ResidueShader(scheme);
     startRes = start;
     endRes = end;
     recalcConservation();
@@ -157,6 +158,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public SequenceGroup(SequenceGroup seqsel)
   {
+    this();
     if (seqsel != null)
     {
       sequences = new ArrayList<SequenceI>();
@@ -207,7 +209,7 @@ public class SequenceGroup implements AnnotatedCollectionI
       if (seqs[ipos] != null)
       {
         seqs[ipos].setDescription(seq.getDescription());
-        seqs[ipos].setDBRef(seq.getDBRef());
+        seqs[ipos].setDBRefs(seq.getDBRefs());
         seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
         if (seq.getDatasetSequence() != null)
         {
@@ -502,32 +504,51 @@ public class SequenceGroup implements AnnotatedCollectionI
   }
 
   /**
-   * calculate residue conservation for group - but only if necessary.
+   * calculate residue conservation and colourschemes for group - but only if
+   * necessary. returns true if the calculation resulted in a visible change to
+   * group
+   */
+  public boolean recalcConservation()
+  {
+    return recalcConservation(false);
+  }
+
+  /**
+   * calculate residue conservation for group - but only if necessary. returns
+   * true if the calculation resulted in a visible change to group
+   * 
+   * @param defer
+   *          when set, colourschemes for this group are not refreshed after
+   *          recalculation
    */
-  public void recalcConservation()
+  public boolean recalcConservation(boolean defer)
   {
     if (cs == null && consensus == null && conservation == null)
     {
-      return;
+      return false;
     }
+    // TODO: try harder to detect changes in state in order to minimise
+    // recalculation effort
+    boolean upd = false;
     try
     {
-      Hashtable cnsns[] = AAFrequency.calculate(sequences, startRes,
+      ProfilesI cnsns = AAFrequency.calculate(sequences, startRes,
               endRes + 1, showSequenceLogo);
       if (consensus != null)
       {
         _updateConsensusRow(cnsns, sequences.size());
+        upd = true;
       }
       if (cs != null)
       {
         cs.setConsensus(cnsns);
+        upd = true;
       }
 
       if ((conservation != null)
               || (cs != null && cs.conservationApplied()))
       {
-        Conservation c = new Conservation(groupName,
-                ResidueProperties.propHash, 3, sequences, startRes,
+        Conservation c = new Conservation(groupName, sequences, startRes,
                 endRes + 1);
         c.calculate();
         c.verdict(false, consPercGaps);
@@ -542,17 +563,25 @@ public class SequenceGroup implements AnnotatedCollectionI
             cs.setConservation(c);
           }
         }
+        // eager update - will cause a refresh of overview regardless
+        upd = true;
       }
-      if (cs != null)
+      if (cs != null && !defer)
       {
+        // TODO: JAL-2034 should cs.alignmentChanged modify return state
         cs.alignmentChanged(context != null ? context : this, null);
+        return true;
+      }
+      else
+      {
+        return upd;
       }
     } catch (java.lang.OutOfMemoryError err)
     {
       // TODO: catch OOM
       System.out.println("Out of memory loading groups: " + err);
     }
-
+    return upd;
   }
 
   private void _updateConservationRow(Conservation c)
@@ -575,9 +604,9 @@ public class SequenceGroup implements AnnotatedCollectionI
     c.completeAnnotations(conservation, null, startRes, endRes + 1);
   }
 
-  public Hashtable[] consensusData = null;
+  public ProfilesI consensusData = null;
 
-  private void _updateConsensusRow(Hashtable[] cnsns, long nseq)
+  private void _updateConsensusRow(ProfilesI cnsns, long nseq)
   {
     if (consensus == null)
     {
@@ -611,13 +640,13 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     synchronized (sequences)
     {
-    if (sequences.contains(s))
-    {
-      deleteSequence(s, recalc);
-    }
-    else
-    {
-      addSequence(s, recalc);
+      if (sequences.contains(s))
+      {
+        deleteSequence(s, recalc);
+      }
+      else
+      {
+        addSequence(s, recalc);
       }
     }
   }
@@ -773,8 +802,9 @@ public class SequenceGroup implements AnnotatedCollectionI
     synchronized (sequences)
     {
       // MC This needs to get reset when characters are inserted and deleted
-      boolean first=true;
-      for (SequenceI seq:sequences) {
+      boolean first = true;
+      for (SequenceI seq : sequences)
+      {
         if (first || seq.getLength() > width)
         {
           width = seq.getLength();
@@ -891,6 +921,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * @return the representative sequence for this group
    */
+  @Override
   public SequenceI getSeqrep()
   {
     return seqrep;
@@ -903,6 +934,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * @param seqrep
    *          the seqrep to set (null means no sequence representative)
    */
+  @Override
   public void setSeqrep(SequenceI seqrep)
   {
     this.seqrep = seqrep;
@@ -912,6 +944,7 @@ public class SequenceGroup implements AnnotatedCollectionI
    * 
    * @return true if group has a sequence representative
    */
+  @Override
   public boolean hasSeqrep()
   {
     return seqrep != null;
@@ -1033,7 +1066,8 @@ public class SequenceGroup implements AnnotatedCollectionI
 
   /**
    * 
-   * @return automatically calculated consensus row
+   * @return automatically calculated consensus row note: the row is a stub if a
+   *         consensus calculation has not yet been performed on the group
    */
   public AlignmentAnnotation getConsensus()
   {
@@ -1240,10 +1274,14 @@ public class SequenceGroup implements AnnotatedCollectionI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    List<AlignmentAnnotation> aa = new ArrayList<AlignmentAnnotation>();
+    if (calcId == null)
+    {
+      return aa;
+    }
     for (AlignmentAnnotation a : getAlignmentAnnotation())
     {
-      if (a.getCalcId() == calcId)
+      if (calcId.equals(a.getCalcId()))
       {
         aa.add(a);
       }
@@ -1295,6 +1333,9 @@ public class SequenceGroup implements AnnotatedCollectionI
     return false;
   }
 
+  /**
+   * Remove all sequences from the group (leaving other properties unchanged).
+   */
   public void clear()
   {
     synchronized (sequences)
@@ -1325,4 +1366,37 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     return context;
   }
+
+  public void setColourScheme(ColourSchemeI scheme)
+  {
+    if (cs == null)
+    {
+      cs = new ResidueShader();
+    }
+    cs.setColourScheme(scheme);
+  }
+
+  public void setGroupColourScheme(ResidueShaderI scheme)
+  {
+    cs = scheme;
+  }
+
+  public ColourSchemeI getColourScheme()
+  {
+    return cs == null ? null : cs.getColourScheme();
+  }
+
+  public ResidueShaderI getGroupColourScheme()
+  {
+    return cs;
+  }
+
+  @Override
+  public boolean isNucleotide()
+  {
+    if (context != null) {
+      return context.isNucleotide();
+    }
+    return false;
+  }
 }