Merge branch 'features/JAL-2446NCList' into features/JAL-2574findFeaturesByColumn
[jalview.git] / src / jalview / datamodel / features / SequenceFeatures.java
index af99ada..8f6d496 100644 (file)
@@ -1,5 +1,6 @@
 package jalview.datamodel.features;
 
+import jalview.datamodel.ContiguousI;
 import jalview.datamodel.SequenceFeature;
 import jalview.io.gff.SequenceOntologyFactory;
 import jalview.io.gff.SequenceOntologyI;
@@ -62,7 +63,7 @@ public class SequenceFeatures implements SequenceFeaturesI
   {
     /*
      * use a TreeMap so that features are returned in alphabetical order of type
-     * wrap as a synchronized map for add and delete operations
+     * ? wrap as a synchronized map for add and delete operations
      */
     // featureStore = Collections
     // .synchronizedSortedMap(new TreeMap<String, FeatureStore>());
@@ -70,6 +71,21 @@ public class SequenceFeatures implements SequenceFeaturesI
   }
 
   /**
+   * Constructor given a list of features
+   */
+  public SequenceFeatures(List<SequenceFeature> features)
+  {
+    this();
+    if (features != null)
+    {
+      for (SequenceFeature feature : features)
+      {
+        add(feature);
+      }
+    }
+  }
+
+  /**
    * {@inheritDoc}
    */
   @Override
@@ -220,9 +236,11 @@ public class SequenceFeatures implements SequenceFeaturesI
     /*
      * else make a copy of the list, and remove any null value just in case,
      * as it would cause errors looking up the features Map
+     * sort in alphabetical order for consistent output behaviour
      */
     List<String> types = new ArrayList<String>(Arrays.asList(type));
     types.remove(null);
+    Collections.sort(types);
     return types;
   }
 
@@ -425,4 +443,52 @@ public class SequenceFeatures implements SequenceFeaturesI
     Collections.sort(features, forwardStrand ? FORWARD_STRAND
             : REVERSE_STRAND);
   }
+
+  /**
+   * {@inheritDoc} This method is 'semi-optimised': it only inspects features
+   * for types that include the specified group, but has to inspect every
+   * feature of those types for matching feature group. This is efficient unless
+   * a sequence has features that share the same type but are in different
+   * groups - an unlikely case.
+   * <p>
+   * For example, if RESNUM feature is created with group = PDBID, then features
+   * would only be retrieved for those sequences associated with the target
+   * PDBID (group).
+   */
+  @Override
+  public List<SequenceFeature> getFeaturesForGroup(boolean positional,
+          String group, String... type)
+  {
+    List<SequenceFeature> result = new ArrayList<SequenceFeature>();
+    Iterable<String> types = varargToTypes(type);
+
+    for (String featureType : types)
+    {
+      /*
+       * check whether the feature type is present, and also
+       * whether it has features for the specified group
+       */
+      FeatureStore features = featureStore.get(featureType);
+      if (features != null
+              && features.getFeatureGroups(positional).contains(group))
+      {
+        result.addAll(features.getFeaturesForGroup(positional, group));
+      }
+    }
+    return result;
+  }
+
+  /**
+   * {@inheritDoc}
+   */
+  @Override
+  public boolean shiftFeatures(int shift)
+  {
+    boolean modified = false;
+    for (FeatureStore fs : featureStore.values())
+    {
+      modified |= fs.shiftFeatures(shift);
+    }
+    return modified;
+  }
 }
\ No newline at end of file