Merge branch 'features/JAL-4071_visibleFeaturesCounter' into features/JAL-3417_sdppre...
[jalview.git] / src / jalview / workers / VisibleFeaturesAnnotationTracks.java
diff --git a/src/jalview/workers/VisibleFeaturesAnnotationTracks.java b/src/jalview/workers/VisibleFeaturesAnnotationTracks.java
new file mode 100644 (file)
index 0000000..6e54628
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ * 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.workers;
+
+import java.awt.Color;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import jalview.api.AlignViewportI;
+import jalview.api.FeatureColourI;
+import jalview.api.FeaturesDisplayedI;
+import jalview.datamodel.SequenceFeature;
+import jalview.gui.FeatureRenderer;
+
+public class VisibleFeaturesAnnotationTracks implements FeatureSetCounterI
+{
+  AlignViewportI ourViewport = null;
+
+  jalview.api.FeatureRenderer ourFr = null;
+
+  PropertyChangeListener ourListener = new PropertyChangeListener()
+  {
+
+    @Override
+    public void propertyChange(PropertyChangeEvent evt)
+    {
+      if (ourViewport != null) // could
+                               // check
+                               // source
+                               // is
+                               // ourFr.getChangeSupport...
+      {
+        updateFeatureAnnotationTracks();
+      }
+    }
+  };
+
+  public VisibleFeaturesAnnotationTracks(AlignViewportI viewport,
+          FeatureRenderer fr)
+  {
+    ourViewport = viewport;
+    ourFr = fr;
+    registerListener();
+  }
+
+  void registerListener()
+  {
+    ourFr.addPropertyChangeListener(ourListener);
+  }
+
+  public void tidyUp()
+  {
+    if (ourFr != null)
+    {
+      ourFr.removePropertyChangeListener(ourListener);
+    }
+    if (ourViewport != null && ourViewport.getCalcManager() != null)
+    {
+      if (ourWorker != null)
+      {
+        ourWorker.abortAndDestroy();
+        ourViewport.getCalcManager()
+                .removeRegisteredWorkersOfClass(ourWorker.getClass());
+      }
+      ourWorker = null;
+      ourViewport = null;
+    }
+  }
+
+  public void updateFeatureAnnotationTracks()
+  {
+    // if tracks are turned off, this returns null.
+    FeaturesDisplayedI featuresDisp = ourViewport
+            .isShowSequenceFeatureCounts()
+                    ? ourViewport.getFeaturesDisplayed()
+                    : null;
+    // get latest FeatureRenderer, just in case it's different.
+    ourFr = ourFr.getAlignPanel().getFeatureRenderer();
+
+    Set<String> visibleFeatures = new HashSet();
+    if (featuresDisp != null)
+    {
+      visibleFeatures.addAll(featuresDisp.getVisibleFeatures());
+    }
+    if (dispFeatures.equals(visibleFeatures))
+    {
+      // all the same features displayed
+      return;
+    }
+    // otherwise set up tracks accordingly
+
+    int[][] minC = new int[visibleFeatures.size()][3],
+            maxC = new int[visibleFeatures.size()][3];
+    Map<String, FeatureColourI> fcs = ourFr.getDisplayedFeatureCols();
+    int p = 0;
+    for (String s : visibleFeatures)
+    {
+      FeatureColourI color = fcs.get(s);
+      if (color.isSimpleColour())
+      {
+        minC[p] = new int[] { 133, 133, 133 };
+        maxC[p] = new int[] { color.getColour().getRed(),
+            color.getColour().getGreen(), color.getColour().getBlue() };
+      }
+      else
+      {
+        Color min = color.getMinColour(), max = color.getMaxColour();
+        minC[p] = new int[] { min.getRed(), min.getGreen(), min.getBlue() };
+        maxC[p] = new int[] { max.getRed(), max.getGreen(), max.getBlue() };
+      }
+      p++;
+    }
+    minColours = minC;
+    maxColours = maxC;
+    /*
+     * and register the counter
+     */
+    if (ourWorker != null)
+    {
+      Set<String> toRemove = new HashSet<String>();
+      toRemove.addAll(dispFeatures);
+      toRemove.removeAll(visibleFeatures);
+      dispFeatures = visibleFeatures;
+      ourWorker.removeOldAnnotations(toRemove.toArray(new String[0]));
+
+    }
+    else
+    {
+      dispFeatures = visibleFeatures;
+      ourWorker = new ColumnCounterSetWorker(ourViewport,
+              ourFr.getAlignPanel(), this);
+    }
+    ourViewport.getCalcManager().registerWorker(ourWorker);
+    ourViewport.getCalcManager().startWorker(ourWorker);
+  }
+
+  ColumnCounterSetWorker ourWorker = null;
+
+  Set<String> dispFeatures = Collections.EMPTY_SET;
+
+  @Override
+  public int[] count(String residue, List<SequenceFeature> features)
+  {
+    final Set<String> ourDispFeatures = dispFeatures;
+    int[] obs = new int[ourDispFeatures.size()];
+    SequenceFeature[] sfs = features.toArray(new SequenceFeature[0]);
+    for (SequenceFeature sf : sfs)
+    {
+      /*
+       * Here we inspect the type of the sequence feature.
+       * You can also test sf.description, sf.score, sf.featureGroup,
+       * sf.strand, sf.phase, sf.begin, sf.end
+       * or sf.getValue(attributeName) for GFF 'column 9' properties
+       */
+      int pos = 0;
+      for (String type : ourDispFeatures)
+      {
+        if (type.equals(sf.type))
+        {
+          obs[pos]++;
+        }
+        pos++;
+      }
+    }
+    return obs;
+  }
+
+  @Override
+  public String[] getNames()
+  {
+    return dispFeatures.toArray(new String[0]);
+  }
+
+  @Override
+  public String[] getDescriptions()
+  {
+    return dispFeatures.toArray(new String[0]);
+  }
+
+  int[][] minColours = null, maxColours = null;
+
+  @Override
+  public int[] getMaxColour(int row)
+  {
+    if (maxColours != null && row >= 0 && row < maxColours.length)
+    {
+      return maxColours[row];
+    }
+    return new int[] { 0, 0, 255 };
+  }
+
+  @Override
+  public int[] getMinColour(int row)
+  {
+    if (minColours != null && row >= 0 && row < minColours.length)
+    {
+      return minColours[row];
+    }
+    return new int[] { 133, 133, 133 };
+  }
+}
\ No newline at end of file