JAL-3070 JAL-3066 AlignmentI.findOrAddAnnotation(AlignmentAnnotation ala) - calls...
[jalview.git] / src / jalview / analysis / AlignmentAnnotationUtils.java
index ef8e670..194ef80 100644 (file)
@@ -1,7 +1,26 @@
+/*
+ * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
+ * Copyright (C) $$Year-Rel$$ The Jalview Authors
+ * 
+ * This file is part of Jalview.
+ * 
+ * Jalview is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License 
+ * as published by the Free Software Foundation, either version 3
+ * of the License, or (at your option) any later version.
+ *  
+ * Jalview is distributed in the hope that it will be useful, but 
+ * WITHOUT ANY WARRANTY; without even the implied warranty 
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+ * PURPOSE.  See the GNU General Public License for more details.
+ * 
+ * You should have received a copy of the GNU General Public License
+ * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
+ * The Jalview Authors are detailed in the 'AUTHORS' file.
+ */
 package jalview.analysis;
 
 import jalview.datamodel.AlignmentAnnotation;
-import jalview.datamodel.AlignmentI;
 import jalview.datamodel.SequenceI;
 import jalview.renderer.AnnotationRenderer;
 
@@ -64,9 +83,16 @@ public class AlignmentAnnotationUtils
 
     for (AlignmentAnnotation aa : annotations)
     {
-      if (forSequences != null
-              && (aa.sequenceRef != null && forSequences
-                      .contains(aa.sequenceRef)))
+      /*
+       * Ignore non-positional annotations, can't render these against an
+       * alignment
+       */
+      if (aa.annotations == null)
+      {
+        continue;
+      }
+      if (forSequences != null && (aa.sequenceRef != null
+              && forSequences.contains(aa.sequenceRef)))
       {
         String calcId = aa.getCalcId();
 
@@ -87,8 +113,8 @@ public class AlignmentAnnotationUtils
                   .get(calcId);
           if (groupLabelsForCalcId.containsKey(aa.graphGroup))
           {
-            if (!groupLabelsForCalcId.get(aa.graphGroup).contains(
-                    displayLabel))
+            if (!groupLabelsForCalcId.get(aa.graphGroup)
+                    .contains(displayLabel))
             {
               groupLabelsForCalcId.get(aa.graphGroup).add(displayLabel);
             }
@@ -130,21 +156,28 @@ public class AlignmentAnnotationUtils
       }
     }
     /*
-     * finally add the 'composite group labels' to the appropriate lists,
-     * depending on whether the group is identified as visible or hidden
+     * Finally add the 'composite group labels' to the appropriate lists,
+     * depending on whether the group is identified as visible or hidden. Don't
+     * add the same label more than once (there may be many graph groups that
+     * generate it).
      */
     for (String calcId : groupLabels.keySet())
     {
       for (int group : groupLabels.get(calcId).keySet())
       {
         final List<String> groupLabel = groupLabels.get(calcId).get(group);
+        // don't want to duplicate 'same types in different order'
+        Collections.sort(groupLabel);
         if (visibleGraphGroups.get(group))
         {
           if (!shownTypes.containsKey(calcId))
           {
             shownTypes.put(calcId, new ArrayList<List<String>>());
           }
-          shownTypes.get(calcId).add(groupLabel);
+          if (!shownTypes.get(calcId).contains(groupLabel))
+          {
+            shownTypes.get(calcId).add(groupLabel);
+          }
         }
         else
         {
@@ -152,7 +185,10 @@ public class AlignmentAnnotationUtils
           {
             hiddenTypes.put(calcId, new ArrayList<List<String>>());
           }
-          hiddenTypes.get(calcId).add(groupLabel);
+          if (!hiddenTypes.get(calcId).contains(groupLabel))
+          {
+            hiddenTypes.get(calcId).add(groupLabel);
+          }
         }
       }
     }
@@ -203,4 +239,42 @@ public class AlignmentAnnotationUtils
     return (anns == null ? Collections.<AlignmentAnnotation> emptyList()
             : Arrays.asList(anns));
   }
+
+  /**
+   * replace an existing sequence associated annotation with another, creating
+   * association as necessary.
+   * 
+   * @param newAnnot
+   *          - annotation row associated with an alignment sequence to be
+   *          propagated to its dataset sequence.
+   * @param typeName
+   *          - label used to match existing row
+   * @param calcId
+   *          - calcId for existing row
+   */
+  public static void replaceAnnotationOnAlignmentWith(
+          AlignmentAnnotation newAnnot, String typeName, String calcId)
+  {
+    if (newAnnot.sequenceRef != null)
+    {
+      SequenceI dsseq = newAnnot.sequenceRef.getDatasetSequence();
+      while (dsseq.getDatasetSequence() != null)
+      {
+        dsseq = dsseq.getDatasetSequence();
+      }
+      // look for same annotation on dataset and lift this one over
+      List<AlignmentAnnotation> dsan = dsseq.getAlignmentAnnotations(calcId,
+              typeName);
+      if (dsan != null && dsan.size() > 0)
+      {
+        for (AlignmentAnnotation dssan : dsan)
+        {
+          dsseq.removeAlignmentAnnotation(dssan);
+        }
+      }
+      AlignmentAnnotation dssan = new AlignmentAnnotation(newAnnot);
+      dsseq.addAlignmentAnnotation(dssan);
+      dssan.adjustForAlignment();
+    }
+  }
 }