--- /dev/null
+/*
+ * 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