patch to fix occasional arrayoutofbounds exception when working with hidden columns...
[jalview.git] / src / jalview / appletgui / Tooltip.java
1 /*\r
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.4)\r
3  * Copyright (C) 2008 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.appletgui;\r
20 \r
21 import java.applet.*;\r
22 import java.util.*;\r
23 \r
24 import java.awt.*;\r
25 import java.awt.event.*;\r
26 \r
27 public class Tooltip extends Canvas implements MouseListener,\r
28         MouseMotionListener\r
29 {\r
30   private String[] tip;\r
31 \r
32   private String lastTip = "";\r
33 \r
34   private boolean setPosition = false;\r
35 \r
36   protected Component owner;\r
37 \r
38   private Container mainContainer;\r
39 \r
40   private LayoutManager mainLayout;\r
41 \r
42   private boolean shown;\r
43 \r
44   private final int VERTICAL_OFFSET = 20;\r
45 \r
46   private final int HORIZONTAL_ENLARGE = 10;\r
47 \r
48   int fontHeight = 0;\r
49 \r
50   Image linkImage;\r
51 \r
52   FontMetrics fm;\r
53 \r
54   public Tooltip(String tip, Component owner)\r
55   {\r
56     this.owner = owner;\r
57     owner.addMouseListener(this);\r
58     owner.addMouseMotionListener(this);\r
59     setBackground(new Color(255, 255, 220));\r
60     setTip(tip);\r
61     java.net.URL url = getClass().getResource("/images/link.gif");\r
62     if (url != null)\r
63     {\r
64       linkImage = java.awt.Toolkit.getDefaultToolkit().getImage(url);\r
65     }\r
66   }\r
67 \r
68   public void paint(Graphics g)\r
69   {\r
70     int w = getSize().width;\r
71     int h = getSize().height;\r
72 \r
73     g.drawRect(0, 0, w - 1, h - 1);\r
74     int lindex, x;\r
75     for (int i = 0; i < tip.length; i++)\r
76     {\r
77       x = 3;\r
78       lindex = tip[i].indexOf("%LINK%");\r
79       if (lindex != -1)\r
80       {\r
81         if (lindex > 0)\r
82         {\r
83           g.drawString(tip[i].substring(0, lindex), 3, (i + 1) * fontHeight\r
84                   - 3);\r
85           x += fm.stringWidth(tip[i].substring(0, lindex) + 3);\r
86         }\r
87         g.drawImage(linkImage, x, i * fontHeight + 1, this);\r
88         if (lindex + 6 < tip[i].length())\r
89         {\r
90           g.drawString(tip[i].substring(lindex + 6), x\r
91                   + linkImage.getWidth(this), (i + 1) * fontHeight - 3);\r
92         }\r
93       }\r
94       else\r
95       {\r
96         g.drawString(tip[i], 3, (i + 1) * fontHeight - 3);\r
97       }\r
98     }\r
99   }\r
100 \r
101   synchronized void setTip(String tip)\r
102   {\r
103     if (tip == null)\r
104     {\r
105       setTip("");\r
106       return;\r
107     }\r
108 \r
109     if (lastTip.equals(tip))\r
110     {\r
111       return;\r
112     }\r
113 \r
114     lastTip = tip;\r
115     setPosition = true;\r
116 \r
117     fm = getFontMetrics(owner.getFont());\r
118     fontHeight = fm.getHeight();\r
119 \r
120     int longestLine = 0;\r
121     StringTokenizer st = new StringTokenizer(tip, "\n");\r
122     this.tip = new String[st.countTokens()];\r
123     int index = 0;\r
124     while (st.hasMoreElements())\r
125     {\r
126       this.tip[index] = st.nextToken();\r
127       if (fm.stringWidth(this.tip[index]) > longestLine)\r
128       {\r
129         longestLine = fm.stringWidth(this.tip[index]);\r
130       }\r
131       index++;\r
132     }\r
133 \r
134     setSize(longestLine + HORIZONTAL_ENLARGE, fontHeight * this.tip.length);\r
135 \r
136     repaint();\r
137 \r
138   }\r
139 \r
140   void setTipLocation(MouseEvent evt)\r
141   {\r
142     if (mainContainer == null || owner == null)\r
143     {\r
144       return;\r
145     }\r
146     setLocation((owner.getLocationOnScreen().x - mainContainer\r
147             .getLocationOnScreen().x)\r
148             + evt.getX(), (owner.getLocationOnScreen().y\r
149             - mainContainer.getLocationOnScreen().y + VERTICAL_OFFSET)\r
150             + evt.getY());\r
151 \r
152     // correction, whole tool tip must be visible\r
153     if (mainContainer.getSize().width < (getLocation().x + getSize().width))\r
154     {\r
155       setLocation(mainContainer.getSize().width - getSize().width,\r
156               getLocation().y);\r
157     }\r
158   }\r
159 \r
160   private void removeToolTip()\r
161   {\r
162     if (shown)\r
163     {\r
164       mainContainer.remove(0);\r
165       mainContainer.setLayout(mainLayout);\r
166       mainContainer.validate();\r
167     }\r
168     shown = false;\r
169   }\r
170 \r
171   private void findMainContainer()\r
172   {\r
173     Container parent = owner.getParent();\r
174     while (true)\r
175     {\r
176       if ((parent instanceof Applet) || (parent instanceof Frame))\r
177       {\r
178         mainContainer = parent;\r
179         break;\r
180       }\r
181       else\r
182       {\r
183         parent = parent.getParent();\r
184       }\r
185     }\r
186     mainLayout = mainContainer.getLayout();\r
187   }\r
188 \r
189   public void mouseEntered(MouseEvent me)\r
190   {\r
191     setTipLocation(me);\r
192   }\r
193 \r
194   public void mouseExited(MouseEvent me)\r
195   {\r
196     removeToolTip();\r
197   }\r
198 \r
199   public void mousePressed(MouseEvent me)\r
200   {\r
201     removeToolTip();\r
202   }\r
203 \r
204   public void mouseReleased(MouseEvent me)\r
205   {\r
206   }\r
207 \r
208   public void mouseClicked(MouseEvent me)\r
209   {\r
210   }\r
211 \r
212   public void mouseMoved(MouseEvent me)\r
213   {\r
214     if (!shown)\r
215     {\r
216       findMainContainer();\r
217       mainContainer.setLayout(null);\r
218       mainContainer.add(this, 0);\r
219       mainContainer.validate();\r
220       shown = true;\r
221       setTipLocation(me);\r
222     }\r
223     else if (setPosition)\r
224     {\r
225       setTipLocation(me);\r
226       setPosition = false;\r
227     }\r
228   }\r
229 \r
230   public void mouseDragged(MouseEvent me)\r
231   {\r
232   }\r
233 }\r