fa06d94c2836e0369c6ed507ef6cf9a7494a2ec8
[jalview.git] / src / jalview / gui / FeatureRenderer.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer\r
3  * Copyright (C) 2005 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.gui;\r
20 \r
21 import jalview.datamodel.*;\r
22 \r
23 import java.awt.*;\r
24 \r
25 import java.util.*;\r
26 \r
27 import java.awt.image.*;\r
28 \r
29 \r
30 /**\r
31  * DOCUMENT ME!\r
32  *\r
33  * @author $author$\r
34  * @version $Revision$\r
35  */\r
36 public class FeatureRenderer\r
37 {\r
38     AlignViewport av;\r
39     Color resBoxColour;\r
40     float transparency = 1.0f;\r
41     FontMetrics fm;\r
42     int charOffset;\r
43     boolean drawText = true;\r
44 \r
45     // The following vector holds the features which are\r
46     // to be added, in the correct order or rendering\r
47     Vector featuresDisplayed = null;\r
48 \r
49     /**\r
50      * Creates a new FeatureRenderer object.\r
51      *\r
52      * @param av DOCUMENT ME!\r
53      */\r
54     public FeatureRenderer(AlignViewport av)\r
55     {\r
56         this.av = av;\r
57         initColours();\r
58     }\r
59 \r
60     /**\r
61      * This is used by the Molecule Viewer to get the accurate colour\r
62      * of the rendered sequence\r
63      */\r
64     BufferedImage bi;\r
65     public synchronized Color findFeatureColour(Color initialCol, SequenceI seq, int i)\r
66     {\r
67       if(!av.showSequenceFeatures)\r
68         return initialCol;\r
69 \r
70       if (bi == null)\r
71         bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_RGB);\r
72 \r
73       bi.setRGB(0,0, initialCol.getRGB());\r
74 \r
75       drawText = false;\r
76       drawSequence(bi.getGraphics(), seq, i, i, 0, 0, 1, 1);\r
77       drawText = true;\r
78 \r
79       return new Color(bi.getRGB(0, 0));\r
80     }\r
81 \r
82 \r
83     /**\r
84      * DOCUMENT ME!\r
85      *\r
86      * @param g DOCUMENT ME!\r
87      * @param seq DOCUMENT ME!\r
88      * @param sg DOCUMENT ME!\r
89      * @param start DOCUMENT ME!\r
90      * @param end DOCUMENT ME!\r
91      * @param x1 DOCUMENT ME!\r
92      * @param y1 DOCUMENT ME!\r
93      * @param width DOCUMENT ME!\r
94      * @param height DOCUMENT ME!\r
95      */\r
96     public void drawSequence(Graphics g, SequenceI seq,\r
97                              int start, int end, int x1, int y1, int width, int height)\r
98     {\r
99 \r
100 //System.out.println(start+" "+end+" "+x1+" "+y1);\r
101       if (seq.getDatasetSequence().getSequenceFeatures() == null\r
102           || seq.getDatasetSequence().getSequenceFeatures().size()==0)\r
103         return;\r
104 \r
105       fm = g.getFontMetrics();\r
106 \r
107       if (transparency != 1)\r
108       {\r
109         Graphics2D g2 = (Graphics2D) g;\r
110         g2.setComposite(\r
111             AlphaComposite.getInstance(\r
112                 AlphaComposite.SRC_OVER, transparency));\r
113       }\r
114 \r
115       String type;\r
116       SequenceFeature sf;\r
117       if (featuresDisplayed == null)\r
118         findAllFeatures();\r
119 \r
120       Enumeration e = featuresDisplayed.elements(), e2;\r
121 \r
122       // Loop through each visible feature\r
123       while (e.hasMoreElements())\r
124       {\r
125 \r
126         type = e.nextElement().toString();\r
127         e2 = seq.getDatasetSequence().getSequenceFeatures().elements();\r
128         // loop through all features in sequence to find\r
129         // current feature to render\r
130           while (e2.hasMoreElements())\r
131         {\r
132 \r
133           sf = (SequenceFeature) e2.nextElement();\r
134           if (!type.equals(sf.getType()))\r
135             continue;\r
136 \r
137           if (sf.getBegin() > seq.getEnd())\r
138             continue;\r
139 \r
140           if (type.equals("disulfide bond"))\r
141           {\r
142 \r
143             renderFeature(g, seq,\r
144                           seq.findIndex(sf.getBegin()) - 1,\r
145                           seq.findIndex(sf.getBegin()) - 1,\r
146                           type, start, end, x1, y1, width, height);\r
147             renderFeature(g, seq,\r
148                           seq.findIndex(sf.getEnd()) - 1,\r
149                           seq.findIndex(sf.getEnd()) - 1,\r
150                           type, start, end, x1, y1, width, height);\r
151 \r
152           }\r
153           else\r
154             renderFeature(g, seq,\r
155                           seq.findIndex(sf.getBegin()) - 1,\r
156                           seq.findIndex(sf.getEnd()) - 1,\r
157                           type, start, end, x1, y1, width, height);\r
158         }\r
159       }\r
160 \r
161         if(transparency!=1.0f)\r
162         {\r
163           Graphics2D g2 = (Graphics2D) g;\r
164           g2.setComposite(\r
165               AlphaComposite.getInstance(\r
166                   AlphaComposite.SRC_OVER, 1.0f));\r
167         }\r
168     }\r
169 \r
170 \r
171     void renderFeature(Graphics g, SequenceI seq,\r
172                        int fstart, int fend, String type, int start, int end, int x1, int y1, int width, int height)\r
173     {\r
174 \r
175       if (((fstart <= end) && (fend >= start)))\r
176       {\r
177           if (fstart < start)\r
178           { // fix for if the feature we have starts before the sequence start,\r
179               fstart = start; // but the feature end is still valid!!\r
180           }\r
181 \r
182           if (fend >= end)\r
183           {\r
184             fend = end;\r
185           }\r
186           for (int i = fstart; i <= fend; i++)\r
187           {\r
188             char s = seq.getSequence().charAt(i);\r
189 \r
190             if (jalview.util.Comparison.isGap(s))\r
191             {\r
192               continue;\r
193             }\r
194 \r
195             g.setColor(getColour(type));\r
196 \r
197             g.fillRect( (i - start) * width, y1, width, height);\r
198 \r
199             if(drawText)\r
200            {\r
201              g.setColor(Color.white);\r
202              charOffset = (width - fm.charWidth(s)) / 2;\r
203              g.drawString(String.valueOf(s),\r
204                           charOffset + x1 + (width * (i - start)),\r
205                           (y1 + height) - height / 5); //pady = height / 5;\r
206            }\r
207           }\r
208         }\r
209     }\r
210 \r
211     void findAllFeatures()\r
212     {\r
213       Vector features = new Vector();\r
214       SequenceFeature sf;\r
215       featuresDisplayed = new Vector();\r
216       Enumeration e;\r
217       for (int i = 0; i < av.alignment.getHeight(); i++)\r
218       {\r
219         features = av.alignment.getSequenceAt(i).getDatasetSequence().\r
220             getSequenceFeatures();\r
221         if (features == null)\r
222           continue;\r
223 \r
224         e = features.elements();\r
225         while (e.hasMoreElements())\r
226         {\r
227           sf = (SequenceFeature) e.nextElement();\r
228           if (!featuresDisplayed.contains(sf.getType()))\r
229           {\r
230             featuresDisplayed.addElement(sf.getType());\r
231           }\r
232         }\r
233       }\r
234     }\r
235 \r
236     public Color getColour(String featureType)\r
237     {\r
238       return (Color)featureColours.get(featureType);\r
239     }\r
240 \r
241     public void setColour(String featureType, Color col)\r
242     {\r
243       featureColours.put(featureType, col);\r
244     }\r
245 \r
246     public void setTransparency(float value)\r
247     {\r
248       transparency = value;\r
249     }\r
250 \r
251     public float getTransparency()\r
252     {\r
253       return transparency;\r
254     }\r
255 \r
256     public void setFeaturePriority(Object [][] data)\r
257     {\r
258       // The feature table will display high priority\r
259       // features at the top, but theses are the ones\r
260       // we need to render last, so invert the data\r
261       featuresDisplayed.clear();\r
262       for(int i=data.length-1; i>-1; i--)\r
263       {\r
264        String type = data[i][0].toString();\r
265        setColour(type, (Color)data[i][1]);\r
266        if( ((Boolean)data[i][2]).booleanValue() )\r
267          featuresDisplayed.addElement(type);\r
268       }\r
269     }\r
270 \r
271     Hashtable featureColours = new Hashtable();\r
272     void initColours()\r
273     {\r
274       featureColours.put("active site", new Color(255, 75, 0));\r
275       featureColours.put("binding site", new Color(245, 85, 0));\r
276       featureColours.put("calcium-binding region", new Color(235, 95, 0));\r
277       featureColours.put("chain", new Color(225, 105, 0));\r
278       featureColours.put("coiled-coil region", new Color(215, 115, 0));\r
279       featureColours.put("compositionally biased region", new Color(205, 125, 0));\r
280       featureColours.put("cross-link", new Color(195, 135, 0));\r
281       featureColours.put("disulfide bond", new Color(230,230,0));\r
282       featureColours.put("DNA-binding region", new Color(175, 155, 0));\r
283       featureColours.put("domain", new Color(165, 165, 0));\r
284       featureColours.put("glycosylation site", new Color(155, 175, 0));\r
285       featureColours.put("helix", new Color(145, 185, 0));\r
286       featureColours.put("initiator methionine", new Color(135, 195, 5));\r
287       featureColours.put("lipid moiety-binding region", new Color(125, 205, 15));\r
288       featureColours.put("metal ion-binding site", new Color(115, 215, 25));\r
289       featureColours.put("modified residue", new Color(105, 225, 35));\r
290       featureColours.put("mutagenesis site", new Color(95, 235, 45));\r
291       featureColours.put("non-consecutive residues", new Color(85, 245, 55));\r
292       featureColours.put("non-terminal residue", new Color(75, 255, 65));\r
293       featureColours.put("nucleotide phosphate-binding region",new Color(65, 245, 75));\r
294       featureColours.put("peptide", new Color(55, 235, 85));\r
295       featureColours.put("propeptide", new Color(45, 225, 95));\r
296       featureColours.put("region of interest", new Color(35, 215, 105));\r
297       featureColours.put("repeat", new Color(25, 205, 115));\r
298       featureColours.put("selenocysteine", new Color(15, 195, 125));\r
299       featureColours.put("sequence conflict", new Color(5, 185, 135));\r
300       featureColours.put("sequence variant", new Color(0, 175, 145));\r
301       featureColours.put("short sequence motif", new Color(0, 165, 155));\r
302       featureColours.put("signal peptide", new Color(0, 155, 165));\r
303       featureColours.put("site", new Color(0, 145, 175));\r
304       featureColours.put("splice variant", new Color(0, 135, 185));\r
305       featureColours.put("strand", new Color(0, 125, 195));\r
306       featureColours.put("topological domain", new Color(0, 115, 205));\r
307       featureColours.put("transit peptide", new Color(0, 105, 215));\r
308       featureColours.put("transmembrane region", new Color(0, 95, 225));\r
309       featureColours.put("turn", new Color(0, 85, 235));\r
310       featureColours.put("unsure residue", new Color(0, 75, 245));\r
311       featureColours.put("zinc finger region", new Color(0, 65, 255));\r
312     }\r
313 \r
314 }\r