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