Merge branch 'features/JAL-4071_visibleFeaturesCounter' into features/JAL-3417_sdppre...
[jalview.git] / src / jalview / workers / VisibleFeaturesAnnotationTracks.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer ($$Version-Rel$$)
3  * Copyright (C) $$Year-Rel$$ The Jalview Authors
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3
10  * of the License, or (at your option) any later version.
11  *  
12  * Jalview is distributed in the hope that it will be useful, but 
13  * WITHOUT ANY WARRANTY; without even the implied warranty 
14  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
15  * PURPOSE.  See the GNU General Public License for more details.
16  * 
17  * You should have received a copy of the GNU General Public License
18  * along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
19  * The Jalview Authors are detailed in the 'AUTHORS' file.
20  */
21 package jalview.workers;
22
23 import java.awt.Color;
24 import java.beans.PropertyChangeEvent;
25 import java.beans.PropertyChangeListener;
26 import java.util.Collections;
27 import java.util.HashSet;
28 import java.util.List;
29 import java.util.Map;
30 import java.util.Set;
31
32 import jalview.api.AlignViewportI;
33 import jalview.api.FeatureColourI;
34 import jalview.api.FeaturesDisplayedI;
35 import jalview.datamodel.SequenceFeature;
36 import jalview.gui.FeatureRenderer;
37
38 public class VisibleFeaturesAnnotationTracks implements FeatureSetCounterI
39 {
40   AlignViewportI ourViewport = null;
41
42   jalview.api.FeatureRenderer ourFr = null;
43
44   PropertyChangeListener ourListener = new PropertyChangeListener()
45   {
46
47     @Override
48     public void propertyChange(PropertyChangeEvent evt)
49     {
50       if (ourViewport != null) // could
51                                // check
52                                // source
53                                // is
54                                // ourFr.getChangeSupport...
55       {
56         updateFeatureAnnotationTracks();
57       }
58     }
59   };
60
61   public VisibleFeaturesAnnotationTracks(AlignViewportI viewport,
62           FeatureRenderer fr)
63   {
64     ourViewport = viewport;
65     ourFr = fr;
66     registerListener();
67   }
68
69   void registerListener()
70   {
71     ourFr.addPropertyChangeListener(ourListener);
72   }
73
74   public void tidyUp()
75   {
76     if (ourFr != null)
77     {
78       ourFr.removePropertyChangeListener(ourListener);
79     }
80     if (ourViewport != null && ourViewport.getCalcManager() != null)
81     {
82       if (ourWorker != null)
83       {
84         ourWorker.abortAndDestroy();
85         ourViewport.getCalcManager()
86                 .removeRegisteredWorkersOfClass(ourWorker.getClass());
87       }
88       ourWorker = null;
89       ourViewport = null;
90     }
91   }
92
93   public void updateFeatureAnnotationTracks()
94   {
95     // if tracks are turned off, this returns null.
96     FeaturesDisplayedI featuresDisp = ourViewport
97             .isShowSequenceFeatureCounts()
98                     ? ourViewport.getFeaturesDisplayed()
99                     : null;
100     // get latest FeatureRenderer, just in case it's different.
101     ourFr = ourFr.getAlignPanel().getFeatureRenderer();
102
103     Set<String> visibleFeatures = new HashSet();
104     if (featuresDisp != null)
105     {
106       visibleFeatures.addAll(featuresDisp.getVisibleFeatures());
107     }
108     if (dispFeatures.equals(visibleFeatures))
109     {
110       // all the same features displayed
111       return;
112     }
113     // otherwise set up tracks accordingly
114
115     int[][] minC = new int[visibleFeatures.size()][3],
116             maxC = new int[visibleFeatures.size()][3];
117     Map<String, FeatureColourI> fcs = ourFr.getDisplayedFeatureCols();
118     int p = 0;
119     for (String s : visibleFeatures)
120     {
121       FeatureColourI color = fcs.get(s);
122       if (color.isSimpleColour())
123       {
124         minC[p] = new int[] { 133, 133, 133 };
125         maxC[p] = new int[] { color.getColour().getRed(),
126             color.getColour().getGreen(), color.getColour().getBlue() };
127       }
128       else
129       {
130         Color min = color.getMinColour(), max = color.getMaxColour();
131         minC[p] = new int[] { min.getRed(), min.getGreen(), min.getBlue() };
132         maxC[p] = new int[] { max.getRed(), max.getGreen(), max.getBlue() };
133       }
134       p++;
135     }
136     minColours = minC;
137     maxColours = maxC;
138     /*
139      * and register the counter
140      */
141     if (ourWorker != null)
142     {
143       Set<String> toRemove = new HashSet<String>();
144       toRemove.addAll(dispFeatures);
145       toRemove.removeAll(visibleFeatures);
146       dispFeatures = visibleFeatures;
147       ourWorker.removeOldAnnotations(toRemove.toArray(new String[0]));
148
149     }
150     else
151     {
152       dispFeatures = visibleFeatures;
153       ourWorker = new ColumnCounterSetWorker(ourViewport,
154               ourFr.getAlignPanel(), this);
155     }
156     ourViewport.getCalcManager().registerWorker(ourWorker);
157     ourViewport.getCalcManager().startWorker(ourWorker);
158   }
159
160   ColumnCounterSetWorker ourWorker = null;
161
162   Set<String> dispFeatures = Collections.EMPTY_SET;
163
164   @Override
165   public int[] count(String residue, List<SequenceFeature> features)
166   {
167     final Set<String> ourDispFeatures = dispFeatures;
168     int[] obs = new int[ourDispFeatures.size()];
169     SequenceFeature[] sfs = features.toArray(new SequenceFeature[0]);
170     for (SequenceFeature sf : sfs)
171     {
172       /*
173        * Here we inspect the type of the sequence feature.
174        * You can also test sf.description, sf.score, sf.featureGroup,
175        * sf.strand, sf.phase, sf.begin, sf.end
176        * or sf.getValue(attributeName) for GFF 'column 9' properties
177        */
178       int pos = 0;
179       for (String type : ourDispFeatures)
180       {
181         if (type.equals(sf.type))
182         {
183           obs[pos]++;
184         }
185         pos++;
186       }
187     }
188     return obs;
189   }
190
191   @Override
192   public String[] getNames()
193   {
194     return dispFeatures.toArray(new String[0]);
195   }
196
197   @Override
198   public String[] getDescriptions()
199   {
200     return dispFeatures.toArray(new String[0]);
201   }
202
203   int[][] minColours = null, maxColours = null;
204
205   @Override
206   public int[] getMaxColour(int row)
207   {
208     if (maxColours != null && row >= 0 && row < maxColours.length)
209     {
210       return maxColours[row];
211     }
212     return new int[] { 0, 0, 255 };
213   }
214
215   @Override
216   public int[] getMinColour(int row)
217   {
218     if (minColours != null && row >= 0 && row < minColours.length)
219     {
220       return minColours[row];
221     }
222     return new int[] { 133, 133, 133 };
223   }
224 }