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 super.installUI(c); 77 installDefaults(c); 78 installComponents(c); 79 installListeners(c); 80 } 81 82 public void uninstallUI(JComponent c) { 83 // REMIND: this is NOT getting called 84 uninstallDefaults(c); 85 uninstallComponents(c); 86 uninstallListeners(c); 87 } 88 89 /** 90 * Installs default properties. 91 * 92 * @param c a component 93 */ 94 protected void installDefaults(JComponent c){ 95 LookAndFeel.installColorsAndFont(c, "ToolTip.background", 96 "ToolTip.foreground", 97 "ToolTip.font"); 98 LookAndFeel.installProperty(c, "opaque", Boolean.TRUE); 99 componentChanged(c); 100 } 101 102 /** 103 * Uninstalls default properties. 104 * 105 * @param c a component 106 */ 107 protected void uninstallDefaults(JComponent c){ 108 LookAndFeel.uninstallBorder(c); 109 } 110 111 /* Unfortunately this has to remain private until we can make API additions. 112 */ 113 private void installComponents(JComponent c){ 114 BasicHTML.updateRenderer(c, ((JToolTip) c).getTipText()); 115 } 116 117 /* Unfortunately this has to remain private until we can make API additions. 118 */ 119 private void uninstallComponents(JComponent c){ 120 BasicHTML.updateRenderer(c, ""); 121 } 122 123 /** 124 * Registers listeners. 125 * 126 * @param c a component 127 */ 128 protected void installListeners(JComponent c) { 129 propertyChangeListener = createPropertyChangeListener(c); 130 131 c.addPropertyChangeListener(propertyChangeListener); 132 } 133 134 /** 135 * Unregisters listeners. 136 * 137 * @param c a component 138 */ 139 protected void uninstallListeners(JComponent c) { 140 c.removePropertyChangeListener(propertyChangeListener); 141 142 propertyChangeListener = null; 143 } 144 145 /* Unfortunately this has to remain private until we can make API additions. 146 */ 147 private PropertyChangeListener createPropertyChangeListener(JComponent c) { 148 if (sharedPropertyChangedListener == null) { 149 sharedPropertyChangedListener = new PropertyChangeHandler(); 150 } 151 return sharedPropertyChangedListener; 152 } 153 154 public void paint(Graphics g, JComponent c) { 155 Font font = c.getFont(); 156 FontMetrics metrics = SwingUtilities2.getFontMetrics(c, g, font); 157 Dimension size = c.getSize(); 158 159 g.setColor(c.getForeground()); 160 // fix for bug 4153892 161 String tipText = ((JToolTip)c).getTipText(); 162 if (tipText == null) { 163 tipText = ""; 164 } 165 166 Insets insets = c.getInsets(); 167 Rectangle paintTextR = new Rectangle( 168 insets.left + 3, 169 insets.top, 170 size.width - (insets.left + insets.right) - 6, 171 size.height - (insets.top + insets.bottom)); 172 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 173 if (v != null) { 174 v.paint(g, paintTextR); 175 } else { 176 g.setFont(font); 177 getTextUIDrawing().drawString(c, g, tipText, paintTextR.x, 178 paintTextR.y + metrics.getAscent()); 179 } 180 } 181 182 public Dimension getPreferredSize(JComponent c) { 183 Font font = c.getFont(); 184 FontMetrics fm = c.getFontMetrics(font); 185 Insets insets = c.getInsets(); 186 187 Dimension prefSize = new Dimension(insets.left+insets.right, 188 insets.top+insets.bottom); 189 String text = ((JToolTip)c).getTipText(); 190 191 if ((text == null) || text.equals("")) { 192 text = ""; 193 } 194 else { 195 View v = (c != null) ? (View) c.getClientProperty("html") : null; 196 if (v != null) { 197 prefSize.width += (int) v.getPreferredSpan(View.X_AXIS) + 6; 198 prefSize.height += (int) v.getPreferredSpan(View.Y_AXIS); 199 } else { 200 prefSize.width += getTextUIDrawing().getStringWidth(c,fm,text) + 6; 201 prefSize.height += fm.getHeight(); 202 } 203 } 204 return prefSize; 205 } 206 207 public Dimension getMinimumSize(JComponent c) { 208 Dimension d = getPreferredSize(c); 209 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 210 if (v != null) { 211 d.width -= v.getPreferredSpan(View.X_AXIS) - v.getMinimumSpan(View.X_AXIS); 212 } 213 return d; 214 } 215 216 public Dimension getMaximumSize(JComponent c) { 217 Dimension d = getPreferredSize(c); 218 View v = (View) c.getClientProperty(BasicHTML.propertyKey); 219 if (v != null) { 220 d.width += v.getMaximumSpan(View.X_AXIS) - v.getPreferredSpan(View.X_AXIS); 221 } 222 return d; 223 } 224 225 /** 226 * Invoked when the <code>JCompoment</code> associated with the 227 * <code>JToolTip</code> has changed, or at initialization time. This 228 * should update any state dependant upon the <code>JComponent</code>. 229 * 230 * @param c the JToolTip the JComponent has changed on. 231 */ 232 private void componentChanged(JComponent c) { 233 JComponent comp = ((JToolTip)c).getComponent(); 234 235 if (comp != null && !(comp.isEnabled())) { 236 // For better backward compatibility, only install inactive 237 // properties if they are defined. 238 if (UIManager.getBorder("ToolTip.borderInactive") != null) { 239 LookAndFeel.installBorder(c, "ToolTip.borderInactive"); 240 } 241 else { 242 LookAndFeel.installBorder(c, "ToolTip.border"); 243 } 244 if (UIManager.getColor("ToolTip.backgroundInactive") != null) { 245 LookAndFeel.installColors(c,"ToolTip.backgroundInactive", 246 "ToolTip.foregroundInactive"); 247 } 248 else { 249 LookAndFeel.installColors(c,"ToolTip.background", 250 "ToolTip.foreground"); 251 } 252 } else { 253 LookAndFeel.installBorder(c, "ToolTip.border"); 254 LookAndFeel.installColors(c, "ToolTip.background", 255 "ToolTip.foreground"); 256 } 257 } 258 259 260 private static class PropertyChangeHandler implements 261 PropertyChangeListener { 262 public void propertyChange(PropertyChangeEvent e) { 263 String name = e.getPropertyName(); 264 if (name.equals("tiptext") || "font".equals(name) || 265 "foreground".equals(name)) { 266 // remove the old html view client property if one 267 // existed, and install a new one if the text installed 268 // into the JLabel is html source. 269 JToolTip tip = ((JToolTip) e.getSource()); 270 String text = tip.getTipText(); 271 BasicHTML.updateRenderer(tip, text); 272 } 273 else if ("component".equals(name)) { 274 JToolTip tip = ((JToolTip) e.getSource()); 275 276 if (tip.getUI() instanceof BasicToolTipUI) { 277 ((BasicToolTipUI)tip.getUI()).componentChanged(tip); 278 } 279 } 280 } 281 } 282 }