GraphGroups added
[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 = "Show Values In Textbox";\r
44     boolean active = false;\r
45     Image image;\r
46     AlignmentPanel ap;\r
47     AlignViewport av;\r
48     boolean resizing = false;\r
49     int oldY;\r
50     int mouseX;\r
51     int selectedRow = 0;\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     /**\r
112      * DOCUMENT ME!\r
113      *\r
114      * @param evt DOCUMENT ME!\r
115      */\r
116     public void actionPerformed(ActionEvent evt)\r
117     {\r
118         int dif = 0;\r
119         AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();\r
120 \r
121         if (evt.getActionCommand().equals(ADDNEW))\r
122         {\r
123             String label = JOptionPane.showInputDialog(this,\r
124                     "Label for annotation");\r
125 \r
126             if (label == null)\r
127             {\r
128                 label = "";\r
129             }\r
130 \r
131             ap.av.alignment.addAnnotation(new AlignmentAnnotation(label,\r
132                     "New description",\r
133                     new Annotation[ap.av.alignment.getWidth()]));\r
134 \r
135             dif = aa[aa.length - 1].height;\r
136         }\r
137         else if (evt.getActionCommand().equals(HIDE))\r
138         {\r
139             aa[selectedRow].visible = false;\r
140 \r
141             if (aa[selectedRow].label.equals("Conservation"))\r
142             {\r
143                 ap.av.showConservation = false;\r
144             }\r
145 \r
146             if (aa[selectedRow].label.equals("Quality"))\r
147             {\r
148                 ap.av.showQuality = false;\r
149             }\r
150 \r
151             if (aa[selectedRow].label.equals("Consensus"))\r
152             {\r
153                 ap.av.showIdentity = false;\r
154             }\r
155 \r
156             dif = aa[selectedRow].height * -1;\r
157         }\r
158         else if (evt.getActionCommand().equals(DELETE))\r
159         {\r
160             ap.av.alignment.deleteAnnotation(aa[selectedRow]);\r
161             dif = aa[selectedRow].height * -1;\r
162         }\r
163         else if (evt.getActionCommand().equals(SHOWALL))\r
164         {\r
165             for (int i = 0; i < aa.length; i++)\r
166             {\r
167                 if (!aa[i].visible)\r
168                 {\r
169                     dif += aa[i].height;\r
170                     aa[i].visible = true;\r
171                 }\r
172             }\r
173         }\r
174         else if (evt.getActionCommand().equals(OUTPUT_TEXT))\r
175         {\r
176             CutAndPasteTransfer cap = new CutAndPasteTransfer();\r
177             Desktop.addInternalFrame(cap,\r
178                 ap.alignFrame.getTitle() + " - " + aa[selectedRow].label, 500,\r
179                 100);\r
180             cap.setText(aa[selectedRow].toString());\r
181         }\r
182 \r
183 \r
184         ap.annotationPanel.adjustPanelHeight();\r
185         ap.annotationScroller.validate();\r
186         ap.repaint();\r
187     }\r
188 \r
189     /**\r
190      * DOCUMENT ME!\r
191      *\r
192      * @param evt DOCUMENT ME!\r
193      */\r
194     public void mousePressed(MouseEvent evt)\r
195     {\r
196         oldY = evt.getY();\r
197     }\r
198 \r
199     /**\r
200      * DOCUMENT ME!\r
201      *\r
202      * @param evt DOCUMENT ME!\r
203      */\r
204     public void mouseReleased(MouseEvent evt)\r
205     {\r
206         active = false;\r
207         repaint();\r
208     }\r
209 \r
210     /**\r
211      * DOCUMENT ME!\r
212      *\r
213      * @param evt DOCUMENT ME!\r
214      */\r
215     public void mouseEntered(MouseEvent evt)\r
216     {\r
217         active = true;\r
218         repaint();\r
219     }\r
220 \r
221     /**\r
222      * DOCUMENT ME!\r
223      *\r
224      * @param evt DOCUMENT ME!\r
225      */\r
226     public void mouseExited(MouseEvent evt)\r
227     {\r
228         active = false;\r
229         repaint();\r
230     }\r
231 \r
232     /**\r
233      * DOCUMENT ME!\r
234      *\r
235      * @param evt DOCUMENT ME!\r
236      */\r
237     public void mouseDragged(MouseEvent evt)\r
238     {\r
239         active = true;\r
240 \r
241         Dimension d = ap.annotationScroller.getPreferredSize();\r
242         int dif = evt.getY() - oldY;\r
243 \r
244         dif /= ap.av.charHeight;\r
245         dif *= ap.av.charHeight;\r
246 \r
247         if ((d.height - dif) > 20)\r
248         {\r
249             ap.annotationScroller.setPreferredSize(new Dimension(d.width,\r
250                     d.height - dif));\r
251             d = ap.annotationSpaceFillerHolder.getPreferredSize();\r
252             ap.annotationSpaceFillerHolder.setPreferredSize(new Dimension(\r
253                     d.width, d.height - dif));\r
254             ap.repaint();\r
255         }\r
256 \r
257         ap.addNotify();\r
258     }\r
259 \r
260     /**\r
261      * DOCUMENT ME!\r
262      *\r
263      * @param evt DOCUMENT ME!\r
264      */\r
265     public void mouseMoved(MouseEvent evt)\r
266     {\r
267     }\r
268 \r
269     /**\r
270      * DOCUMENT ME!\r
271      *\r
272      * @param evt DOCUMENT ME!\r
273      */\r
274     public void mouseClicked(MouseEvent evt)\r
275     {\r
276         int y = evt.getY() - scrollOffset;\r
277         AlignmentAnnotation[] aa = ap.av.alignment.getAlignmentAnnotation();\r
278 \r
279         if ((aa == null) || (aa.length == 0))\r
280         {\r
281             JPopupMenu pop = new JPopupMenu("Annotations");\r
282             JMenuItem item = new JMenuItem(ADDNEW);\r
283             item.addActionListener(this);\r
284             pop.add(item);\r
285             pop.show(this, evt.getX(), evt.getY());\r
286 \r
287             return;\r
288         }\r
289 \r
290         int height = 0;\r
291 \r
292         for (int i = 0; i < aa.length; i++)\r
293         {\r
294             if (!aa[i].visible)\r
295             {\r
296                 continue;\r
297             }\r
298 \r
299             height += aa[i].height;\r
300 \r
301             if (y < height)\r
302             {\r
303                 selectedRow = i;\r
304 \r
305                 break;\r
306             }\r
307         }\r
308 \r
309         JPopupMenu pop = new JPopupMenu("Annotations");\r
310         JMenuItem item = new JMenuItem(ADDNEW);\r
311         item.addActionListener(this);\r
312         pop.add(item);\r
313         item = new JMenuItem(HIDE);\r
314         item.addActionListener(this);\r
315         pop.add(item);\r
316         item = new JMenuItem(DELETE);\r
317         item.addActionListener(this);\r
318         pop.add(item);\r
319         item = new JMenuItem(SHOWALL);\r
320         item.addActionListener(this);\r
321         pop.add(item);\r
322         item = new JMenuItem(OUTPUT_TEXT);\r
323         item.addActionListener(this);\r
324         pop.add(item);\r
325 \r
326         if (aa[selectedRow].label.equals("Consensus"))\r
327         {\r
328           pop.addSeparator();\r
329           final JCheckBoxMenuItem cbmi = new JCheckBoxMenuItem(\r
330               "Ignore Gaps In Consensus",\r
331               ap.av.getIgnoreGapsConsensus());\r
332           cbmi.addActionListener(new ActionListener()\r
333               {public void actionPerformed(ActionEvent e)\r
334                {\r
335                  ap.av.setIgnoreGapsConsensus(cbmi.getState());\r
336                  ap.repaint();\r
337                }\r
338               });\r
339           pop.add(cbmi);\r
340 \r
341         }\r
342 \r
343         pop.show(this, evt.getX(), evt.getY());\r
344     }\r
345 \r
346     /**\r
347      * DOCUMENT ME!\r
348      *\r
349      * @param g1 DOCUMENT ME!\r
350      */\r
351     public void paintComponent(Graphics g)\r
352     {\r
353 \r
354         int width = getWidth();\r
355         if(width==0)\r
356          width = ap.calculateIdWidth().width + 4;\r
357 \r
358        Graphics2D g2 = (Graphics2D) g;\r
359        if(av.antiAlias)\r
360         g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,\r
361             RenderingHints.VALUE_ANTIALIAS_ON);\r
362 \r
363        drawComponent(g2, width);\r
364 \r
365     }\r
366 \r
367     /**\r
368      * DOCUMENT ME!\r
369      *\r
370      * @param g DOCUMENT ME!\r
371      */\r
372     public void drawComponent(Graphics g, int width)\r
373     {\r
374         if(av.getFont().getSize()<10)\r
375           g.setFont(new Font("Arial", Font.PLAIN, av.getFont().getSize()-1));\r
376         else\r
377           g.setFont(font);\r
378 \r
379         FontMetrics fm = g.getFontMetrics(g.getFont());\r
380         g.setColor(Color.white);\r
381         g.fillRect(0, 0, getWidth(), getHeight());\r
382 \r
383         g.translate(0, scrollOffset);\r
384         g.setColor(Color.black);\r
385 \r
386         AlignmentAnnotation[] aa = av.alignment.getAlignmentAnnotation();\r
387         int fontHeight = g.getFont().getSize();\r
388         int y = fontHeight;\r
389         int x = 0;\r
390         int graphExtras = 0;\r
391 \r
392 \r
393 \r
394         if (aa != null)\r
395         {\r
396             for (int i = 0; i < aa.length; i++)\r
397             {\r
398                 if (!aa[i].visible)\r
399                 {\r
400                     continue;\r
401                 }\r
402 \r
403                 x = width - fm.stringWidth(aa[i].label) - 3;\r
404 \r
405                 if (aa[i].graph>0)\r
406                 {\r
407                     graphExtras = y;\r
408 \r
409                     y += (aa[i].height / 3);\r
410 \r
411                     if(aa[i].graphGroup<0)\r
412                         graphExtras = y + fontHeight;\r
413                 }\r
414 \r
415                 if(aa[i].graphGroup>-1)\r
416                 {\r
417                   int groupSize = 0;\r
418                   for (int gg = 0; gg < aa.length; gg++)\r
419                   {\r
420                     if (aa[gg].graphGroup == aa[i].graphGroup)\r
421                       groupSize++;\r
422                   }\r
423 \r
424                   if(groupSize * (fontHeight+8) < aa[i].height)\r
425                     graphExtras += (aa[i].height -( groupSize * (fontHeight+8)) )/2;\r
426 \r
427                  for(int gg=0; gg<aa.length; gg++)\r
428                  {\r
429                    if(aa[gg].graphGroup==aa[i].graphGroup)\r
430                    {\r
431                      x = width - fm.stringWidth(aa[gg].label) - 3;\r
432                      g.drawString(aa[gg].label, x, graphExtras );\r
433                      if(aa[gg].annotations[0]!=null)\r
434                        g.setColor(aa[gg].annotations[0].colour);\r
435 \r
436                      g.drawLine( x, graphExtras+3,\r
437                                  x+fm.stringWidth(aa[gg].label),\r
438                                  graphExtras+3);\r
439 \r
440                      g.setColor(Color.black);\r
441                      graphExtras += fontHeight+8;\r
442                    }\r
443                  }\r
444                 }\r
445                 else\r
446                   g.drawString(aa[i].label, x, y);\r
447 \r
448                 if (aa[i].graph>0)\r
449                 {\r
450                   if (aa[i].graphLines != null)\r
451                   {\r
452                     for (int gl = 0; gl < aa[i].graphLines.size(); gl++)\r
453                     {\r
454                        x = width - fm.stringWidth(aa[i].getGraphLine(gl).label) - 3;\r
455                       g.drawString(aa[i].getGraphLine(gl).label, x, graphExtras);\r
456                       g.setColor(aa[i].getGraphLine(gl).colour);\r
457                       Graphics2D g2 = (Graphics2D) g;\r
458                       g2.setStroke(new BasicStroke(1,\r
459                           BasicStroke.CAP_SQUARE,\r
460                           BasicStroke.JOIN_ROUND, 3f,\r
461                           new float[]\r
462                           {5f, 3f}, 0f));\r
463 \r
464                       graphExtras += 3;\r
465 \r
466                       g.drawLine(x, graphExtras,\r
467                                  x+fm.stringWidth(aa[i].label),\r
468                                  graphExtras);\r
469                       g2.setStroke(new BasicStroke());\r
470                     }\r
471                   }\r
472                     y += ((2 * aa[i].height) / 3);\r
473                 }\r
474                 else\r
475                 {\r
476                     y += aa[i].height;\r
477                 }\r
478             }\r
479         }\r
480 \r
481         if (active)\r
482         {\r
483             if (image != null)\r
484             {\r
485                 g.drawImage(image, 2, 0 - scrollOffset, this);\r
486             }\r
487         }\r
488 \r
489         if ((aa == null) || (aa.length < 1))\r
490         {\r
491             g.drawString("Right click", 2, 8);\r
492             g.drawString("to add annotation", 2, 18);\r
493         }\r
494     }\r
495 }\r