JAL-2335 patched FeatureRendererModel.findFeaturesAtRes to honour isContactFeature
[jalview.git] / src / jalview / viewmodel / seqfeatures / FeatureRendererModel.java
index b299624..c1ad465 100644 (file)
@@ -29,13 +29,13 @@ import jalview.datamodel.SequenceI;
 import jalview.renderer.seqfeatures.FeatureRenderer;
 import jalview.schemes.FeatureColour;
 import jalview.schemes.UserColourScheme;
-import jalview.viewmodel.AlignmentViewport;
 
 import java.awt.Color;
 import java.beans.PropertyChangeListener;
 import java.beans.PropertyChangeSupport;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashMap;
 import java.util.Hashtable;
 import java.util.Iterator;
 import java.util.List;
@@ -63,7 +63,7 @@ public abstract class FeatureRendererModel implements
   protected PropertyChangeSupport changeSupport = new PropertyChangeSupport(
           this);
 
-  protected AlignmentViewport av;
+  protected AlignViewportI av;
 
   @Override
   public AlignViewportI getViewport()
@@ -288,8 +288,12 @@ public abstract class FeatureRendererModel implements
           continue;
         }
 
-        if ((features[i].getBegin() <= res)
-                && (features[i].getEnd() >= res))
+        // check if start/end are at res, and if not a contact feature, that res
+        // lies between start and end
+        if ((features[i].getBegin() == res || features[i].getEnd() == res)
+                || (!features[i].isContactFeature()
+                        && (features[i].getBegin() < res) && (features[i]
+                        .getEnd() >= res)))
         {
           tmp.add(features[i]);
         }
@@ -564,17 +568,22 @@ public abstract class FeatureRendererModel implements
     return fc.isColored(sequenceFeature);
   }
 
+  /**
+   * Answers true if the feature type is currently selected to be displayed,
+   * else false
+   * 
+   * @param type
+   * @return
+   */
   protected boolean showFeatureOfType(String type)
   {
-    return av.getFeaturesDisplayed().isVisible(type);
+    return type == null ? false : av.getFeaturesDisplayed().isVisible(type);
   }
 
   @Override
   public void setColour(String featureType, FeatureColourI col)
   {
-    {
-      featureColours.put(featureType, col);
-    }
+    featureColours.put(featureType, col);
   }
 
   public void setTransparency(float value)
@@ -636,21 +645,32 @@ public abstract class FeatureRendererModel implements
    * 
    * @param data
    *          { String(Type), Colour(Type), Boolean(Displayed) }
+   * @return true if any visible features have been reordered, else false
    */
-  public void setFeaturePriority(Object[][] data)
+  public boolean setFeaturePriority(Object[][] data)
   {
-    setFeaturePriority(data, true);
+    return setFeaturePriority(data, true);
   }
 
   /**
+   * Sets the priority order for features
    * 
    * @param data
    *          { String(Type), Colour(Type), Boolean(Displayed) }
    * @param visibleNew
    *          when true current featureDisplay list will be cleared
+   * @return true if any visible features have been reordered or recoloured,
+   *         else false (i.e. no need to repaint)
    */
-  public void setFeaturePriority(Object[][] data, boolean visibleNew)
+  public boolean setFeaturePriority(Object[][] data, boolean visibleNew)
   {
+    /*
+     * note visible feature ordering and colours before update
+     */
+    List<String> visibleFeatures = getDisplayedFeatureTypes();
+    Map<String, FeatureColourI> visibleColours = new HashMap<String, FeatureColourI>(
+            getFeatureColours());
+
     FeaturesDisplayedI av_featuresdisplayed = null;
     if (visibleNew)
     {
@@ -669,10 +689,10 @@ public abstract class FeatureRendererModel implements
     }
     if (data == null)
     {
-      return;
+      return false;
     }
     // The feature table will display high priority
-    // features at the top, but theses are the ones
+    // features at the top, but these are the ones
     // we need to render last, so invert the data
     renderOrder = new String[data.length];
 
@@ -691,6 +711,30 @@ public abstract class FeatureRendererModel implements
       }
     }
 
+    /*
+     * get the new visible ordering and return true if it has changed
+     * order or any colour has changed
+     */
+    List<String> reorderedVisibleFeatures = getDisplayedFeatureTypes();
+    if (!visibleFeatures.equals(reorderedVisibleFeatures))
+    {
+      /*
+       * the list of ordered visible features has changed
+       */
+      return true;
+    }
+
+    /*
+     * return true if any feature colour has changed
+     */
+    for (String feature : visibleFeatures)
+    {
+      if (visibleColours.get(feature) != getFeatureStyle(feature))
+      {
+        return true;
+      }
+    }
+    return false;
   }
 
   /**
@@ -726,6 +770,9 @@ public abstract class FeatureRendererModel implements
     return renderOrder != null;
   }
 
+  /**
+   * Returns feature types in ordering of rendering, where last means on top
+   */
   public List<String> getRenderOrder()
   {
     if (renderOrder == null)
@@ -775,7 +822,7 @@ public abstract class FeatureRendererModel implements
    * @return list of groups
    */
   @Override
-  public List<String> getGroups(boolean visible)
+  public List getGroups(boolean visible)
   {
     if (featureGroups != null)
     {
@@ -846,39 +893,39 @@ public abstract class FeatureRendererModel implements
     return av.getFeaturesDisplayed();
   }
 
+  /**
+   * Returns a (possibly empty) list of visible feature types, in render order
+   * (last is on top)
+   */
   @Override
-  public String[] getDisplayedFeatureTypes()
+  public List<String> getDisplayedFeatureTypes()
   {
-    String[] typ = null;
-    typ = getRenderOrder().toArray(new String[0]);
+    List<String> typ = getRenderOrder();
+    List<String> displayed = new ArrayList<String>();
     FeaturesDisplayedI feature_disp = av.getFeaturesDisplayed();
     if (feature_disp != null)
     {
       synchronized (feature_disp)
       {
-        for (int i = 0; i < typ.length; i++)
+        for (String type : typ)
         {
-          if (!feature_disp.isVisible(typ[i]))
+          if (feature_disp.isVisible(type))
           {
-            typ[i] = null;
+            displayed.add(type);
           }
         }
       }
     }
-    return typ;
+    return displayed;
   }
 
   @Override
-  public String[] getDisplayedFeatureGroups()
+  public List<String> getDisplayedFeatureGroups()
   {
-    String[] gps = null;
-    ArrayList<String> _gps = new ArrayList<String>();
-    Iterator en = getFeatureGroups().iterator();
-    int g = 0;
+    List<String> _gps = new ArrayList<String>();
     boolean valid = false;
-    while (en.hasNext())
+    for (String gp : getFeatureGroups())
     {
-      String gp = (String) en.next();
       if (checkGroupVisibility(gp, false))
       {
         valid = true;
@@ -890,11 +937,11 @@ public abstract class FeatureRendererModel implements
       }
       else
       {
-        gps = new String[_gps.size()];
-        _gps.toArray(gps);
+        // gps = new String[_gps.size()];
+        // _gps.toArray(gps);
       }
     }
-    return gps;
+    return _gps;
   }
 
 }