Uncomment graphics 2d bit
[jalview.git] / src / jalview / appletgui / FeatureRenderer.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2007 AM Waterhouse, J Procter, G Barton, M Clamp, S Searle\r
4  *\r
5  * This program is free software; you can redistribute it and/or\r
6  * modify it under the terms of the GNU General Public License\r
7  * as published by the Free Software Foundation; either version 2\r
8  * of the License, or (at your option) any later version.\r
9  *\r
10  * This program is distributed in the hope that it will be useful,\r
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\r
13  * GNU General Public License for more details.\r
14  *\r
15  * You should have received a copy of the GNU General Public License\r
16  * along with this program; if not, write to the Free Software\r
17  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA\r
18  */\r
19 package jalview.appletgui;\r
20 \r
21 import java.util.*;\r
22 \r
23 import java.awt.*;\r
24 \r
25 import jalview.datamodel.*;\r
26 \r
27 /**\r
28  * DOCUMENT ME!\r
29  *\r
30  * @author $author$\r
31  * @version $Revision$\r
32  */\r
33 public class FeatureRenderer\r
34 {\r
35   AlignViewport av;\r
36 \r
37   Hashtable featureColours = new Hashtable();\r
38 \r
39   // A higher level for grouping features of a\r
40   // particular type\r
41   Hashtable featureGroups = null;\r
42 \r
43   // Holds web links for feature groups and feature types\r
44   // in the form label|link\r
45   Hashtable featureLinks = null;\r
46 \r
47   // This is actually an Integer held in the hashtable,\r
48   // Retrieved using the key feature type\r
49   Object currentColour;\r
50 \r
51   String[] renderOrder;\r
52 \r
53   FontMetrics fm;\r
54   int charOffset;\r
55 \r
56   float transparency = 1f;\r
57 \r
58   TransparencySetter transparencySetter = null;\r
59 \r
60   /**\r
61    * Creates a new FeatureRenderer object.\r
62    *\r
63    * @param av DOCUMENT ME!\r
64    */\r
65   public FeatureRenderer(AlignViewport av)\r
66   {\r
67     this.av = av;\r
68 \r
69     if (!System.getProperty("java.version").startsWith("1.1"))\r
70     {\r
71       transparencySetter = new TransparencySetter();\r
72     }\r
73   }\r
74 \r
75   public void transferSettings(FeatureRenderer fr)\r
76   {\r
77     renderOrder = fr.renderOrder;\r
78     featureGroups = fr.featureGroups;\r
79     featureColours = fr.featureColours;\r
80     transparency = fr.transparency;\r
81   }\r
82 \r
83   public Color findFeatureColour(Color initialCol, SequenceI seq, int i)\r
84   {\r
85     overview = true;\r
86     if (!av.showSequenceFeatures)\r
87     {\r
88       return initialCol;\r
89     }\r
90 \r
91     lastSequence = seq;\r
92     sequenceFeatures = lastSequence.getSequenceFeatures();\r
93     if (sequenceFeatures == null)\r
94     {\r
95       return initialCol;\r
96     }\r
97 \r
98     sfSize = sequenceFeatures.length;\r
99 \r
100     if (jalview.util.Comparison.isGap(lastSequence.getCharAt(i)))\r
101     {\r
102       return Color.white;\r
103     }\r
104 \r
105     currentColour = null;\r
106 \r
107     drawSequence(null, lastSequence, lastSequence.findPosition(i), -1, -1);\r
108 \r
109     if (currentColour == null)\r
110     {\r
111       return initialCol;\r
112     }\r
113 \r
114     return new Color( ( (Integer) currentColour).intValue());\r
115   }\r
116 \r
117   /**\r
118    * This is used by the Molecule Viewer to get the accurate colour\r
119    * of the rendered sequence\r
120    */\r
121   boolean overview = false;\r
122 \r
123   int white = Color.white.getRGB();\r
124   public int findFeatureColour(int initialCol, int seqIndex, int column)\r
125   {\r
126     if (!av.showSequenceFeatures)\r
127     {\r
128       return initialCol;\r
129     }\r
130 \r
131     if (seqIndex != lastSequenceIndex)\r
132     {\r
133       lastSequence = av.alignment.getSequenceAt(seqIndex);\r
134       lastSequenceIndex = seqIndex;\r
135       sequenceFeatures = lastSequence.getSequenceFeatures();\r
136       if (sequenceFeatures == null)\r
137       {\r
138         return initialCol;\r
139       }\r
140 \r
141       sfSize = sequenceFeatures.length;\r
142     }\r
143 \r
144     if (jalview.util.Comparison.isGap(lastSequence.getCharAt(column)))\r
145     {\r
146       return Color.white.getRGB();\r
147     }\r
148 \r
149     currentColour = null;\r
150 \r
151     drawSequence(null, lastSequence, lastSequence.findPosition(column), -1, -1);\r
152 \r
153     if (currentColour == null)\r
154     {\r
155       return initialCol;\r
156     }\r
157 \r
158     return ( (Integer) currentColour).intValue();\r
159   }\r
160 \r
161   /**\r
162    * DOCUMENT ME!\r
163    *\r
164    * @param g DOCUMENT ME!\r
165    * @param seq DOCUMENT ME!\r
166    * @param sg DOCUMENT ME!\r
167    * @param start DOCUMENT ME!\r
168    * @param end DOCUMENT ME!\r
169    * @param x1 DOCUMENT ME!\r
170    * @param y1 DOCUMENT ME!\r
171    * @param width DOCUMENT ME!\r
172    * @param height DOCUMENT ME!\r
173    */\r
174   // String type;\r
175   // SequenceFeature sf;\r
176   int lastSequenceIndex = -1;\r
177   SequenceI lastSequence;\r
178   SequenceFeature[] sequenceFeatures;\r
179   int sfSize, sfindex, spos, epos;\r
180 \r
181   public void drawSequence(Graphics g, SequenceI seq,\r
182                            int start, int end, int y1)\r
183   {\r
184     if (seq.getSequenceFeatures() == null\r
185         || seq.getSequenceFeatures().length == 0)\r
186     {\r
187       return;\r
188     }\r
189 \r
190     if (transparencySetter != null && g != null)\r
191     {\r
192       transparencySetter.setTransparency(g, transparency);\r
193     }\r
194 \r
195     if (av.featuresDisplayed == null || renderOrder == null)\r
196     {\r
197       findAllFeatures();\r
198       if (av.featuresDisplayed.size() < 1)\r
199       {\r
200         return;\r
201       }\r
202 \r
203       sequenceFeatures = seq.getSequenceFeatures();\r
204       sfSize = sequenceFeatures.length;\r
205     }\r
206     if (lastSequence == null || seq != lastSequence)\r
207     {\r
208       lastSequence = seq;\r
209       sequenceFeatures = seq.getSequenceFeatures();\r
210       sfSize = sequenceFeatures.length;\r
211     }\r
212     if (!overview)\r
213     {\r
214       spos = lastSequence.findPosition(start);\r
215       epos = lastSequence.findPosition(end);\r
216       if (g != null)\r
217       {\r
218         fm = g.getFontMetrics();\r
219       }\r
220     }\r
221     String type;\r
222     for (int renderIndex = 0; renderIndex < renderOrder.length; renderIndex++)\r
223     {\r
224       type = renderOrder[renderIndex];\r
225       if (!av.featuresDisplayed.containsKey(type))\r
226       {\r
227         continue;\r
228       }\r
229 \r
230       // loop through all features in sequence to find\r
231       // current feature to render\r
232       for (sfindex = 0; sfindex < sfSize; sfindex++)\r
233       {\r
234         if (!sequenceFeatures[sfindex].type.equals(type))\r
235         {\r
236           continue;\r
237         }\r
238 \r
239         if (featureGroups != null\r
240             && sequenceFeatures[sfindex].featureGroup != null\r
241             &&\r
242             featureGroups.containsKey(sequenceFeatures[sfindex].featureGroup)\r
243             &&\r
244             ! ( (Boolean) featureGroups.get(sequenceFeatures[sfindex].\r
245                                             featureGroup)).\r
246             booleanValue())\r
247         {\r
248           continue;\r
249         }\r
250 \r
251         if (!overview && (sequenceFeatures[sfindex].getBegin() > epos\r
252                           || sequenceFeatures[sfindex].getEnd() < spos))\r
253         {\r
254           continue;\r
255         }\r
256 \r
257         if (overview)\r
258         {\r
259           if (sequenceFeatures[sfindex].begin <= start &&\r
260               sequenceFeatures[sfindex].end >= start)\r
261           {\r
262             currentColour = av.featuresDisplayed.get(sequenceFeatures[sfindex].\r
263                 type);\r
264           }\r
265 \r
266         }\r
267         else if (sequenceFeatures[sfindex].type.equals("disulfide bond"))\r
268         {\r
269 \r
270           renderFeature(g, seq,\r
271                         seq.findIndex(sequenceFeatures[sfindex].begin) - 1,\r
272                         seq.findIndex(sequenceFeatures[sfindex].begin) - 1,\r
273                         new Color( ( (Integer) av.featuresDisplayed.get(\r
274                             sequenceFeatures[sfindex].type)).intValue()),\r
275                         start, end, y1);\r
276           renderFeature(g, seq,\r
277                         seq.findIndex(sequenceFeatures[sfindex].end) - 1,\r
278                         seq.findIndex(sequenceFeatures[sfindex].end) - 1,\r
279                         new Color( ( (Integer) av.featuresDisplayed.get(\r
280                             sequenceFeatures[sfindex].type)).intValue()),\r
281                         start, end, y1);\r
282 \r
283         }\r
284         else\r
285         {\r
286           renderFeature(g, seq,\r
287                         seq.findIndex(sequenceFeatures[sfindex].begin) - 1,\r
288                         seq.findIndex(sequenceFeatures[sfindex].end) - 1,\r
289                         getColour(sequenceFeatures[sfindex].type),\r
290                         start, end, y1);\r
291         }\r
292 \r
293       }\r
294     }\r
295 \r
296     if (transparencySetter != null && g != null)\r
297     {\r
298       transparencySetter.setTransparency(g, 1.0f);\r
299     }\r
300   }\r
301 \r
302   char s;\r
303   int i;\r
304   void renderFeature(Graphics g, SequenceI seq,\r
305                      int fstart, int fend, Color featureColour, int start,\r
306                      int end, int y1)\r
307   {\r
308 \r
309     if ( ( (fstart <= end) && (fend >= start)))\r
310     {\r
311       if (fstart < start)\r
312       { // fix for if the feature we have starts before the sequence start,\r
313         fstart = start; // but the feature end is still valid!!\r
314       }\r
315 \r
316       if (fend >= end)\r
317       {\r
318         fend = end;\r
319       }\r
320 \r
321       for (i = fstart; i <= fend; i++)\r
322       {\r
323         s = seq.getCharAt(i);\r
324 \r
325         if (jalview.util.Comparison.isGap(s))\r
326         {\r
327           continue;\r
328         }\r
329 \r
330         g.setColor(featureColour);\r
331 \r
332         g.fillRect( (i - start) * av.charWidth, y1, av.charWidth, av.charHeight);\r
333 \r
334         if (!av.validCharWidth)\r
335         {\r
336           continue;\r
337         }\r
338 \r
339         g.setColor(Color.white);\r
340         charOffset = (av.charWidth - fm.charWidth(s)) / 2;\r
341         g.drawString(String.valueOf(s),\r
342                      charOffset + (av.charWidth * (i - start)),\r
343                      (y1 + av.charHeight) - av.charHeight / 5); //pady = height / 5;\r
344 \r
345       }\r
346     }\r
347   }\r
348 \r
349   void findAllFeatures()\r
350   {\r
351     jalview.schemes.UserColourScheme ucs = new\r
352         jalview.schemes.UserColourScheme();\r
353 \r
354     av.featuresDisplayed = new Hashtable();\r
355     Vector allfeatures = new Vector();\r
356     for (int i = 0; i < av.alignment.getHeight(); i++)\r
357     {\r
358       SequenceFeature[] features = av.alignment.getSequenceAt(i).\r
359           getSequenceFeatures();\r
360 \r
361       if (features == null)\r
362       {\r
363         continue;\r
364       }\r
365 \r
366       int index = 0;\r
367       while (index < features.length)\r
368       {\r
369         if (!av.featuresDisplayed.containsKey(features[index].getType()))\r
370         {\r
371           if (getColour(features[index].getType()) == null)\r
372           {\r
373             featureColours.put(features[index].getType(),\r
374                                ucs.createColourFromName(features[index].\r
375                 getType()));\r
376           }\r
377 \r
378           av.featuresDisplayed.put(features[index].getType(),\r
379                                    new Integer(getColour(features[index].\r
380               getType()).getRGB()));\r
381           allfeatures.addElement(features[index].getType());\r
382         }\r
383         index++;\r
384       }\r
385     }\r
386 \r
387     renderOrder = new String[allfeatures.size()];\r
388     Enumeration en = allfeatures.elements();\r
389     int i = allfeatures.size() - 1;\r
390     while (en.hasMoreElements())\r
391     {\r
392       renderOrder[i] = en.nextElement().toString();\r
393       i--;\r
394     }\r
395   }\r
396 \r
397   public Color getColour(String featureType)\r
398   {\r
399     return (Color) featureColours.get(featureType);\r
400   }\r
401 \r
402   public void addNewFeature(String name, Color col)\r
403   {\r
404 \r
405     setColour(name, col);\r
406     if (av.featuresDisplayed == null)\r
407     {\r
408       av.featuresDisplayed = new Hashtable();\r
409     }\r
410 \r
411     av.featuresDisplayed.put(name, "NOGROUP");\r
412   }\r
413 \r
414   public void setColour(String featureType, Color col)\r
415   {\r
416     featureColours.put(featureType, col);\r
417   }\r
418 \r
419   public void setFeaturePriority(Object[][] data)\r
420   {\r
421     // The feature table will display high priority\r
422     // features at the top, but theses are the ones\r
423     // we need to render last, so invert the data\r
424     if (av.featuresDisplayed != null)\r
425     {\r
426       av.featuresDisplayed.clear();\r
427     }\r
428 \r
429     renderOrder = new String[data.length];\r
430 \r
431     if (data.length > 0)\r
432     {\r
433       for (int i = 0; i < data.length; i++)\r
434       {\r
435         String type = data[i][0].toString();\r
436         setColour(type, (Color) data[i][1]);\r
437         if ( ( (Boolean) data[i][2]).booleanValue())\r
438         {\r
439           av.featuresDisplayed.put(type, new Integer(getColour(type).getRGB()));\r
440         }\r
441 \r
442         renderOrder[data.length - i - 1] = type;\r
443       }\r
444     }\r
445   }\r
446 }\r
447 \r
448 class TransparencySetter\r
449 {\r
450   void setTransparency(Graphics g, float value)\r
451   {\r
452      Graphics2D g2 = (Graphics2D) g;\r
453      g2.setComposite(\r
454         AlphaComposite.getInstance(\r
455              AlphaComposite.SRC_OVER, value));\r
456   }\r
457 }\r