package prefuse.util.ui; import java.awt.BorderLayout; import java.awt.Component; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Insets; import java.awt.Point; import java.awt.Window; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.BorderFactory; import javax.swing.JComponent; import javax.swing.JToolTip; import javax.swing.Popup; import javax.swing.PopupFactory; import javax.swing.SwingUtilities; import javax.swing.ToolTipManager; import javax.swing.event.AncestorEvent; import javax.swing.event.AncestorListener; /** * Tooltip component that allows arbitrary Swing components to be * used within tooltips. To use this class, provide the constructor * with both the source component (the component to provide the * tooltip for) and the tooltip component (a JComponent to use as the * displayed tooltip). This class can be used to provide * a custom tooltip for a prefuse {@link prefuse.Display} instance, * by registering it with the * {@link prefuse.Display#setCustomToolTip(JToolTip)} method. * * <p>In general, <code>JCustomTooltip</code> can be used with any Swing * widget. This is done by overriding JComponent's <code>createToolTip</code> * method such that it returns the custom tooltip instance.</p> * * <p>Before using this class, you might first check if you can * achieve your desired custom tooltip by using HTML formatting. * As with JLabel instances, the standard Swing tooltip mechanism includes * support for HTML tooltip text, allowing multi-line tooltips using * coloring and various fonts to be created. See * See <a href="http://examples.oreilly.com/jswing2/code/ch04/HtmlLabel.java"> * this example</a> for an instance of using HTML formatting in * a JLabel. The same HTML string could be used as the input to * JComponent's <code>setToolTipText</code> method.</p> * * @author <a href="http://jheer.org">jeffrey heer</a> */ public class JCustomTooltip extends JToolTip { private boolean m_persist = false; private Listener m_lstnr = null; /** * Create a new JCustomTooltip * @param src the component for which this is a tooltip * @param content the component to use as the tooltip content */ public JCustomTooltip(JComponent src, JComponent content) { this(src, content, false); } /** * Create a new JCustomTooltip * @param src the component for which this is a tooltip * @param content the component to use as the tooltip content * @param inter indicates if the tooltip should be interactive */ public JCustomTooltip(JComponent src, JComponent content, boolean inter) { this.setLayout(new BorderLayout()); this.setBorder(BorderFactory.createEmptyBorder(1,1,1,1)); this.setComponent(src); this.add(content); setPersistent(inter); } /** * Indicates if the tooltip will stay persistent on the screen to * support interaction within the tooltip component. * @return true if persistent, false otherwise. */ public boolean isPersistent() { return m_persist; } /** * Sets if the tooltip will stay persistent on the screen to * support interaction within the tooltip component. * @param inter true for persistence, false otherwise. */ public void setPersistent(boolean inter) { if ( inter == m_persist ) return; if ( inter ) { m_lstnr = new Listener(); this.addAncestorListener(m_lstnr); } else { this.removeAncestorListener(m_lstnr); m_lstnr = null; } m_persist = inter; } /** * Set the content component of the tooltip * @param content the tooltip content */ public void setContent(JComponent content) { this.removeAll(); this.add(content); } /** * @see java.awt.Component#getPreferredSize() */ public Dimension getPreferredSize() { if ( getComponentCount() > 0 ) { Dimension d = getComponent(0).getPreferredSize(); Insets ins = getInsets(); return new Dimension(d.width+ins.left+ins.right, d.height+ins.top+ins.bottom); } else { return super.getPreferredSize(); } } /** * @see javax.swing.JComponent#paintComponent(java.awt.Graphics) */ public void paintComponent(Graphics g) { if ( getComponentCount() > 0 ) { // paint background g.setColor(getBackground()); g.drawRect(0,0,getWidth()-1,getHeight()-1); g.setColor(getComponent(0).getBackground()); g.fillRect(1,1,getWidth()-2,getHeight()-2); } } /** * Listener class that registers the tooltip component and performs * persistence management. */ private class Listener extends MouseAdapter implements AncestorListener { private Point point = new Point(); private boolean showing = false; private Popup popup; public void ancestorAdded(AncestorEvent event) { if ( showing ) { return; } Window ttip = SwingUtilities.getWindowAncestor(getParent()); if ( ttip == null || !ttip.isVisible() ) { return; } //ttip.addMouseListener(this); ttip.getLocation(point); ttip.setVisible(false); getParent().remove(JCustomTooltip.this); JComponent c = getComponent(); c.setToolTipText(null); c.removeMouseMotionListener(ToolTipManager.sharedInstance()); popup = PopupFactory.getSharedInstance().getPopup( c, JCustomTooltip.this, point.x, point.y); Window w = SwingUtilities.getWindowAncestor(JCustomTooltip.this); w.addMouseListener(this); w.setFocusableWindowState(true); popup.show(); showing = true; } public void mouseEntered(MouseEvent e) { // Window ttip = SwingUtilities.getWindowAncestor(getParent()); // ttip.removeMouseListener(this); // if ( ttip == null || !ttip.isVisible() ) { // return; // } // ttip.getLocation(point); // ttip.hide(); // getParent().remove(JCustomTooltip.this); // // JComponent c = getComponent(); // c.setToolTipText(null); // c.removeMouseMotionListener(ToolTipManager.sharedInstance()); // // popup = PopupFactory.getSharedInstance().getPopup( // c, JCustomTooltip.this, point.x, point.y); // Window w = SwingUtilities.getWindowAncestor(JCustomTooltip.this); // w.addMouseListener(this); // w.setFocusableWindowState(true); // popup.show(); // // showing = true; } public void mouseExited(MouseEvent e) { if ( !showing ) return; int x = e.getX(), y = e.getY(); Component c = (Component)e.getSource(); if ( x < 0 || y < 0 || x > c.getWidth() || y > c.getHeight() ) { Window w = SwingUtilities.getWindowAncestor(JCustomTooltip.this); w.removeMouseListener(this); w.setFocusableWindowState(false); popup.hide(); popup = null; getComponent().setToolTipText("?"); showing = false; } } public void ancestorMoved(AncestorEvent event) { } public void ancestorRemoved(AncestorEvent event) { } } } // end of class JCustomTooltip