Formatting changes
[jalview.git] / src / jalview / appletgui / AnnotationPanel.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 \r
20 package jalview.appletgui;\r
21 \r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 import jalview.datamodel.*;\r
28 \r
29 public class AnnotationPanel\r
30     extends Panel implements AdjustmentListener\r
31 {\r
32   AlignViewport av;\r
33   AlignmentPanel ap;\r
34   int activeRow = -1;\r
35 \r
36   Vector activeRes;\r
37   static String HELIX = "Helix";\r
38   static String SHEET = "Sheet";\r
39   static String LABEL = "Label";\r
40   static String REMOVE = "Remove Annotation";\r
41   static String COLOUR = "Colour";\r
42   static Color HELIX_COLOUR = Color.red.darker();\r
43   static Color SHEET_COLOUR = Color.green.darker().darker();\r
44 \r
45   Image image;\r
46   Graphics gg;\r
47   FontMetrics fm;\r
48   int imgWidth = 0;\r
49 \r
50   boolean fastPaint = false;\r
51 \r
52   public static int GRAPH_HEIGHT = 40;\r
53 \r
54   public AnnotationPanel(AlignmentPanel ap)\r
55   {\r
56     this.ap = ap;\r
57     av = ap.av;\r
58     this.setLayout(null);\r
59     adjustPanelHeight();\r
60 \r
61     addMouseMotionListener(new MouseMotionAdapter()\r
62     {\r
63       public void mouseMoved(MouseEvent evt)\r
64       {\r
65         doMouseMoved(evt);\r
66       }\r
67     });\r
68 \r
69     // ap.annotationScroller.getVAdjustable().addAdjustmentListener( this );\r
70   }\r
71 \r
72   public void adjustmentValueChanged(AdjustmentEvent evt)\r
73   {\r
74     ap.alabels.setScrollOffset( -evt.getValue());\r
75   }\r
76 \r
77   public void adjustPanelHeight()\r
78   {\r
79     // setHeight of panels\r
80     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
81     int height = 0;\r
82     if (aa != null)\r
83     {\r
84       for (int i = 0; i < aa.length; i++)\r
85       {\r
86         if (!aa[i].visible)\r
87         {\r
88           continue;\r
89         }\r
90 \r
91         aa[i].height = 0;\r
92 \r
93         if (aa[i].hasText)\r
94         {\r
95           aa[i].height += av.charHeight;\r
96         }\r
97         if (aa[i].hasIcons)\r
98         {\r
99           aa[i].height += 16;\r
100         }\r
101 \r
102         if (aa[i].isGraph)\r
103         {\r
104           aa[i].height += GRAPH_HEIGHT;\r
105         }\r
106 \r
107         if (aa[i].height == 0)\r
108         {\r
109           aa[i].height = 20;\r
110         }\r
111         height += aa[i].height;\r
112       }\r
113     }\r
114     else\r
115     {\r
116       height = 20;\r
117     }\r
118 \r
119     this.setSize(getSize().width, height);\r
120     ap.annotationScroller.setSize(getSize().width, height);\r
121 \r
122 //  ap.annotationSpaceFillerHolder.setSize(d.width,annotationPanel.getSize().height);\r
123 \r
124     repaint();\r
125 \r
126   }\r
127 \r
128   public void addEditableColumn(int i)\r
129   {\r
130     if (activeRow == -1)\r
131     {\r
132       AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
133       for (int j = 0; j < aa.length; j++)\r
134       {\r
135         if (aa[j].editable)\r
136         {\r
137           activeRow = j;\r
138           break;\r
139         }\r
140       }\r
141     }\r
142 \r
143     if (activeRes == null)\r
144     {\r
145       activeRes = new Vector();\r
146       activeRes.addElement(String.valueOf(i));\r
147       return;\r
148     }\r
149 \r
150     activeRes.addElement(String.valueOf(i));\r
151   }\r
152 \r
153   public void doMouseMoved(MouseEvent evt)\r
154   {\r
155     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
156     if (aa == null)\r
157     {\r
158       return;\r
159     }\r
160 \r
161     int row = -1;\r
162     int height = 0;\r
163     for (int i = 0; i < aa.length; i++)\r
164     {\r
165 \r
166       if (aa[i].visible)\r
167       {\r
168         height += aa[i].height;\r
169       }\r
170 \r
171       if (evt.getY() < height)\r
172       {\r
173         row = i;\r
174         break;\r
175       }\r
176     }\r
177 \r
178     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
179     if (row > -1 && res < aa[row].annotations.length && aa[row].annotations[res] != null)\r
180     {\r
181       StringBuffer text = new StringBuffer("Sequence position " + (res + 1) +\r
182                                            "  " +\r
183                                            aa[row].annotations[res].description);\r
184       ap.alignFrame.statusBar.setText(text.toString());\r
185     }\r
186   }\r
187 \r
188   public void update(Graphics g)\r
189   {\r
190     paint(g);\r
191   }\r
192 \r
193   public void paint(Graphics g)\r
194   {\r
195     imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
196 \r
197     if (image == null || imgWidth != image.getWidth(this))\r
198     {\r
199       image = createImage(imgWidth, ap.annotationPanel.getSize().height);\r
200       gg = image.getGraphics();\r
201       gg.setFont(av.getFont());\r
202       fm = gg.getFontMetrics();\r
203       fastPaint = false;\r
204     }\r
205 \r
206     if (fastPaint)\r
207     {\r
208       g.drawImage(image, 0, 0, this);\r
209       fastPaint = false;\r
210       return;\r
211     }\r
212 \r
213     drawComponent(gg, av.startRes, av.endRes + 1);\r
214     g.drawImage(image, 0, 0, this);\r
215 \r
216   }\r
217 \r
218   public void fastPaint(int horizontal)\r
219   {\r
220     if (horizontal == 0\r
221         || av.alignment.getAlignmentAnnotation() == null\r
222         || av.alignment.getAlignmentAnnotation().length < 1\r
223         )\r
224     {\r
225       repaint();\r
226       return;\r
227     }\r
228 \r
229     gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.charWidth, 0);\r
230     int sr = av.startRes, er = av.endRes + 1, transX = 0;\r
231 \r
232     if (horizontal > 0) // scrollbar pulled right, image to the left\r
233     {\r
234       transX = (er - sr - horizontal) * av.charWidth;\r
235       sr = er - horizontal;\r
236     }\r
237     else if (horizontal < 0)\r
238     {\r
239       er = sr - horizontal;\r
240     }\r
241 \r
242     gg.translate(transX, 0);\r
243 \r
244     drawComponent(gg, sr, er);\r
245 \r
246     gg.translate( -transX, 0);\r
247 \r
248     fastPaint = true;\r
249     repaint();\r
250   }\r
251 \r
252   public void drawComponent(Graphics g, int startRes, int endRes)\r
253   {\r
254     g.setColor(Color.white);\r
255     g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);\r
256     if (av.alignment.getAlignmentAnnotation() == null ||\r
257         av.alignment.getAlignmentAnnotation().length < 1)\r
258     {\r
259       g.setColor(Color.white);\r
260       g.fillRect(0, 0, getSize().width, getSize().height);\r
261       g.setColor(Color.black);\r
262       g.drawString("Alignment has no annotations", 20, 15);\r
263       return;\r
264     }\r
265 \r
266     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
267 \r
268     int j, x = 0, y = 0;\r
269     char[] lastSS = new char[aa.length];\r
270     int[] lastSSX = new int[aa.length];\r
271     int iconOffset = av.charHeight / 2;\r
272     boolean validRes = false;\r
273     //\u03B2 \u03B1\r
274 \r
275     for (int i = 0; i < aa.length; i++)\r
276     {\r
277       AlignmentAnnotation row = aa[i];\r
278       if (!row.visible)\r
279       {\r
280         continue;\r
281       }\r
282 \r
283       if (row.isGraph)\r
284       {\r
285         // this is so that we draw the characters below the graph\r
286         y += row.height;\r
287         if (row.hasText)\r
288         {\r
289           y -= av.charHeight;\r
290         }\r
291       }\r
292       if (row.hasText)\r
293       {\r
294         iconOffset = av.charHeight / 2;\r
295       }\r
296       else\r
297       {\r
298         iconOffset = 0;\r
299       }\r
300 \r
301       for (j = startRes; j < endRes; j++)\r
302       {\r
303         if (row.annotations.length <= j || row.annotations[j] == null)\r
304         {\r
305           validRes = false;\r
306         }\r
307         else\r
308         {\r
309           validRes = true;\r
310         }\r
311 \r
312         x = (j - startRes) * av.charWidth;\r
313 \r
314         if (activeRow == i)\r
315         {\r
316 \r
317           g.setColor(Color.red);\r
318 \r
319           if (activeRes != null)\r
320           {\r
321             for (int n = 0; n < activeRes.size(); n++)\r
322             {\r
323               int v = Integer.parseInt(activeRes.elementAt(n).toString());\r
324               if (v == j)\r
325               {\r
326                 g.fillRect( (j - startRes) * av.charWidth, y, av.charWidth,\r
327                            row.height);\r
328               }\r
329             }\r
330           }\r
331         }\r
332 \r
333         if (validRes && row.annotations[j].displayCharacter.length() > 0)\r
334         {\r
335           int charOffset = (av.charWidth -\r
336                             fm.charWidth(row.annotations[j].displayCharacter.\r
337                                          charAt(0))) / 2;\r
338           g.setColor(row.annotations[j].colour);\r
339           if (j == 0)\r
340           {\r
341             if (row.annotations[0].secondaryStructure == 'H'\r
342                 || row.annotations[0].secondaryStructure == 'E')\r
343             {\r
344               g.drawString(row.annotations[j].displayCharacter, x,\r
345                            y + iconOffset + 2);\r
346             }\r
347           }\r
348           else if ( (row.annotations[j].secondaryStructure == 'H'\r
349                      || row.annotations[j].secondaryStructure == 'E') &&\r
350                    (row.annotations[j - 1] == null ||\r
351                     row.annotations[j].secondaryStructure !=\r
352                     row.annotations[j - 1].secondaryStructure))\r
353           {\r
354 \r
355             g.drawString(row.annotations[j].displayCharacter, x + charOffset,\r
356                          y + iconOffset + 2);\r
357           }\r
358 \r
359           if (!row.hasIcons)\r
360           {\r
361             g.drawString(row.annotations[j].displayCharacter, x + charOffset,\r
362                          y + iconOffset + 2);\r
363           }\r
364         }\r
365 \r
366         if (row.hasIcons)\r
367         {\r
368           if (!validRes || row.annotations[j].secondaryStructure != lastSS[i])\r
369           {\r
370             switch (lastSS[i])\r
371             {\r
372               case 'H':\r
373                 g.setColor(HELIX_COLOUR);\r
374                 g.fillRoundRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i],\r
375                                 7, 8, 8);\r
376                 break;\r
377               case 'E':\r
378                 g.setColor(SHEET_COLOUR);\r
379                 g.fillRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i] - 4,\r
380                            7);\r
381                 g.fillPolygon(new int[]\r
382                               {x - 4, x - 4, x}\r
383                               , new int[]\r
384                               {y + iconOffset, y + 14 + iconOffset,\r
385                               y + 8 + iconOffset}, 3);\r
386                 break;\r
387               case 'C':\r
388                 break;\r
389               default:\r
390                 g.setColor(Color.gray);\r
391                 g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
392                 break;\r
393             }\r
394 \r
395             if (validRes)\r
396             {\r
397               lastSS[i] = row.annotations[j].secondaryStructure;\r
398             }\r
399             else\r
400             {\r
401               lastSS[i] = ' ';\r
402             }\r
403             lastSSX[i] = x;\r
404           }\r
405         }\r
406 \r
407         if (validRes && row.isGraph)\r
408         {\r
409           g.setColor(new Color(0, 0, 180));\r
410           int height = (int) ( (row.annotations[j].value / row.graphMax) *\r
411                               GRAPH_HEIGHT);\r
412 \r
413           if (row.windowLength > 1)\r
414           {\r
415             int total = 0;\r
416             for (int i2 = j - (row.windowLength / 2);\r
417                  i2 < j + (row.windowLength / 2); i2++)\r
418             {\r
419               if (i2 < 0 || i2 >= av.alignment.getWidth())\r
420               {\r
421                 continue;\r
422               }\r
423 \r
424               total += row.annotations[i2].value;\r
425             }\r
426 \r
427             total /= row.windowLength;\r
428             height = (int) ( (total / row.graphMax) * GRAPH_HEIGHT);\r
429 \r
430           }\r
431           g.setColor(row.annotations[j].colour);\r
432           g.fillRect(x, y - height, av.charWidth, height);\r
433         }\r
434 \r
435       }\r
436 \r
437       x += av.charWidth;\r
438 \r
439       if (row.hasIcons)\r
440       {\r
441         switch (lastSS[i])\r
442         {\r
443           case 'H':\r
444             g.setColor(HELIX_COLOUR);\r
445             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i], 7,\r
446                             8, 8);\r
447             break;\r
448           case 'E':\r
449             g.setColor(SHEET_COLOUR);\r
450             g.fillRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i] - 4, 7);\r
451             g.fillPolygon(new int[]\r
452                           {x - 4, x - 4, x}\r
453                           , new int[]\r
454                           {y + iconOffset, y + 14 + iconOffset,\r
455                           y + 7 + iconOffset}\r
456                           , 3);\r
457             break;\r
458           case 'C':\r
459             break;\r
460           default:\r
461             g.setColor(Color.gray);\r
462             g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
463             break;\r
464 \r
465         }\r
466       }\r
467 \r
468       if (row.isGraph && row.hasText)\r
469       {\r
470         y += av.charHeight;\r
471       }\r
472       if (!row.isGraph)\r
473       {\r
474         y += aa[i].height;\r
475       }\r
476     }\r
477   }\r
478 \r
479   // used by overview window\r
480   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y)\r
481   {\r
482     g.setColor(Color.white);\r
483     g.fillRect(0, 0, width, y);\r
484     g.setColor(new Color(0, 0, 180));\r
485     int x = 0;\r
486     for (int j = 0; j < aa.annotations.length; j++)\r
487     {\r
488       g.setColor(new Color(0, 0, 180));\r
489       int height = (int) ( (aa.annotations[j].value / aa.graphMax) *\r
490                           GRAPH_HEIGHT);\r
491       g.fillRect(x, y - height, av.charWidth, height);\r
492       x += av.charWidth;\r
493     }\r
494   }\r
495 }\r