JAL-674 JAL-961 JAL-1578 accessors and copy constructor for annotation row properties
[jalview.git] / src / jalview / datamodel / AlignmentAnnotation.java
index c0d911e..e0a8e6e 100755 (executable)
@@ -26,7 +26,9 @@ import jalview.analysis.WUSSParseException;
 
 import java.util.ArrayList;
 import java.util.Enumeration;
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
 import java.util.Map.Entry;
 
 /**
@@ -43,17 +45,24 @@ public class AlignmentAnnotation
    */
   public boolean autoCalculated = false;
 
+  /**
+   * unique ID for this annotation, used to match up the same annotation row
+   * shown in multiple views and alignments
+   */
   public String annotationId;
 
+  /**
+   * the sequence this annotation is associated with (or null)
+   */
   public SequenceI sequenceRef;
 
-  /** DOCUMENT ME!! */
+  /** label shown in dropdown menus and in the annotation label area */
   public String label;
 
-  /** DOCUMENT ME!! */
+  /** longer description text shown as a tooltip */
   public String description;
 
-  /** DOCUMENT ME!! */
+  /** Array of annotations placed in the current coordinate system */
   public Annotation[] annotations;
 
   public ArrayList<SimpleBP> bps = null;
@@ -103,6 +112,9 @@ public class AlignmentAnnotation
     // System.out.println("featuregroup " + _rnasecstr[0].getFeatureGroup());
   }
 
+  /**
+   * map of positions in the associated annotation
+   */
   public java.util.Hashtable<Integer, Annotation> sequenceMapping;
 
   /** DOCUMENT ME!! */
@@ -622,6 +634,14 @@ public class AlignmentAnnotation
     this.scaleColLabel = annotation.scaleColLabel;
     this.showAllColLabels = annotation.showAllColLabels;
     this.calcId = annotation.calcId;
+    if (annotation.properties!=null)
+    {
+      properties = new HashMap<String,String>();
+      for (Map.Entry<String, String> val:annotation.properties.entrySet())
+      {
+        properties.put(val.getKey(), val.getValue());
+      }
+    }
     if (this.hasScore = annotation.hasScore)
     {
       this.score = annotation.score;
@@ -1119,6 +1139,11 @@ public class AlignmentAnnotation
   protected String calcId = "";
 
   /**
+   * properties associated with the calcId
+   */
+  protected Map<String, String> properties = new HashMap<String, String>();
+
+  /**
    * base colour for line graphs. If null, will be set automatically by
    * searching the alignment annotation
    */
@@ -1182,6 +1207,108 @@ public class AlignmentAnnotation
         // trim positions
       }
     }
+  }
+
+  /**
+   * like liftOver but more general.
+   * 
+   * Takes an array of int pairs that will be used to update the internal
+   * sequenceMapping and so shuffle the annotated positions
+   * 
+   * @param newref
+   *          - new sequence reference for the annotation row - if null,
+   *          sequenceRef is left unchanged
+   * @param mapping
+   *          array of ints containing corresponding positions
+   * @param from
+   *          - column for current coordinate system (-1 for index+1)
+   * @param to
+   *          - column for destination coordinate system (-1 for index+1)
+   * @param idxoffset
+   *          - offset added to index when referencing either coordinate system
+   * @note no checks are made as to whether from and/or to are sensible
+   * @note caller should add the remapped annotation to newref if they have not
+   *       already
+   */
+  public void remap(SequenceI newref, int[][] mapping, int from, int to,
+          int idxoffset)
+  {
+    if (mapping != null)
+    {
+      Hashtable<Integer, Annotation> old = sequenceMapping, remap = new Hashtable<Integer, Annotation>();
+      int index = -1;
+      for (int mp[] : mapping)
+      {
+        if (index++ < 0)
+        {
+          continue;
+        }
+        Annotation ann = null;
+        if (from == -1)
+        {
+          ann = sequenceMapping.get(Integer.valueOf(idxoffset + index));
+        }
+        else
+        {
+          if (mp != null && mp.length > from)
+          {
+            ann = sequenceMapping.get(Integer.valueOf(mp[from]));
+          }
+        }
+        if (ann != null)
+        {
+          if (to == -1)
+          {
+            remap.put(Integer.valueOf(idxoffset + index), ann);
+          }
+          else
+          {
+            if (to > -1 && to < mp.length)
+            {
+              remap.put(Integer.valueOf(mp[to]), ann);
+            }
+          }
+        }
+      }
+      sequenceMapping = remap;
+      old.clear();
+      if (newref != null)
+      {
+        sequenceRef = newref;
+      }
+      adjustForAlignment();
+    }
+  }
+
+  public String getProperty(String property)
+  {
+    if (properties == null)
+    {
+      return null;
+    }
+    return properties.get(property);
+  }
+
+  public void setProperty(String property, String value)
+  {
+    if (properties==null)
+    {
+      properties = new HashMap<String,String>();
+    }
+    properties.put(property, value);
+  }
+
+  public boolean hasProperties()
+  {
+    return properties != null && properties.size() > 0;
+  }
 
+  public Collection<String> getProperties()
+  {
+    if (properties == null)
+    {
+      return Collections.EMPTY_LIST;
+    }
+    return properties.keySet();
   }
 }