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