null pointers removed
[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       if(aa ==null)\r
134         return;\r
135 \r
136       for (int j = 0; j < aa.length; j++)\r
137       {\r
138         if (aa[j].editable)\r
139         {\r
140           activeRow = j;\r
141           break;\r
142         }\r
143       }\r
144     }\r
145 \r
146     if (activeRes == null)\r
147     {\r
148       activeRes = new Vector();\r
149       activeRes.addElement(String.valueOf(i));\r
150       return;\r
151     }\r
152 \r
153     activeRes.addElement(String.valueOf(i));\r
154   }\r
155 \r
156   public void doMouseMoved(MouseEvent evt)\r
157   {\r
158     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
159     if (aa == null)\r
160     {\r
161       return;\r
162     }\r
163 \r
164     int row = -1;\r
165     int height = 0;\r
166     for (int i = 0; i < aa.length; i++)\r
167     {\r
168 \r
169       if (aa[i].visible)\r
170       {\r
171         height += aa[i].height;\r
172       }\r
173 \r
174       if (evt.getY() < height)\r
175       {\r
176         row = i;\r
177         break;\r
178       }\r
179     }\r
180 \r
181     int res = evt.getX() / av.getCharWidth() + av.getStartRes();\r
182     if (row > -1 && res < aa[row].annotations.length && aa[row].annotations[res] != null)\r
183     {\r
184       StringBuffer text = new StringBuffer("Sequence position " + (res + 1) +\r
185                                            "  " +\r
186                                            aa[row].annotations[res].description);\r
187       ap.alignFrame.statusBar.setText(text.toString());\r
188     }\r
189   }\r
190 \r
191   public void update(Graphics g)\r
192   {\r
193     paint(g);\r
194   }\r
195 \r
196   public void paint(Graphics g)\r
197   {\r
198     g.setColor(Color.white);\r
199     g.fillRect(0,0, getSize().width, getSize().height);\r
200     imgWidth = (av.endRes - av.startRes + 1) * av.charWidth;\r
201 \r
202     if (image == null || imgWidth != image.getWidth(this))\r
203     {\r
204       image = createImage(imgWidth, ap.annotationPanel.getSize().height);\r
205       gg = image.getGraphics();\r
206       gg.setFont(av.getFont());\r
207       fm = gg.getFontMetrics();\r
208       fastPaint = false;\r
209     }\r
210 \r
211     if (fastPaint)\r
212     {\r
213       g.drawImage(image, 0, 0, this);\r
214       fastPaint = false;\r
215       return;\r
216     }\r
217 \r
218     drawComponent(gg, av.startRes, av.endRes + 1);\r
219     g.drawImage(image, 0, 0, this);\r
220 \r
221   }\r
222 \r
223   public void fastPaint(int horizontal)\r
224   {\r
225     if (horizontal == 0\r
226         || av.alignment.getAlignmentAnnotation() == null\r
227         || av.alignment.getAlignmentAnnotation().length < 1\r
228         )\r
229     {\r
230       repaint();\r
231       return;\r
232     }\r
233 \r
234     gg.copyArea(0, 0, imgWidth, getSize().height, -horizontal * av.charWidth, 0);\r
235     int sr = av.startRes, er = av.endRes + 1, transX = 0;\r
236 \r
237     if (horizontal > 0) // scrollbar pulled right, image to the left\r
238     {\r
239       transX = (er - sr - horizontal) * av.charWidth;\r
240       sr = er - horizontal;\r
241     }\r
242     else if (horizontal < 0)\r
243     {\r
244       er = sr - horizontal;\r
245     }\r
246 \r
247     gg.translate(transX, 0);\r
248 \r
249     drawComponent(gg, sr, er);\r
250 \r
251     gg.translate( -transX, 0);\r
252 \r
253     fastPaint = true;\r
254     repaint();\r
255   }\r
256 \r
257   public void drawComponent(Graphics g, int startRes, int endRes)\r
258   {\r
259     g.setColor(Color.white);\r
260     g.fillRect(0, 0, (endRes - startRes) * av.charWidth, getSize().height);\r
261     if (av.alignment.getAlignmentAnnotation() == null ||\r
262         av.alignment.getAlignmentAnnotation().length < 1)\r
263     {\r
264       g.setColor(Color.white);\r
265       g.fillRect(0, 0, getSize().width, getSize().height);\r
266       g.setColor(Color.black);\r
267       g.drawString("Alignment has no annotations", 20, 15);\r
268       return;\r
269     }\r
270 \r
271     AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
272 \r
273     int j, x = 0, y = 0;\r
274     char[] lastSS = new char[aa.length];\r
275     int[] lastSSX = new int[aa.length];\r
276     int iconOffset = av.charHeight / 2;\r
277     boolean validRes = false;\r
278     //\u03B2 \u03B1\r
279 \r
280     for (int i = 0; i < aa.length; i++)\r
281     {\r
282       AlignmentAnnotation row = aa[i];\r
283       if (!row.visible)\r
284       {\r
285         continue;\r
286       }\r
287 \r
288       if (row.isGraph)\r
289       {\r
290         // this is so that we draw the characters below the graph\r
291         y += row.height;\r
292         if (row.hasText)\r
293         {\r
294           y -= av.charHeight;\r
295         }\r
296       }\r
297       if (row.hasText)\r
298       {\r
299         iconOffset = av.charHeight / 2;\r
300       }\r
301       else\r
302       {\r
303         iconOffset = 0;\r
304       }\r
305 \r
306       for (j = startRes; j < endRes; j++)\r
307       {\r
308         if (row.annotations.length <= j || row.annotations[j] == null)\r
309         {\r
310           validRes = false;\r
311         }\r
312         else\r
313         {\r
314           validRes = true;\r
315         }\r
316 \r
317         x = (j - startRes) * av.charWidth;\r
318 \r
319         if (activeRow == i)\r
320         {\r
321 \r
322           g.setColor(Color.red);\r
323 \r
324           if (activeRes != null)\r
325           {\r
326             for (int n = 0; n < activeRes.size(); n++)\r
327             {\r
328               int v = Integer.parseInt(activeRes.elementAt(n).toString());\r
329               if (v == j)\r
330               {\r
331                 g.fillRect( (j - startRes) * av.charWidth, y, av.charWidth,\r
332                            row.height);\r
333               }\r
334             }\r
335           }\r
336         }\r
337 \r
338         if (validRes && row.annotations[j].displayCharacter.length() > 0)\r
339         {\r
340           int charOffset = (av.charWidth -\r
341                             fm.charWidth(row.annotations[j].displayCharacter.\r
342                                          charAt(0))) / 2;\r
343           g.setColor(row.annotations[j].colour);\r
344           if (j == 0 || row.isGraph)\r
345           {\r
346             if (row.annotations[0].secondaryStructure == 'H'\r
347                 || row.annotations[0].secondaryStructure == 'E')\r
348             {\r
349               g.drawString(row.annotations[j].displayCharacter, x,\r
350                            y + iconOffset + 3);\r
351             }\r
352           }\r
353           else if ( (row.annotations[j].secondaryStructure == 'H'\r
354                      || row.annotations[j].secondaryStructure == 'E') &&\r
355                    (row.annotations[j - 1] == null ||\r
356                     row.annotations[j].secondaryStructure !=\r
357                     row.annotations[j - 1].secondaryStructure))\r
358           {\r
359 \r
360             g.drawString(row.annotations[j].displayCharacter, x + charOffset,\r
361                          y + iconOffset + 3);\r
362           }\r
363 \r
364           if (!row.hasIcons)\r
365           {\r
366             g.drawString(row.annotations[j].displayCharacter, x + charOffset,\r
367                          y + iconOffset + 3);\r
368           }\r
369         }\r
370 \r
371         if (row.hasIcons)\r
372         {\r
373           if (!validRes || row.annotations[j].secondaryStructure != lastSS[i])\r
374           {\r
375             switch (lastSS[i])\r
376             {\r
377               case 'H':\r
378                 g.setColor(HELIX_COLOUR);\r
379                 g.fillRoundRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i],\r
380                                 7, 8, 8);\r
381                 break;\r
382               case 'E':\r
383                 g.setColor(SHEET_COLOUR);\r
384                 g.fillRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i] - 4,\r
385                            7);\r
386                 g.fillPolygon(new int[]\r
387                               {x - 4, x - 4, x}\r
388                               , new int[]\r
389                               {y + iconOffset, y + 14 + iconOffset,\r
390                               y + 8 + iconOffset}, 3);\r
391                 break;\r
392               case 'C':\r
393                 break;\r
394               default:\r
395                 g.setColor(Color.gray);\r
396                 g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
397                 break;\r
398             }\r
399 \r
400             if (validRes)\r
401             {\r
402               lastSS[i] = row.annotations[j].secondaryStructure;\r
403             }\r
404             else\r
405             {\r
406               lastSS[i] = ' ';\r
407             }\r
408             lastSSX[i] = x;\r
409           }\r
410         }\r
411 \r
412         if (validRes && row.isGraph)\r
413         {\r
414           g.setColor(new Color(0, 0, 180));\r
415           int height = (int) ( (row.annotations[j].value / row.graphMax) *\r
416                               GRAPH_HEIGHT);\r
417 \r
418           if (row.windowLength > 1)\r
419           {\r
420             int total = 0;\r
421             for (int i2 = j - (row.windowLength / 2);\r
422                  i2 < j + (row.windowLength / 2); i2++)\r
423             {\r
424               if (i2 < 0 || i2 >= av.alignment.getWidth())\r
425               {\r
426                 continue;\r
427               }\r
428 \r
429               total += row.annotations[i2].value;\r
430             }\r
431 \r
432             total /= row.windowLength;\r
433             height = (int) ( (total / row.graphMax) * GRAPH_HEIGHT);\r
434 \r
435           }\r
436           g.setColor(row.annotations[j].colour);\r
437           g.fillRect(x, y - height, av.charWidth, height);\r
438         }\r
439 \r
440       }\r
441 \r
442       x += av.charWidth;\r
443 \r
444       if (row.hasIcons)\r
445       {\r
446         switch (lastSS[i])\r
447         {\r
448           case 'H':\r
449             g.setColor(HELIX_COLOUR);\r
450             g.fillRoundRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i], 7,\r
451                             8, 8);\r
452             break;\r
453           case 'E':\r
454             g.setColor(SHEET_COLOUR);\r
455             g.fillRect(lastSSX[i], y + 4 + iconOffset, x - lastSSX[i] - 4, 7);\r
456             g.fillPolygon(new int[]\r
457                           {x - 4, x - 4, x}\r
458                           , new int[]\r
459                           {y + iconOffset, y + 14 + iconOffset,\r
460                           y + 7 + iconOffset}\r
461                           , 3);\r
462             break;\r
463           case 'C':\r
464             break;\r
465           default:\r
466             g.setColor(Color.gray);\r
467             g.fillRect(lastSSX[i], y + 6 + iconOffset, x - lastSSX[i], 2);\r
468             break;\r
469 \r
470         }\r
471       }\r
472 \r
473       if (row.isGraph && row.hasText)\r
474       {\r
475         y += av.charHeight;\r
476       }\r
477       if (!row.isGraph)\r
478       {\r
479         y += aa[i].height;\r
480       }\r
481     }\r
482   }\r
483 \r
484   // used by overview window\r
485   public void drawGraph(Graphics g, AlignmentAnnotation aa, int width, int y, int sRes, int eRes)\r
486   {\r
487       g.setColor(Color.white);\r
488       g.fillRect(0, 0, width, y);\r
489       g.setColor(new Color(0, 0, 180));\r
490 \r
491       int x = 0, height;\r
492 \r
493       for (int j = sRes; j < eRes; j++)\r
494       {\r
495           g.setColor(new Color(0, 0, 180));\r
496 \r
497           height = (int) ((aa.annotations[j].value / aa.graphMax) * GRAPH_HEIGHT);\r
498           if(height>y)\r
499               height = y;\r
500           g.fillRect(x, y - height, av.charWidth, height);\r
501           x += av.charWidth;\r
502       }\r
503     }\r
504 }\r