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