Merge branch 'develop' into Jalview-JS/develop
[jalview.git] / src / jalview / viewmodel / seqfeatures / FeatureRendererModel.java
index 4fc143e..459a28b 100644 (file)
@@ -43,6 +43,7 @@ import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Hashtable;
@@ -618,7 +619,7 @@ public abstract class FeatureRendererModel
    * @param type
    * @return
    */
-  protected boolean showFeatureOfType(String type)
+  public boolean showFeatureOfType(String type)
   {
     return type == null ? false : (av.getFeaturesDisplayed() == null ? true
             : av.getFeaturesDisplayed().isVisible(type));
@@ -658,7 +659,7 @@ public abstract class FeatureRendererModel
     {
       featureOrder = new Hashtable<>();
     }
-    featureOrder.put(type, new Float(position));
+    featureOrder.put(type, Float.valueOf(position));
     return position;
   }
 
@@ -858,7 +859,7 @@ public abstract class FeatureRendererModel
     }
     if (newGroupsVisible)
     {
-      featureGroups.put(group, new Boolean(true));
+      featureGroups.put(group, Boolean.valueOf(true));
       return true;
     }
     return false;
@@ -894,7 +895,7 @@ public abstract class FeatureRendererModel
   @Override
   public void setGroupVisibility(String group, boolean visible)
   {
-    featureGroups.put(group, new Boolean(visible));
+    featureGroups.put(group, Boolean.valueOf(visible));
   }
 
   @Override
@@ -906,7 +907,7 @@ public abstract class FeatureRendererModel
       for (String gst : toset)
       {
         Boolean st = featureGroups.get(gst);
-        featureGroups.put(gst, new Boolean(visible));
+        featureGroups.put(gst, Boolean.valueOf(visible));
         if (st != null)
         {
           rdrw = rdrw || (visible != st.booleanValue());
@@ -1034,11 +1035,11 @@ public abstract class FeatureRendererModel
   }
 
   /**
-   * Removes from the list of features any that duplicate the location of a
-   * feature of the same type. Should be used only for features of the same,
-   * simple, feature colour (which normally implies the same feature type). Does
-   * not check visibility settings for feature type or feature group. No
-   * filtering is done if transparency, or any feature filters, are in force.
+   * Removes from the list of features any whose group is not shown, or that are
+   * visible and duplicate the location of a visible feature of the same type.
+   * Should be used only for features of the same, simple, feature colour (which
+   * normally implies the same feature type). No filtering is done if
+   * transparency, or any feature filters, are in force.
    * 
    * @param features
    */
@@ -1062,6 +1063,11 @@ public abstract class FeatureRendererModel
     while (it.hasNext())
     {
       SequenceFeature sf = it.next();
+      if (featureGroupNotShown(sf))
+      {
+        it.remove();
+        continue;
+      }
 
       /*
        * a feature is redundant for rendering purposes if it has the
@@ -1069,7 +1075,8 @@ public abstract class FeatureRendererModel
        * (checking type and isContactFeature as a fail-safe here, although
        * currently they are guaranteed to match in this context)
        */
-      if (lastFeature != null && sf.getBegin() == lastFeature.getBegin()
+      if (lastFeature != null
+              && sf.getBegin() == lastFeature.getBegin()
               && sf.getEnd() == lastFeature.getEnd()
               && sf.isContactFeature() == lastFeature.isContactFeature()
               && sf.getType().equals(lastFeature.getType()))
@@ -1156,15 +1163,33 @@ public abstract class FeatureRendererModel
   }
 
   /**
-   * Answers a (possibly empty) list of features in this alignment at a position
-   * (or range) which is mappable from the given sequence residue position in a
-   * mapped alignment. Features are returned in render order of feature type (on
-   * top last), with order within feature type undefined.
+   * Answers true unless the specified group is set to hidden. Defaults to true
+   * if group visibility is not set.
    * 
-   * @param sequence
-   * @param pos
+   * @param group
    * @return
    */
+  public boolean isGroupVisible(String group)
+  {
+    if (!featureGroups.containsKey(group))
+    {
+      return true;
+    }
+    return featureGroups.get(group);
+  }
+
+  /**
+   * Orders features in render precedence (last in order is last to render, so
+   * displayed on top of other features)
+   * 
+   * @param order
+   */
+  public void orderFeatures(Comparator<String> order)
+  {
+    Arrays.sort(renderOrder, order);
+  }
+
+  @Override
   public MappedFeatures findComplementFeaturesAtResidue(SequenceI sequence,
           int pos)
   {
@@ -1180,6 +1205,16 @@ public abstract class FeatureRendererModel
             .getCodonFrame(sequence);
 
     /*
+     * fudge: if no mapping found, check the complementary alignment
+     * todo: only store in one place? StructureSelectionManager?
+     */
+    if (mappings.isEmpty())
+    {
+      mappings = this.av.getCodingComplement().getAlignment()
+              .getCodonFrame(sequence);
+    }
+
+    /*
      * todo: direct lookup of CDS for peptide and vice-versa; for now,
      * have to search through an unordered list of mappings for a candidate
      */
@@ -1188,9 +1223,8 @@ public abstract class FeatureRendererModel
 
     for (AlignedCodonFrame acf : mappings)
     {
-      mapping = acf.getMappingForSequence(sequence, true);
-      if (mapping == null || mapping.getMap().getFromRatio() == mapping
-              .getMap().getToRatio())
+      mapping = acf.getMappingForSequence(sequence);
+      if (mapping == null || !mapping.getMap().isTripletMap())
       {
         continue; // we are only looking for 3:1 or 1:3 mappings
       }
@@ -1220,6 +1254,10 @@ public abstract class FeatureRendererModel
         break;
       }
     }
+    if (found.isEmpty())
+    {
+      return null;
+    }
 
     /*
      * sort by renderorder, inefficiently
@@ -1244,4 +1282,31 @@ public abstract class FeatureRendererModel
     return new MappedFeatures(mapping, mapFrom, pos, residue, result);
   }
 
+  @Override
+  public boolean isVisible(SequenceFeature feature)
+  {
+    if (feature == null)
+    {
+      return false;
+    }
+    if (getFeaturesDisplayed() == null
+            || !getFeaturesDisplayed().isVisible(feature.getType()))
+    {
+      return false;
+    }
+    if (featureGroupNotShown(feature))
+    {
+      return false;
+    }
+    FeatureColourI fc = featureColours.get(feature.getType());
+    if (fc != null && fc.isOutwithThreshold(feature))
+    {
+      return false;
+    }
+    if (!featureMatchesFilters(feature))
+    {
+      return false;
+    }
+    return true;
+  }
 }