be03c52bc7bb42d6731c1eeb4a13e19868aa138c
[jalview.git] / src / jalview / appletgui / Tooltip.java
1 /*
2  * Jalview - A Sequence Alignment Editor and Viewer (Version 2.8)
3  * Copyright (C) 2012 J Procter, AM Waterhouse, LM Lui, J Engelhardt, G Barton, M Clamp, S Searle
4  * 
5  * This file is part of Jalview.
6  * 
7  * Jalview is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License 
9  * as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
10  *  
11  * Jalview is distributed in the hope that it will be useful, but 
12  * WITHOUT ANY WARRANTY; without even the implied warranty 
13  * of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
14  * PURPOSE.  See the GNU General Public License for more details.
15  * 
16  * You should have received a copy of the GNU General Public License along with Jalview.  If not, see <http://www.gnu.org/licenses/>.
17  */
18 package jalview.appletgui;
19
20 import java.applet.*;
21 import java.util.*;
22
23 import java.awt.*;
24 import java.awt.event.*;
25
26 public class Tooltip extends Canvas implements MouseListener,
27         MouseMotionListener
28 {
29   private String[] tip;
30
31   private String lastTip = "";
32
33   private boolean setPosition = false;
34
35   protected Component owner;
36
37   private Container mainContainer;
38
39   private LayoutManager mainLayout;
40
41   private boolean shown;
42
43   private final int VERTICAL_OFFSET = 20;
44
45   private final int HORIZONTAL_ENLARGE = 10;
46
47   int fontHeight = 0;
48
49   Image linkImage;
50
51   FontMetrics fm;
52
53   public Tooltip(String tip, Component owner)
54   {
55     this.owner = owner;
56     owner.addMouseListener(this);
57     owner.addMouseMotionListener(this);
58     setBackground(new Color(255, 255, 220));
59     setTip(tip);
60     java.net.URL url = getClass().getResource("/images/link.gif");
61     if (url != null)
62     {
63       linkImage = java.awt.Toolkit.getDefaultToolkit().getImage(url);
64     }
65   }
66
67   public void paint(Graphics g)
68   {
69     int w = getSize().width;
70     int h = getSize().height;
71
72     g.drawRect(0, 0, w - 1, h - 1);
73     int lindex, x;
74     for (int i = 0; i < tip.length; i++)
75     {
76       x = 3;
77       lindex = tip[i].indexOf("%LINK%");
78       if (lindex != -1)
79       {
80         if (lindex > 0)
81         {
82           g.drawString(tip[i].substring(0, lindex), 3, (i + 1) * fontHeight
83                   - 3);
84           x += fm.stringWidth(tip[i].substring(0, lindex) + 3);
85         }
86         g.drawImage(linkImage, x, i * fontHeight + 1, this);
87         if (lindex + 6 < tip[i].length())
88         {
89           g.drawString(tip[i].substring(lindex + 6),
90                   x + linkImage.getWidth(this), (i + 1) * fontHeight - 3);
91         }
92       }
93       else
94       {
95         g.drawString(tip[i], 3, (i + 1) * fontHeight - 3);
96       }
97     }
98   }
99
100   synchronized void setTip(String tip)
101   {
102     if (tip == null)
103     {
104       setTip("");
105       return;
106     }
107
108     if (lastTip.equals(tip))
109     {
110       return;
111     }
112
113     lastTip = tip;
114     setPosition = true;
115
116     fm = getFontMetrics(owner.getFont());
117     fontHeight = fm.getHeight();
118
119     int longestLine = 0;
120     StringTokenizer st = new StringTokenizer(tip, "\n");
121     this.tip = new String[st.countTokens()];
122     int index = 0;
123     while (st.hasMoreElements())
124     {
125       this.tip[index] = st.nextToken();
126       if (fm.stringWidth(this.tip[index]) > longestLine)
127       {
128         longestLine = fm.stringWidth(this.tip[index]);
129       }
130       index++;
131     }
132
133     setSize(longestLine + HORIZONTAL_ENLARGE, fontHeight * this.tip.length);
134
135     repaint();
136
137   }
138
139   void setTipLocation(MouseEvent evt)
140   {
141     if (mainContainer == null || owner == null)
142     {
143       return;
144     }
145     setLocation(
146             (owner.getLocationOnScreen().x - mainContainer.getLocationOnScreen().x)
147                     + evt.getX(),
148             (owner.getLocationOnScreen().y
149                     - mainContainer.getLocationOnScreen().y + VERTICAL_OFFSET)
150                     + evt.getY());
151
152     // correction, whole tool tip must be visible
153     if (mainContainer.getSize().width < (getLocation().x + getSize().width))
154     {
155       setLocation(mainContainer.getSize().width - getSize().width,
156               getLocation().y);
157     }
158   }
159
160   private void removeToolTip()
161   {
162     if (shown)
163     {
164       mainContainer.remove(0);
165       mainContainer.setLayout(mainLayout);
166       mainContainer.validate();
167     }
168     shown = false;
169   }
170
171   private void findMainContainer()
172   {
173     Container parent = owner.getParent();
174     while (true)
175     {
176       if ((parent instanceof Applet) || (parent instanceof Frame))
177       {
178         mainContainer = parent;
179         break;
180       }
181       else
182       {
183         parent = parent.getParent();
184       }
185     }
186     mainLayout = mainContainer.getLayout();
187   }
188
189   public void mouseEntered(MouseEvent me)
190   {
191     setTipLocation(me);
192   }
193
194   public void mouseExited(MouseEvent me)
195   {
196     removeToolTip();
197   }
198
199   public void mousePressed(MouseEvent me)
200   {
201     removeToolTip();
202   }
203
204   public void mouseReleased(MouseEvent me)
205   {
206   }
207
208   public void mouseClicked(MouseEvent me)
209   {
210   }
211
212   public void mouseMoved(MouseEvent me)
213   {
214     if (!shown)
215     {
216       findMainContainer();
217       mainContainer.setLayout(null);
218       mainContainer.add(this, 0);
219       mainContainer.validate();
220       shown = true;
221       setTipLocation(me);
222     }
223     else if (setPosition)
224     {
225       setTipLocation(me);
226       setPosition = false;
227     }
228   }
229
230   public void mouseDragged(MouseEvent me)
231   {
232   }
233 }