1 /* 2 * Copyright (c) 1997, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javax.swing.plaf.basic; 27 28 import sun.swing.SwingUtilities2; 29 import java.awt.*; 30 import java.beans.PropertyChangeEvent; 31 import java.beans.PropertyChangeListener; 32 33 import javax.swing.*; 34 import javax.swing.BorderFactory; 35 import javax.swing.border.Border; 36 import javax.swing.plaf.ToolTipUI; 37 import javax.swing.plaf.ComponentUI; 38 import javax.swing.plaf.UIResource; 39 import javax.swing.text.View; 40 41 42 /** 43 * Standard tool tip L&F. 44 * 45 * @author Dave Moore 46 */ 47 public class BasicToolTipUI extends ToolTipUI 48 { 49 static BasicToolTipUI sharedInstance = new BasicToolTipUI(); 50 /** 51 * Global <code>PropertyChangeListener</code> that 52 * <code>createPropertyChangeListener</code> returns. 53 */ 54 private static PropertyChangeListener sharedPropertyChangedListener; 55 56 private PropertyChangeListener propertyChangeListener; 57 58 /** 59 * Returns the instance of {@code BasicToolTipUI}. 60 * 61 * @param c a component 62 * @return the instance of {@code BasicToolTipUI} 63 */ 64 public static ComponentUI createUI(JComponent c) { 65 return sharedInstance; 66 } 67 68 /** 69 * Constructs a new instance of {@code BasicToolTipUI}. 70 */ 71 public BasicToolTipUI() { 72 super(); 73 } 74 75 public void installUI(JComponent c) { 76 installDefaults(c); 77 installComponents(c); 78 installListeners(c); 79 } 80 81 public void uninstallUI(JComponent c) { 82 // REMIND: this is NOT getting called 83 uninstallDefaults(c); 84 uninstallComponents(c); 85 uninstallListeners(c); 86 } 87 88 /** 89 * Installs default properties. 90 * 91 * @param c a component 92 */ 93 protected void installDefaults(JComponent c){ 94 LookAndFeel.installColorsAndFont(c, "ToolTip.background", 95 "ToolTip.foreground", 96 "ToolTip.font"); 97 LookAndFeel.installProperty(c, "opaque", Boolean.TRUE); 98 componentChanged(c); 99 } 100 101 /** 102 * Uninstalls default properties. 103 * 104 * @param c a component 105 */ 106 protected void uninstallDefaults(JComponent c){ 107 LookAndFeel.uninstallBorder(c); 108 } 109 110 /* Unfortunately this has to remain private until we can make API additions. 111 */ 112 private void installComponents(JComponent c){ 113 BasicHTML.updateRenderer(c, ((JToolTip) c).getTipText()); 114 } 115 116 /* Unfortunately this has to remain private until we can make API additions. 117 */ 118 private void uninstallComponents(JComponent c){ 119 BasicHTML.updateRenderer(c, ""); 120 } 121 122 /** 123 * Registers listeners. 124 * 125 * @param c a component 126 */ 127 protected void installListeners(JComponent c) { 128 propertyChangeListener = createPropertyChangeListener(c); 129 130 c.addPropertyChangeListener(propertyChangeListener); 131 } 132 133 /** 134 * Unregisters listeners. 135 * 136 * @param c a component 137 */ 138 protected void uninstallListeners(JComponent c) { 139 c.removePropertyChangeListener(propertyChangeListener); 140 141 propertyChangeListener = null; 142 } 143 144 /* Unfortunately this has to remain private until we can make API additions. 145 */ 146 private PropertyChangeListener createPropertyChangeListener(JComponent c) { 147 if (sharedPropertyChangedListener == null) { 148 sharedPropertyChangedListener = new PropertyChangeHandler(); 149 } 150 return sharedPropertyChangedListener; 151 } 152 153 public void paint(Graphics g, JComponent c) { 154 Font font = c.getFont(); 155 FontMetrics metrics = SwingUtilities2.getFontMetrics(c, g, font); 156 Dimension size = c.getSize(); 157 158 g.setColor(c.getForeground()); 159 // fix for bug 4153892 160 String tipText = ((JToolTip)c).getTipText(); 161 if (tipText == null) { 162 tipText = ""; 163 } 164 165 Insets insets = c.getInsets(); 166 Rectangle paintTextR = new Rectangle( 167 insets.left + 3, 168 insets.top, 169 size.width - (insets.left + insets.right) - 6, 170 size.height - (insets.top + insets.bottom)); 171 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 172 if (v != null) { 173 v.paint(g, paintTextR); 174 } else { 175 g.setFont(font); 176 SwingUtilities2.drawString(c, g, tipText, paintTextR.x, 177 paintTextR.y + metrics.getAscent()); 178 } 179 } 180 181 public Dimension getPreferredSize(JComponent c) { 182 Font font = c.getFont(); 183 FontMetrics fm = c.getFontMetrics(font); 184 Insets insets = c.getInsets(); 185 186 Dimension prefSize = new Dimension(insets.left+insets.right, 187 insets.top+insets.bottom); 188 String text = ((JToolTip)c).getTipText(); 189 190 if ((text == null) || text.equals("")) { 191 text = ""; 192 } 193 else { 194 View v = (c != null) ? (View) c.getClientProperty("html") : null; 195 if (v != null) { 196 prefSize.width += (int) v.getPreferredSpan(View.X_AXIS) + 6; 197 prefSize.height += (int) v.getPreferredSpan(View.Y_AXIS); 198 } else { 199 prefSize.width += SwingUtilities2.stringWidth(c,fm,text) + 6; 200 prefSize.height += fm.getHeight(); 201 } 202 } 203 return prefSize; 204 } 205 206 public Dimension getMinimumSize(JComponent c) { 207 Dimension d = getPreferredSize(c); 208 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 209 if (v != null) { 210 d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS); 211 } 212 return d; 213 } 214 215 public Dimension getMaximumSize(JComponent c) { 216 Dimension d = getPreferredSize(c); 217 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 218 if (v != null) { 219 d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); 220 } 221 return d; 222 } 223 224 /** 225 * Invoked when the <code>JCompoment</code> associated with the 226 * <code>JToolTip</code> has changed, or at initialization time. This 227 * should update any state dependant upon the <code>JComponent</code>. 228 * 229 * @param c the JToolTip the JComponent has changed on. 230 */ 231 private void componentChanged(JComponent c) { 232 JComponent comp = ((JToolTip)c).getComponent(); 233 234 if (comp != null && !(comp.isEnabled())) { 235 // For better backward compatibility, only install inactive 236 // properties if they are defined. 237 if (UIManager.getBorder("ToolTip.borderInactive") != null) { 238 LookAndFeel.installBorder(c, "ToolTip.borderInactive"); 239 } 240 else { 241 LookAndFeel.installBorder(c, "ToolTip.border"); 242 } 243 if (UIManager.getColor("ToolTip.backgroundInactive") != null) { 244 LookAndFeel.installColors(c,"ToolTip.backgroundInactive", 245 "ToolTip.foregroundInactive"); 246 } 247 else { 248 LookAndFeel.installColors(c,"ToolTip.background", 249 "ToolTip.foreground"); 250 } 251 } else { 252 LookAndFeel.installBorder(c, "ToolTip.border"); 253 LookAndFeel.installColors(c, "ToolTip.background", 254 "ToolTip.foreground"); 255 } 256 } 257 258 259 private static class PropertyChangeHandler implements 260 PropertyChangeListener { 261 public void propertyChange(PropertyChangeEvent e) { 262 String name = e.getPropertyName(); 263 if (name.equals("tiptext") || "font".equals(name) || 264 "foreground".equals(name)) { 265 // remove the old html view client property if one 266 // existed, and install a new one if the text installed 267 // into the JLabel is html source. 268 JToolTip tip = ((JToolTip) e.getSource()); 269 String text = tip.getTipText(); 270 BasicHTML.updateRenderer(tip, text); 271 } 272 else if ("component".equals(name)) { 273 JToolTip tip = ((JToolTip) e.getSource()); 274 275 if (tip.getUI() instanceof BasicToolTipUI) { 276 ((BasicToolTipUI)tip.getUI()).componentChanged(tip); 277 } 278 } 279 } 280 } 281 }