1 /*
2 * Copyright (c) 1998, 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.metal;
27
28 import sun.swing.SwingUtilities2;
29 import java.awt.*;
30 import java.awt.event.*;
31 import javax.swing.*;
32 import javax.swing.BorderFactory;
33 import javax.swing.border.Border;
34 import javax.swing.plaf.*;
35 import javax.swing.plaf.basic.BasicToolTipUI;
36 import javax.swing.plaf.basic.BasicHTML;
37 import javax.swing.text.View;
38
39
40 /**
41 * A Metal L&F extension of BasicToolTipUI.
42 * <p>
43 * <strong>Warning:</strong>
44 * Serialized objects of this class will not be compatible with
45 * future Swing releases. The current serialization support is
46 * appropriate for short term storage or RMI between applications running
47 * the same version of Swing. As of 1.4, support for long term storage
48 * of all JavaBeans™
49 * has been added to the <code>java.beans</code> package.
50 * Please see {@link java.beans.XMLEncoder}.
51 *
52 * @author Steve Wilson
53 */
54 @SuppressWarnings("serial") // Same-version serialization only
55 public class MetalToolTipUI extends BasicToolTipUI {
56
57 static MetalToolTipUI sharedInstance = new MetalToolTipUI();
58 private Font smallFont;
59 // Refer to note in getAcceleratorString about this field.
60 private JToolTip tip;
61
62 /**
63 * The space between strings.
64 */
65 public static final int padSpaceBetweenStrings = 12;
66 private String acceleratorDelimiter;
67
68 /**
69 * Constructs an instance of the {@code MetalToolTipUI}.
70 */
71 public MetalToolTipUI() {
72 super();
73 }
74
75 /**
76 * Returns an instance of the {@code MetalToolTipUI}.
77 *
78 * @param c a component
79 * @return an instance of the {@code MetalToolTipUI}.
80 */
81 public static ComponentUI createUI(JComponent c) {
82 return sharedInstance;
83 }
84
85 public void installUI(JComponent c) {
86 super.installUI(c);
87 tip = (JToolTip)c;
88 Font f = c.getFont();
89 smallFont = new Font( f.getName(), f.getStyle(), f.getSize() - 2 );
90 acceleratorDelimiter = UIManager.getString( "MenuItem.acceleratorDelimiter" );
91 if ( acceleratorDelimiter == null ) { acceleratorDelimiter = "-"; }
92 }
93
94 public void uninstallUI(JComponent c) {
95 super.uninstallUI(c);
96 tip = null;
97 }
98
99 public void paint(Graphics g, JComponent c) {
100 JToolTip tip = (JToolTip)c;
101 Font font = c.getFont();
102 FontMetrics metrics = SwingUtilities2.getFontMetrics(c, g, font);
103 Dimension size = c.getSize();
104 int accelBL;
105
106 g.setColor(c.getForeground());
107 // fix for bug 4153892
108 String tipText = tip.getTipText();
109 if (tipText == null) {
110 tipText = "";
111 }
112
113 String accelString = getAcceleratorString(tip);
114 FontMetrics accelMetrics = SwingUtilities2.getFontMetrics(c, g, smallFont);
115 int accelSpacing = calcAccelSpacing(c, accelMetrics, accelString);
116
117 Insets insets = tip.getInsets();
118 Rectangle paintTextR = new Rectangle(
119 insets.left + 3,
120 insets.top,
121 size.width - (insets.left + insets.right) - 6 - accelSpacing,
122 size.height - (insets.top + insets.bottom));
123 View v = (View) c.getClientProperty(BasicHTML.propertyKey);
124 if (v != null) {
125 v.paint(g, paintTextR);
126 accelBL = BasicHTML.getHTMLBaseline(v, paintTextR.width,
127 paintTextR.height);
128 } else {
129 g.setFont(font);
130 SwingUtilities2.drawString(tip, g, tipText, paintTextR.x,
131 paintTextR.y + metrics.getAscent());
132 accelBL = metrics.getAscent();
133 }
134
135 if (!accelString.equals("")) {
136 g.setFont(smallFont);
137 g.setColor( MetalLookAndFeel.getPrimaryControlDarkShadow() );
138 SwingUtilities2.drawString(tip, g, accelString,
139 tip.getWidth() - 1 - insets.right
140 - accelSpacing
141 + padSpaceBetweenStrings
142 - 3,
143 paintTextR.y + accelBL);
144 }
145 }
146
147 private int calcAccelSpacing(JComponent c, FontMetrics fm, String accel) {
148 return accel.equals("")
149 ? 0
150 : padSpaceBetweenStrings +
151 SwingUtilities2.stringWidth(c, fm, accel);
152 }
153
154 public Dimension getPreferredSize(JComponent c) {
155 Dimension d = super.getPreferredSize(c);
156
157 String key = getAcceleratorString((JToolTip)c);
158 if (!(key.equals(""))) {
159 d.width += calcAccelSpacing(c, c.getFontMetrics(smallFont), key);
160 }
161 return d;
162 }
163
164 /**
165 * If the accelerator is hidden, the method returns {@code true},
166 * otherwise, returns {@code false}.
167 *
168 * @return {@code true} if the accelerator is hidden.
169 */
170 protected boolean isAcceleratorHidden() {
171 Boolean b = (Boolean)UIManager.get("ToolTip.hideAccelerator");
172 return b != null && b.booleanValue();
173 }
174
175 private String getAcceleratorString(JToolTip tip) {
176 this.tip = tip;
177
178 String retValue = getAcceleratorString();
179
180 this.tip = null;
181 return retValue;
182 }
183
184 /**
185 * Returns the accelerator string.
186 *
187 * @return the accelerator string.
188 */
189 // NOTE: This requires the tip field to be set before this is invoked.
190 // As MetalToolTipUI is shared between all JToolTips the tip field is
191 // set appropriately before this is invoked. Unfortunately this means
192 // that subclasses that randomly invoke this method will see varying
193 // results. If this becomes an issue, MetalToolTipUI should no longer be
194 // shared.
195 public String getAcceleratorString() {
196 if (tip == null || isAcceleratorHidden()) {
197 return "";
198 }
199 JComponent comp = tip.getComponent();
200 if (!(comp instanceof AbstractButton)) {
201 return "";
202 }
203
204 KeyStroke[] keys = comp.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).keys();
205 if (keys == null) {
206 return "";
207 }
208
209 String controlKeyStr = "";
210
211 for (int i = 0; i < keys.length; i++) {
212 int mod = keys[i].getModifiers();
213 controlKeyStr = KeyEvent.getKeyModifiersText(mod) +
214 acceleratorDelimiter +
215 KeyEvent.getKeyText(keys[i].getKeyCode());
216 break;
217 }
218
219 return controlKeyStr;
220 }
221
222 }
--- EOF ---