001/* BasicToolTipUI.java --
002   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
003
004This file is part of GNU Classpath.
005
006GNU Classpath is free software; you can redistribute it and/or modify
007it under the terms of the GNU General Public License as published by
008the Free Software Foundation; either version 2, or (at your option)
009any later version.
010
011GNU Classpath is distributed in the hope that it will be useful, but
012WITHOUT ANY WARRANTY; without even the implied warranty of
013MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014General Public License for more details.
015
016You should have received a copy of the GNU General Public License
017along with GNU Classpath; see the file COPYING.  If not, write to the
018Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
01902110-1301 USA.
020
021Linking this library statically or dynamically with other modules is
022making a combined work based on this library.  Thus, the terms and
023conditions of the GNU General Public License cover the whole
024combination.
025
026As a special exception, the copyright holders of this library give you
027permission to link this library with independent modules to produce an
028executable, regardless of the license terms of these independent
029modules, and to copy and distribute the resulting executable under
030terms of your choice, provided that you also meet, for each linked
031independent module, the terms and conditions of the license of that
032module.  An independent module is a module which is not derived from
033or based on this library.  If you modify this library, you may extend
034this exception to your version of the library, but you are not
035obligated to do so.  If you do not wish to do so, delete this
036exception statement from your version. */
037
038
039package javax.swing.plaf.basic;
040
041import java.awt.Color;
042import java.awt.Dimension;
043import java.awt.Font;
044import java.awt.FontMetrics;
045import java.awt.Graphics;
046import java.awt.Insets;
047import java.awt.Rectangle;
048import java.beans.PropertyChangeEvent;
049import java.beans.PropertyChangeListener;
050
051import javax.swing.JComponent;
052import javax.swing.JToolTip;
053import javax.swing.LookAndFeel;
054import javax.swing.plaf.ComponentUI;
055import javax.swing.plaf.ToolTipUI;
056import javax.swing.text.View;
057
058/**
059 * This is the Basic Look and Feel UI class for JToolTip.
060 */
061public class BasicToolTipUI extends ToolTipUI
062{
063
064  /**
065   * Receives notification when a property of the JToolTip changes.
066   * This updates the HTML renderer if appropriate.
067   */
068  private class PropertyChangeHandler
069    implements PropertyChangeListener
070  {
071
072    public void propertyChange(PropertyChangeEvent e)
073    {
074      String prop = e.getPropertyName();
075      if (prop.equals("tiptext") || prop.equals("font")
076          || prop.equals("foreground"))
077        {
078          JToolTip tip = (JToolTip) e.getSource();
079          String text = tip.getTipText();
080          BasicHTML.updateRenderer(tip, text);
081        }
082    }
083
084  }
085
086  /** The shared instance of BasicToolTipUI used for all ToolTips. */
087  private static BasicToolTipUI shared;
088
089  /** The tooltip's text */
090  private String text;
091
092  /**
093   * Handles property changes.
094   */
095  private PropertyChangeListener propertyChangeHandler;
096
097  /**
098   * Creates a new BasicToolTipUI object.
099   */
100  public BasicToolTipUI()
101  {
102    super();
103  }
104
105  /**
106   * This method creates a new BasicToolTip UI for the given
107   * JComponent.
108   *
109   * @param c The JComponent to create a UI for.
110   *
111   * @return A BasicToolTipUI that can be used by the given JComponent.
112   */
113  public static ComponentUI createUI(JComponent c)
114  {
115    if (shared == null)
116      shared = new BasicToolTipUI();
117    return shared;
118  }
119
120  /**
121   * This method returns the msximum size of the given JComponent.
122   *
123   * @param c The JComponent to find a maximum size for.
124   *
125   * @return The maximum size.
126   */
127  public Dimension getMaximumSize(JComponent c)
128  {
129    Dimension d = getPreferredSize(c);
130    View view = (View) c.getClientProperty(BasicHTML.propertyKey);
131    if (view != null)
132      d.width += view.getMaximumSpan(View.X_AXIS)
133                 - view.getPreferredSpan(View.X_AXIS);
134    return d;
135  }
136
137  /**
138   * This method returns the minimum size of the given JComponent.
139   *
140   * @param c The JComponent to find a minimum size for.
141   *
142   * @return The minimum size.
143   */
144  public Dimension getMinimumSize(JComponent c)
145  {
146    Dimension d = getPreferredSize(c);
147    View view = (View) c.getClientProperty(BasicHTML.propertyKey);
148    if (view != null)
149      d.width -= view.getPreferredSpan(View.X_AXIS)
150                 - view.getMinimumSpan(View.X_AXIS);
151    return d;
152  }
153
154  /**
155   * This method returns the preferred size of the given JComponent.
156   *
157   * @param c The JComponent to find a preferred size for.
158   *
159   * @return The preferred size.
160   */
161  public Dimension getPreferredSize(JComponent c)
162  {
163    JToolTip tip = (JToolTip) c;
164    String str = tip.getTipText();
165    FontMetrics fm = c.getFontMetrics(c.getFont());
166    Insets i = c.getInsets();
167    Dimension d = new Dimension(i.left + i.right, i.top + i.bottom);
168    if (str != null && ! str.equals(""))
169      {
170        View view = (View) c.getClientProperty(BasicHTML.propertyKey);
171        if (view != null)
172          {
173            d.width += (int) view.getPreferredSpan(View.X_AXIS);
174            d.height += (int) view.getPreferredSpan(View.Y_AXIS);
175          }
176        else
177          {
178            d.width += fm.stringWidth(str) + 6;
179            d.height += fm.getHeight();
180          }
181      }
182    return d;
183  }
184
185  /**
186   * This method installs the defaults for the given JComponent.
187   *
188   * @param c The JComponent to install defaults for.
189   */
190  protected void installDefaults(JComponent c)
191  {
192    LookAndFeel.installColorsAndFont(c, "ToolTip.background",
193                                     "ToolTip.foreground", "ToolTip.font");
194    LookAndFeel.installBorder(c, "ToolTip.border");
195  }
196
197  /**
198   * This method installs the listeners for the given JComponent.
199   *
200   * @param c The JComponent to install listeners for.
201   */
202  protected void installListeners(JComponent c)
203  {
204    propertyChangeHandler = new PropertyChangeHandler();
205    c.addPropertyChangeListener(propertyChangeHandler);
206  }
207
208  /**
209   * This method installs the UI for the given JComponent.
210   *
211   * @param c The JComponent to install the UI for.
212   */
213  public void installUI(JComponent c)
214  {
215    c.setOpaque(true);
216    installDefaults(c);
217    BasicHTML.updateRenderer(c, ((JToolTip) c).getTipText());
218    installListeners(c);
219  }
220
221  /**
222   * This method paints the given JComponent with the given Graphics object.
223   *
224   * @param g The Graphics object to paint with.
225   * @param c The JComponent to paint.
226   */
227  public void paint(Graphics g, JComponent c)
228  {
229    JToolTip tip = (JToolTip) c;
230
231    String text = tip.getTipText();
232    Font font = c.getFont();
233    FontMetrics fm = c.getFontMetrics(font);
234    int ascent = fm.getAscent();
235    Insets i = c.getInsets();
236    Dimension size = c.getSize();
237    Rectangle paintR = new Rectangle(i.left, i.top,
238                                     size.width - i.left - i.right,
239                                     size.height - i.top - i.bottom);
240    Color saved = g.getColor();
241    Font oldFont = g.getFont();
242    g.setColor(Color.BLACK);
243
244    View view = (View) c.getClientProperty(BasicHTML.propertyKey);
245    if (view != null)
246      view.paint(g, paintR);
247    else
248      g.drawString(text, paintR.x + 3, paintR.y + ascent);
249
250    g.setFont(oldFont);
251    g.setColor(saved);
252  }
253
254  /**
255   * This method uninstalls the defaults for the given JComponent.
256   *
257   * @param c The JComponent to uninstall defaults for.
258   */
259  protected void uninstallDefaults(JComponent c)
260  {
261    c.setForeground(null);
262    c.setBackground(null);
263    c.setFont(null);
264    c.setBorder(null);
265  }
266
267  /**
268   * This method uninstalls listeners for the given JComponent.
269   *
270   * @param c The JComponent to uninstall listeners for.
271   */
272  protected void uninstallListeners(JComponent c)
273  {
274    if (propertyChangeHandler != null)
275      {
276        c.removePropertyChangeListener(propertyChangeHandler);
277        propertyChangeHandler = null;
278      }
279  }
280
281  /**
282   * This method uninstalls the UI for the given JComponent.
283   *
284   * @param c The JComponent to uninstall.
285   */
286  public void uninstallUI(JComponent c)
287  {
288    uninstallDefaults(c);
289    BasicHTML.updateRenderer(c, "");
290    uninstallListeners(c);
291  }
292}