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