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