JAL-4159 sometimes the progress bar may not be available - null check
[jalview.git] / src / jalview / datamodel / SequenceGroup.java
index c060ef0..b5048a0 100755 (executable)
  */
 package jalview.datamodel;
 
-import jalview.analysis.AAFrequency;
-import jalview.analysis.Conservation;
-import jalview.renderer.ResidueShader;
-import jalview.renderer.ResidueShaderI;
-import jalview.schemes.ColourSchemeI;
-
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Map;
 
+import jalview.analysis.AAFrequency;
+import jalview.analysis.Conservation;
+import jalview.renderer.ResidueShader;
+import jalview.renderer.ResidueShaderI;
+import jalview.schemes.ColourSchemeI;
+
 /**
  * Collects a set contiguous ranges on a set of sequences
  * 
@@ -87,7 +89,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * group members
    */
-  private List<SequenceI> sequences = new ArrayList<>();
+  private List<SequenceI> sequences;
 
   /**
    * representative sequence for this group (if any)
@@ -101,11 +103,15 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public ResidueShaderI cs;
 
-  // start column (base 0)
-  int startRes = 0;
+  /**
+   * start column (base 0)
+   */
+  private int startRes = 0;
 
-  // end column (base 0)
-  int endRes = 0;
+  /**
+   * end column (base 0)
+   */
+  private int endRes = 0;
 
   public Color outlineColour = Color.black;
 
@@ -126,6 +132,9 @@ public class SequenceGroup implements AnnotatedCollectionI
    * consensus calculation property
    */
   private boolean showSequenceLogo = false;
