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