ceb736dd2d13335bcb436e3ae1e08fcf9e50411f
[jalview.git] / src / jalview / gui / AnnotationLabels.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.gui;\r
20 \r
21 import jalview.datamodel.*;\r
22 \r
23 import java.awt.*;\r
24 import java.awt.event.*;\r
25 import java.awt.image.*;\r
26 \r
27 import javax.swing.*;\r
28 \r
29 \r
30 /**\r
31  * DOCUMENT ME!\r
32  *\r
33  * @author $author$\r
34  * @version $Revision$\r
35  */\r
36 public class AnnotationLabels extends JPanel implements MouseListener,\r
37     MouseMotionListener, ActionListener\r
38 {\r
39     static String ADDNEW = "Add New Row";\r
40     static String HIDE = "Hide This Row";\r
41     static String DELETE = "Delete This Row";\r
42     static String SHOWALL = "Show All Hidden Rows";\r
43     static String OUTPUT_TEXT = "Export Annotation";\r
44     boolean resizePanel = false;\r
45     Image image;\r
46     AlignmentPanel ap;\r
47     AlignViewport av;\r
48     boolean resizing = false;\r
49     MouseEvent dragEvent;\r
50     int oldY;\r
51     int selectedRow;\r
52     int scrollOffset = 0;\r
53     Font font = new Font("Arial", Font.PLAIN, 11);\r
54 \r
55 \r
56     /**\r
57      * Creates a new AnnotationLabels object.\r
58      *\r
59      * @param ap DOCUMENT ME!\r
60      */\r
61     public AnnotationLabels(AlignmentPanel ap)\r
62     {\r
63         this.ap = ap;\r
64         av = ap.av;\r
65 \r
66         java.net.URL url = getClass().getResource("/images/idwidth.gif");\r
67         Image temp = null;\r
68 \r
69         if (url != null)\r
70         {\r
71             temp = java.awt.Toolkit.getDefaultToolkit().createImage(url);\r
72         }\r
73 \r
74         try\r
75         {\r
76             MediaTracker mt = new MediaTracker(this);\r
77             mt.addImage(temp, 0);\r
78             mt.waitForID(0);\r
79         }\r
80         catch (Exception ex)\r
81         {\r
82         }\r
83 \r
84         BufferedImage bi = new BufferedImage(temp.getHeight(this),\r
85                 temp.getWidth(this), BufferedImage.TYPE_INT_RGB);\r
86         Graphics2D g = (Graphics2D) bi.getGraphics();\r
87         g.rotate(Math.toRadians(90));\r
88         g.drawImage(temp, 0, -bi.getWidth(this), this);\r
89         image = (Image) bi;\r
90 \r
91         addMouseListener(this);\r
92         addMouseMotionListener(this);\r
93     }\r
94 \r
95     public AnnotationLabels(AlignViewport av)\r
96     {\r
97       this.av = av;\r
98     }\r
99 \r
100     /**\r
101      * DOCUMENT ME!\r
102      *\r
103      * @param y DOCUMENT ME!\r
104      */\r
105     public void setScrollOffset(int y)\r
106     {\r
107         scrollOffset = y;\r
108         repaint();\r
109     }\r
110 \r
111     void getSelectedRow(int y)\r
112     {\r
113       int height = 0;\r
114       AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();\r
115 \r
116       if(aa!=null)\r
117       {\r
118         for (int i = 0; i < aa.length; i++)\r
119         {\r
120           if (!aa[i].visible)\r
121           {\r
122             continue;\r
123           }\r
124 \r
125           height += aa[i].height;\r
126 \r
127           if (y < height)\r
128           {\r
129             selectedRow = i;\r
130 \r
131             break;\r
132           }\r
133         }\r
134       }\r
135     }\r
136 \r
137     /**\r
138      * DOCUMENT ME!\r
139      *\r
140      * @param evt DOCUMENT ME!\r
141      */\r
142     public void actionPerformed(ActionEvent evt)\r
143     {\r
144         int dif = 0;\r
145         AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();\r
146 \r
147         if (evt.getActionCommand().equals(ADDNEW))\r
148         {\r
149             String label = JOptionPane.showInputDialog(this,\r
150                     "Label for annotation");\r
151 \r
152             if (label == null)\r
153             {\r
154                 label = "";\r
155             }\r
156 \r
157             AlignmentAnnotation newAnnotation = new AlignmentAnnotation(label,\r
158                     "New description",\r
159                     new Annotation[ap.av.alignment.getWidth()]);\r
160 \r
161             ap.av.alignment.addAnnotation(newAnnotation);\r
162             ap.av.alignment.setAnnotationIndex(newAnnotation, 0);\r
163             if (aa != null)\r
164               dif = aa[aa.length - 1].height;\r
165         }\r
166         else if (evt.getActionCommand().equals(HIDE))\r
167         {\r
168             aa[selectedRow].visible = false;\r
169 \r
170             if (aa[selectedRow].label.equals("Conservation"))\r
171             {\r
172                 ap.av.showConservation = false;\r
173             }\r
174 \r
175             if (aa[selectedRow].label.equals("Quality"))\r
176             {\r
177                 ap.av.showQuality = false;\r
178             }\r
179 \r
180             if (aa[selectedRow].label.equals("Consensus"))\r
181             {\r
182                 ap.av.showIdentity = false;\r
183             }\r
184 \r
185             dif = aa[selectedRow].height * -1;\r
186         }\r
187         else if (evt.getActionCommand().equals(DELETE))\r
188         {\r
189             ap.av.alignment.deleteAnnotation(aa[selectedRow]);\r
190             dif = aa[selectedRow].height * -1;\r
191         }\r
192         else if (evt.getActionCommand().equals(SHOWALL))\r
193         {\r
194             for (int i = 0; i < aa.length; i++)\r
195             {\r
196                 if (!aa[i].visible)\r
197                 {\r
198                     dif += aa[i].height;\r
199                     aa[i].visible = true;\r
200                 }\r
201             }\r
202         }\r
203         else if (evt.getActionCommand().equals(OUTPUT_TEXT))\r
204         {\r
205           new AnnotationExporter().exportAnnotations(\r
206               ap,\r
207               new AlignmentAnnotation[]\r
208               {aa[selectedRow]}\r
209               );\r
210         }\r
211 \r
212 \r
213         ap.annotationPanel.adjustPanelHeight();\r
214         ap.annotationScroller.validate();\r
215         ap.repaint();\r
216     }\r
217 \r
218     /**\r
219      * DOCUMENT ME!\r
220      *\r
221      * @param evt DOCUMENT ME!\r
222      */\r
223     public void mousePressed(MouseEvent evt)\r
224     {\r
225         getSelectedRow(evt.getY() - scrollOffset);\r
226         oldY = evt.getY();\r
227     }\r
228 \r
229     /**\r
230      * DOCUMENT ME!\r
231      *\r
232      * @param evt DOCUMENT ME!\r
233      */\r
234     public void mouseReleased(MouseEvent evt)\r
235     {\r
236         int start = selectedRow;\r
237         getSelectedRow(evt.getY() - scrollOffset);\r
238         int end = selectedRow;\r
239 \r
240         if(start!=end)\r
241         {\r
242           //Swap these annotations\r
243           AlignmentAnnotation startAA = ap.av.alignment.getAlignmentAnnotation()[start];\r
244           AlignmentAnnotation endAA = ap.av.alignment.getAlignmentAnnotation()[end];\r
245 \r
246 \r
247           ap.av.alignment.getAlignmentAnnotation()[end] = startAA;\r
248           ap.av.alignment.getAlignmentAnnotation()[start] = endAA;\r
249         }\r
250 \r
251         resizePanel = false;\r
252         dragEvent = null;\r
253         repaint();\r
254         ap.annotationPanel.repaint();\r
255     }\r
256 \r
257     /**\r
258      * DOCUMENT ME!\r
259      *\r
260      * @param evt DOCUMENT ME!\r
261      */\r
262     public void mouseEntered(MouseEvent evt)\r
263     {\r
264       if(evt.getY()<10)\r
265       {\r
266         resizePanel = true;\r
267         repaint();\r
268       }\r
269     }\r
270 \r
271     /**\r
272      * DOCUMENT ME!\r
273      *\r
274      * @param evt DOCUMENT ME!\r
275      */\r
276     public void mouseExited(MouseEvent evt)\r
277     {\r
278       if(dragEvent == null)\r
279       {\r
280         resizePanel = false;\r
281         repaint();\r
282       }\r
283     }\r
284 \r
285     /**\r
286      * DOCUMENT ME!\r
287      *\r
288      * @param evt DOCUMENT ME!\r
289      */\r
290     public void mouseDragged(MouseEvent evt)\r
291     {\r
292       dragEvent = evt;\r
293 \r
294       if (resizePanel)\r
295       {\r
296         Dimension d = ap.annotationScroller.getPreferredSize();\r
297         int dif = evt.getY() - oldY;\r
298 \r
299         dif /= ap.av.charHeight;\r
300         dif *= ap.av.charHeight;\r
301 \r
302         if ( (d.height - dif) > 20)\r
303         {\r
304           ap.annotationScroller.setPreferredSize(new Dimension(d.width,\r
305               d.height - dif));\r
306           d = ap.annotationSpaceFillerHolder.getPreferredSize();\r
307           ap.annotationSpaceFillerHolder.setPreferredSize(new Dimension(\r
308               d.width, d.height - dif));\r
309           ap.repaint();\r
310         }\r
311 \r
312         ap.addNotify();\r
313       }\r
314       else\r
315         repaint();\r
316     }\r
317 \r
318     /**\r
319      * DOCUMENT ME!\r
320      *\r
321      * @param evt DOCUMENT ME!\r
322      */\r
323     public void mouseMoved(MouseEvent evt)\r
324     {\r
325       resizePanel = evt.getY()<10;\r
326 \r
327       repaint();\r
328     }\r
329 \r
330     /**\r
331      * DOCUMENT ME!\r
332      *\r
333      * @param evt DOCUMENT ME!\r
334      */\r
335     public void mouseClicked(MouseEvent evt)\r
336     {\r
337        if(!SwingUtilities.isRightMouseButton(evt))\r
338          return;\r
339 \r
340         AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();\r
341 \r
342         if ((aa == null) || (aa.length == 0))\r
343         {\r
344             JPopupMenu pop = new JPopupMenu("Annotations");\r
345             JMenuItem item = new JMenuItem(ADDNEW);\r
346             item.addActionListener(this);\r
347             pop.add(item);\r
348             pop.show(this, evt.getX(), evt.getY());\r
349 \r
350             return;\r
351         }\r
352 \r
353 \r
354         JPopupMenu pop = new JPopupMenu("Annotations");\r
355         JMenuItem item = new JMenuItem(ADDNEW);\r
356         item.addActionListener(this);\r
357         pop.add(item);\r
358         item = new JMenuItem(HIDE);\r
359         item.addActionListener(this);\r
360         pop.add(item);\r
361         item = new JMenuItem(DELETE);\r
362         item.addActionListener(this);\r
363         pop.add(item);\r
364         item = new JMenuItem(SHOWALL);\r
365         item.addActionListener(this);\r
366         pop.add(item);\r
367         item = new JMenuItem(OUTPUT_TEXT);\r
368         item.addActionListener(this);\r
369         pop.add(item);\r
370 \r
371         if (aa[selectedRow].label.equals("Consensus"))\r
372         {\r
373           pop.addSeparator();\r
374           final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(\r
375               "Ignore Gaps In Consensus",\r
376               ap.av.getIgnoreGapsConsensus());\r
377           cbmi.addActionListener(new ActionListener()\r
378               {public void actionPerformed(ActionEvent e)\r
379                {\r
380                  ap.av.setIgnoreGapsConsensus(cbmi.getState());\r
381                  ap.repaint();\r
382                }\r
383               });\r
384           pop.add(cbmi);\r
385 \r
386         }\r
387 \r
388         pop.show(this, evt.getX(), evt.getY());\r
389     }\r
390 \r
391     /**\r
392      * DOCUMENT ME!\r
393      *\r
394      * @param g1 DOCUMENT ME!\r
395      */\r
396     public void paintComponent(Graphics g)\r
397     {\r
398 \r
399         int width = getWidth();\r
400         if(width==0)\r
401          width = ap.calculateIdWidth().width + 4;\r
402 \r
403        Graphics2D g2 = (Graphics2D) g;\r
404        if(av.antiAlias)\r
405         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
406             RenderingHints.VALUE_ANTIALIAS_ON);\r
407 \r
408        drawComponent(g2, width);\r
409 \r
410     }\r
411 \r
412     /**\r
413      * DOCUMENT ME!\r
414      *\r
415      * @param g DOCUMENT ME!\r
416      */\r
417     public void drawComponent(Graphics g, int width)\r
418     {\r
419         if(av.getFont().getSize()<10)\r
420           g.setFont(font);\r
421         else\r
422           g.setFont(av.getFont());\r
423 \r
424         FontMetrics fm = g.getFontMetrics(g.getFont());\r
425         g.setColor(Color.white);\r
426         g.fillRect(0, 0, getWidth(), getHeight());\r
427 \r
428         g.translate(0, scrollOffset);\r
429         g.setColor(Color.black);\r
430 \r
431         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
432         int fontHeight = g.getFont().getSize();\r
433         int y = fontHeight;\r
434         int x = 0;\r
435         int graphExtras = 0;\r
436 \r
437 \r
438 \r
439         if (aa != null)\r
440         {\r
441             for (int i = 0; i < aa.length; i++)\r
442             {\r
443                 if (!aa[i].visible)\r
444                 {\r
445                     continue;\r
446                 }\r
447 \r
448                 x = width - fm.stringWidth(aa[i].label) - 3;\r
449 \r
450                 if (aa[i].graph>0)\r
451                 {\r
452                     graphExtras = y;\r
453 \r
454                     y += (aa[i].height / 3);\r
455 \r
456                     if(aa[i].graphGroup<0)\r
457                         graphExtras = y + fontHeight;\r
458                 }\r
459 \r
460                 if(aa[i].graphGroup>-1)\r
461                 {\r
462                   int groupSize = 0;\r
463                   for (int gg = 0; gg < aa.length; gg++)\r
464                   {\r
465                     if (aa[gg].graphGroup == aa[i].graphGroup)\r
466                       groupSize++;\r
467                   }\r
468 \r
469                   if(groupSize * (fontHeight+8) < aa[i].height)\r
470                     graphExtras += (aa[i].height -( groupSize * (fontHeight+8)) )/2;\r
471 \r
472                  for(int gg=0; gg<aa.length; gg++)\r
473                  {\r
474                    if(aa[gg].graphGroup==aa[i].graphGroup)\r
475                    {\r
476                      x = width - fm.stringWidth(aa[gg].label) - 3;\r
477                      g.drawString(aa[gg].label, x, graphExtras );\r
478                      if(aa[gg].annotations[0]!=null)\r
479                        g.setColor(aa[gg].annotations[0].colour);\r
480 \r
481                      g.drawLine( x, graphExtras+3,\r
482                                  x+fm.stringWidth(aa[gg].label),\r
483                                  graphExtras+3);\r
484 \r
485                      g.setColor(Color.black);\r
486                      graphExtras += fontHeight+8;\r
487                    }\r
488                  }\r
489                 }\r
490                 else\r
491                   g.drawString(aa[i].label, x, y);\r
492 \r
493                 if (aa[i].graph>0)\r
494                 {\r
495                 /*  if (aa[i].graphLines != null)\r
496                   {\r
497                     for (int gl = 0; gl < aa[i].graphLines.size(); gl++)\r
498                     {\r
499                        x = width - fm.stringWidth(aa[i].getGraphLine(gl).label) - 3;\r
500                       g.drawString(aa[i].getGraphLine(gl).label, x, graphExtras);\r
501                       g.setColor(aa[i].getGraphLine(gl).colour);\r
502                       Graphics2D g2 = (Graphics2D) g;\r
503                       g2.setStroke(new BasicStroke(1,\r
504                           BasicStroke.CAP_SQUARE,\r
505                           BasicStroke.JOIN_ROUND, 3f,\r
506                           new float[]\r
507                           {5f, 3f}, 0f));\r
508 \r
509                       graphExtras += 3;\r
510 \r
511                       g.drawLine(x, graphExtras,\r
512                                  x+fm.stringWidth(aa[i].label),\r
513                                  graphExtras);\r
514                       g2.setStroke(new BasicStroke());\r
515                     }\r
516                   }*/\r
517                     y += ((2 * aa[i].height) / 3);\r
518                 }\r
519                 else\r
520                 {\r
521                     y += aa[i].height;\r
522                 }\r
523             }\r
524         }\r
525 \r
526         if (resizePanel)\r
527         {\r
528           g.drawImage(image, 2, 0 - scrollOffset, this);\r
529         }\r
530         else if (dragEvent != null && aa!=null)\r
531         {\r
532           g.setColor(Color.lightGray);\r
533           g.drawString(aa[selectedRow].label, dragEvent.getX(), dragEvent.getY() - scrollOffset);\r
534         }\r
535 \r
536 \r
537         if ((aa == null) || (aa.length < 1))\r
538         {\r
539             g.drawString("Right click", 2, 8);\r
540             g.drawString("to add annotation", 2, 18);\r
541         }\r
542     }\r
543 }\r