+  
+
+  private boolean showSequenceSSLogo = false;
 
   /**
    * flag indicating if logo should be rendered normalised
@@ -143,10 +152,15 @@ public class SequenceGroup implements AnnotatedCollectionI
   private boolean hidecols = false;
 
   AlignmentAnnotation consensus = null;
+  
+
+  AlignmentAnnotation ssConsensus = null;
 
   AlignmentAnnotation conservation = null;
 
   private boolean showConsensusHistogram;
+  
+  private boolean showSSConsensusHistogram;
 
   private AnnotatedCollectionI context;
 
@@ -157,6 +171,7 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     groupName = "JGroup:" + this.hashCode();
     cs = new ResidueShader();
+    sequences = new ArrayList<>();
   }
 
   /**
@@ -208,6 +223,7 @@ public class SequenceGroup implements AnnotatedCollectionI
       displayBoxes = seqsel.displayBoxes;
       displayText = seqsel.displayText;
       colourText = seqsel.colourText;
+
       startRes = seqsel.startRes;
       endRes = seqsel.endRes;
       cs = new ResidueShader((ResidueShader) seqsel.cs);
@@ -221,6 +237,7 @@ public class SequenceGroup implements AnnotatedCollectionI
       showSequenceLogo = seqsel.showSequenceLogo;
       normaliseSequenceLogo = seqsel.normaliseSequenceLogo;
       showConsensusHistogram = seqsel.showConsensusHistogram;
+      showSSConsensusHistogram = seqsel.showSSConsensusHistogram;
       idColour = seqsel.idColour;
       outlineColour = seqsel.outlineColour;
       seqrep = seqsel.seqrep;
@@ -237,6 +254,17 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
   }
 
+  /**
+   * Constructor that copies the given list of sequences
+   * 
+   * @param seqs
+   */
+  public SequenceGroup(List<SequenceI> seqs)
+  {
+    this();
+    this.sequences.addAll(seqs);
+  }
+
   public boolean isShowSequenceLogo()
   {
     return showSequenceLogo;
@@ -251,18 +279,10 @@ public class SequenceGroup implements AnnotatedCollectionI
     for (int i = 0, ipos = 0; i < inorder.length; i++)
     {
       SequenceI seq = inorder[i];
-
-      seqs[ipos] = seq.getSubSequence(startRes, endRes + 1);
-      if (seqs[ipos] != null)
+      SequenceI seqipos = seqs[ipos] = seq.getSubSequence(startRes,
+              endRes + 1);
+      if (seqipos != null)
       {
-        seqs[ipos].setDescription(seq.getDescription());
-        seqs[ipos].setDBRefs(seq.getDBRefs());
-        seqs[ipos].setSequenceFeatures(seq.getSequenceFeatures());
-        if (seq.getDatasetSequence() != null)
-        {
-          seqs[ipos].setDatasetSequence(seq.getDatasetSequence());
-        }
-
         if (seq.getAnnotation() != null)
         {
           AlignmentAnnotation[] alann = align.getAlignmentAnnotation();
@@ -274,7 +294,7 @@ public class SequenceGroup implements AnnotatedCollectionI
             if (alann != null)
             {
               boolean found = false;
-              for (int pos = 0; pos < alann.length; pos++)
+              for (int pos = 0, np = alann.length; pos < np; pos++)
               {
                 if (alann[pos] == tocopy)
                 {
@@ -292,7 +312,13 @@ public class SequenceGroup implements AnnotatedCollectionI
             newannot.restrict(startRes, endRes);
             newannot.setSequenceRef(seqs[ipos]);
             newannot.adjustForAlignment();
-            seqs[ipos].addAlignmentAnnotation(newannot);
+            ContactMatrixI cm = seq
+                    .getContactMatrixFor(seq.getAnnotation()[a]);
+            if (cm != null)
+            {
+              seqs[ipos].addContactListFor(newannot, cm);
+            }
+            seqipos.addAlignmentAnnotation(newannot);
           }
         }
         ipos++;
@@ -593,6 +619,21 @@ public class SequenceGroup implements AnnotatedCollectionI
         cs.setConsensus(cnsns);
         upd = true;
       }
+      
+      
+      ProfilesI ssCnsns = AAFrequency.calculateSS(sequences, startRes,
+              endRes + 1, showSequenceLogo);
+      if (ssConsensus != null)
+      {
+        _updateSSConsensusRow(ssCnsns, sequences.size());
+        upd = true;
+      }
+      if (cs != null)
+      {
+        cs.setSsConsensus(ssCnsns);
+        upd = true;
+      }
+      
 
       if ((conservation != null)
               || (cs != null && cs.conservationApplied()))
@@ -628,7 +669,8 @@ public class SequenceGroup implements AnnotatedCollectionI
     } catch (java.lang.OutOfMemoryError err)
     {
       // TODO: catch OOM
-      System.out.println("Out of memory loading groups: " + err);
+      jalview.bin.Console
+              .outPrintln("Out of memory loading groups: " + err);
     }
     return upd;
   }
@@ -644,8 +686,10 @@ public class SequenceGroup implements AnnotatedCollectionI
     conservation.description = "Conservation for group " + getName()
             + " less than " + consPercGaps + "% gaps";
     // preserve width if already set
-    int aWidth = (conservation.annotations != null) ? (endRes < conservation.annotations.length ? conservation.annotations.length
-            : endRes + 1)
+    int aWidth = (conservation.annotations != null)
+            ? (endRes < conservation.annotations.length
+                    ? conservation.annotations.length
+                    : endRes + 1)
             : endRes + 1;
     conservation.annotations = null;
     conservation.annotations = new Annotation[aWidth]; // should be alignment
@@ -665,8 +709,10 @@ public class SequenceGroup implements AnnotatedCollectionI
     consensus.description = "Percent Identity";
     consensusData = cnsns;
     // preserve width if already set
-    int aWidth = (consensus.annotations != null) ? (endRes < consensus.annotations.length ? consensus.annotations.length
-            : endRes + 1)
+    int aWidth = (consensus.annotations != null)
+            ? (endRes < consensus.annotations.length
+                    ? consensus.annotations.length
+                    : endRes + 1)
             : endRes + 1;
     consensus.annotations = null;
     consensus.annotations = new Annotation[aWidth]; // should be alignment width
@@ -677,6 +723,33 @@ public class SequenceGroup implements AnnotatedCollectionI
     // for
     // ignoreGapsInConsensusCalculation);
   }
+  
+  public ProfilesI ssConsensusData = null;
+  
+  private void _updateSSConsensusRow(ProfilesI ssCnsns, long nseq)
+  {
+    if (ssConsensus == null)
+    {
+      getSSConsensus();
+    }
+    ssConsensus.label = "Sec Str Consensus for " + getName();
+    ssConsensus.description = "Percent Identity";
+    ssConsensusData = ssCnsns;
+    // preserve width if already set
+    int aWidth = (ssConsensus.annotations != null)
+            ? (endRes < ssConsensus.annotations.length
+                    ? ssConsensus.annotations.length
+                    : endRes + 1)
+            : endRes + 1;
+    ssConsensus.annotations = null;
+    ssConsensus.annotations = new Annotation[aWidth]; // should be alignment width
+
+    AAFrequency.completeSSConsensus(ssConsensus, ssCnsns, startRes, endRes + 1,
+            ignoreGapsInConsensus, showSequenceLogo, nseq); // TODO: setting
+                                                            // container
+    // for
+    // ignoreGapsInConsensusCalculation);
+  }
 
   /**
    * @param s
@@ -747,13 +820,15 @@ public class SequenceGroup implements AnnotatedCollectionI
   /**
    * Set the first column selected by this group. Runs from 0<=i<N_cols
    * 
-   * @param i
+   * @param newStart
    */
-  public void setStartRes(int i)
+  public void setStartRes(int newStart)
   {
     int before = startRes;
-    startRes = i;
+    startRes = Math.max(0, newStart); // sanity check for negative start column
+                                      // positions
     changeSupport.firePropertyChange(SEQ_GROUP_CHANGED, before, startRes);
+
   }
 
   /**
@@ -1130,6 +1205,30 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
     return consensus;
   }
+  
+  public AlignmentAnnotation getSSConsensus()
+  {
+    // TODO get or calculate and get consensus annotation row for this group
+    int aWidth = this.getWidth();
+    // pointer
+    // possibility
+    // here.
+    if (aWidth < 0)
+    {
+      return null;
+    }
+    if (ssConsensus == null)
+    {
+      ssConsensus = new AlignmentAnnotation("", "", new Annotation[1], 0f,
+              100f, AlignmentAnnotation.BAR_GRAPH);
+      ssConsensus.hasText = true;
+      ssConsensus.autoCalculated = true;
+      ssConsensus.groupRef = this;
+      ssConsensus.label = "Sec Str Consensus for " + getName();
+      ssConsensus.description = "Percent Identity";
+    }
+    return ssConsensus;
+  }
 
   /**
    * set this alignmentAnnotation object as the one used to render consensus
@@ -1184,9 +1283,10 @@ public class SequenceGroup implements AnnotatedCollectionI
     {
       if (consensus.annotations[i] != null)
       {
-        if (consensus.annotations[i].description.charAt(0) == '[')
+        String desc = consensus.annotations[i].description;
+        if (desc.length() > 1 && desc.charAt(0) == '[')
         {
-          seqs.append(consensus.annotations[i].description.charAt(1));
+          seqs.append(desc.charAt(1));
         }
         else
         {
@@ -1231,6 +1331,18 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
     this.showSequenceLogo = showSequenceLogo;
   }
+  
+  
+  public void setshowSequenceSSLogo(boolean showSequenceSSLogo)
+  {
+    // TODO: decouple calculation from settings update
+    if (this.showSequenceSSLogo != showSequenceSSLogo && ssConsensus != null)
+    {
+      this.showSequenceSSLogo = showSequenceSSLogo;
+      recalcConservation();
+    }
+    this.showSequenceSSLogo = showSequenceSSLogo;
+  }
 
   /**
    * 
@@ -1248,6 +1360,17 @@ public class SequenceGroup implements AnnotatedCollectionI
     }
     this.showConsensusHistogram = showConsHist;
   }
+  
+  public void setShowSSConsensusHistogram(boolean showSSConsHist)
+  {
+
+    if (showSSConsensusHistogram != showSSConsHist && consensus != null)
+    {
+      this.showSSConsensusHistogram = showSSConsHist;
+      recalcConservation();
+    }
+    this.showSSConsensusHistogram = showSSConsHist;
+  }
 
   /**
    * @return the showConsensusHistogram
@@ -1312,38 +1435,16 @@ public class SequenceGroup implements AnnotatedCollectionI
   @Override
   public Iterable<AlignmentAnnotation> findAnnotation(String calcId)
   {
-    List<AlignmentAnnotation> aa = new ArrayList<>();
-    if (calcId == null)
-    {
-      return aa;
-    }
-    for (AlignmentAnnotation a : getAlignmentAnnotation())
-    {
-      if (calcId.equals(a.getCalcId()))
-      {
-        aa.add(a);
-      }
-    }
-    return aa;
+    return AlignmentAnnotation.findAnnotation(
+            Arrays.asList(getAlignmentAnnotation()), calcId);
   }
 
   @Override
   public Iterable<AlignmentAnnotation> findAnnotations(SequenceI seq,
           String calcId, String label)
   {
-    ArrayList<AlignmentAnnotation> aa = new ArrayList<>();
-    for (AlignmentAnnotation ann : getAlignmentAnnotation())
-    {
-      if ((calcId == null || (ann.getCalcId() != null && ann.getCalcId()
-              .equals(calcId)))
-              && (seq == null || (ann.sequenceRef != null && ann.sequenceRef == seq))
-              && (label == null || (ann.label != null && ann.label
-                      .equals(label))))
-      {
-        aa.add(ann);
-      }
-    }
-    return aa;
+    return AlignmentAnnotation.findAnnotations(
+            Arrays.asList(getAlignmentAnnotation()), seq, calcId, label);
   }
 
   /**
@@ -1354,17 +1455,8 @@ public class SequenceGroup implements AnnotatedCollectionI
    */
   public boolean hasAnnotation(String calcId)
   {
-    if (calcId != null && !"".equals(calcId))
-    {
-      for (AlignmentAnnotation a : getAlignmentAnnotation())
-      {
-        if (a.getCalcId() == calcId)
-        {
-          return true;
-        }
-      }
-    }
-    return false;
+    return AlignmentAnnotation
+            .hasAnnotation(Arrays.asList(getAlignmentAnnotation()), calcId);
   }
 
   /**
@@ -1465,7 +1557,8 @@ public class SequenceGroup implements AnnotatedCollectionI
   @Override
   public boolean isNucleotide()
   {
-    if (context != null) {
+    if (context != null)
+    {
       return context.isNucleotide();
     }
     return false;
@@ -1490,4 +1583,51 @@ public class SequenceGroup implements AnnotatedCollectionI
   {
     return (startRes <= apos && endRes >= apos) && sequences.contains(seq);
   }
+
+  ////
+  //// Contact Matrix Holder Boilerplate
+  ////
+  ContactMapHolder cmholder = new ContactMapHolder();
+
+  @Override
+  public Collection<ContactMatrixI> getContactMaps()
+  {
+    return cmholder.getContactMaps();
+  }
+
+  @Override
+  public ContactMatrixI getContactMatrixFor(AlignmentAnnotation ann)
+  {
+    return cmholder.getContactMatrixFor(ann);
+  }
+
+  @Override
+  public ContactListI getContactListFor(AlignmentAnnotation _aa, int column)
+  {
+    return cmholder.getContactListFor(_aa, column);
+  }
+
+  @Override
+  public AlignmentAnnotation addContactList(ContactMatrixI cm)
+  {
+    AlignmentAnnotation aa = cmholder.addContactList(cm);
+
+    Annotation _aa[] = new Annotation[getWidth()];
+    Annotation dummy = new Annotation(0.0f);
+    for (int i = 0; i < _aa.length; _aa[i++] = dummy)
+    {
+      ;
+    }
+    aa.annotations = _aa;
+    // TODO passing annotations back to context to be added
+    return aa;
+  }
+
+  @Override
+  public void addContactListFor(AlignmentAnnotation annotation,
+          ContactMatrixI cm)
+  {
+    cmholder.addContactListFor(annotation, cm);
+  }
+
 }