1/* 2 * Copyright (c) 1997, 2013, 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 */ 25package javax.swing.text; 26 27import sun.swing.SwingUtilities2; 28import java.awt.*; 29import java.awt.font.FontRenderContext; 30import javax.swing.JPasswordField; 31 32/** 33 * Implements a View suitable for use in JPasswordField 34 * UI implementations. This is basically a field ui that 35 * renders its contents as the echo character specified 36 * in the associated component (if it can narrow the 37 * component to a JPasswordField). 38 * 39 * @author Timothy Prinzing 40 * @see View 41 */ 42public class PasswordView extends FieldView { 43 44 /** 45 * Constructs a new view wrapped on an element. 46 * 47 * @param elem the element 48 */ 49 public PasswordView(Element elem) { 50 super(elem); 51 } 52 53 /** 54 * Renders the given range in the model as normal unselected 55 * text. This sets the foreground color and echos the characters 56 * using the value returned by getEchoChar(). 57 * 58 * @param g the graphics context 59 * @param x the starting X coordinate >= 0 60 * @param y the starting Y coordinate >= 0 61 * @param p0 the starting offset in the model >= 0 62 * @param p1 the ending offset in the model >= p0 63 * @return the X location of the end of the range >= 0 64 * @exception BadLocationException if p0 or p1 are out of range 65 * 66 * @deprecated replaced by 67 * {@link #drawUnselectedText(Graphics2D, float, float, int, int)} 68 */ 69 @Deprecated(since = "9") 70 @Override 71 protected int drawUnselectedText(Graphics g, int x, int y, 72 int p0, int p1) throws BadLocationException { 73 return (int) drawUnselectedTextImpl(g, x, y, p0, p1, false); 74 } 75 76 @Override 77 protected float drawUnselectedText(Graphics2D g, float x, float y, 78 int p0, int p1) 79 throws BadLocationException 80 { 81 return drawUnselectedTextImpl(g, x, y, p0, p1, true); 82 } 83 84 @SuppressWarnings("deprecation") 85 private float drawUnselectedTextImpl(Graphics g, float x, float y, 86 int p0, int p1, 87 boolean useFPAPI) 88 throws BadLocationException 89 { 90 Container c = getContainer(); 91 if (c instanceof JPasswordField) { 92 JPasswordField f = (JPasswordField) c; 93 if (!f.echoCharIsSet()) { 94 boolean useDrawUnselectedFPAPI = useFPAPI 95 && drawUnselectedTextOverridden 96 && g instanceof Graphics2D; 97 return (useDrawUnselectedFPAPI ) 98 ? super.drawUnselectedText((Graphics2D) g, x, y, p0, p1) 99 : super.drawUnselectedText(g, (int) x, (int) y, p0, p1); 100 } 101 if (f.isEnabled()) { 102 g.setColor(f.getForeground()); 103 } 104 else { 105 g.setColor(f.getDisabledTextColor()); 106 } 107 char echoChar = f.getEchoChar(); 108 int n = p1 - p0; 109 boolean useEchoCharFPAPI = useFPAPI 110 && drawEchoCharacterOverridden 111 && g instanceof Graphics2D; 112 for (int i = 0; i < n; i++) { 113 x = (useEchoCharFPAPI) 114 ? drawEchoCharacter((Graphics2D) g, x, y, echoChar) 115 : drawEchoCharacter(g, (int) x, (int) y, echoChar); 116 } 117 } 118 return x; 119 } 120 121 /** 122 * Renders the given range in the model as selected text. This 123 * is implemented to render the text in the color specified in 124 * the hosting component. It assumes the highlighter will render 125 * the selected background. Uses the result of getEchoChar() to 126 * display the characters. 127 * 128 * @param g the graphics context 129 * @param x the starting X coordinate >= 0 130 * @param y the starting Y coordinate >= 0 131 * @param p0 the starting offset in the model >= 0 132 * @param p1 the ending offset in the model >= p0 133 * @return the X location of the end of the range >= 0 134 * @exception BadLocationException if p0 or p1 are out of range 135 * 136 * @deprecated replaced by 137 * {@link #drawSelectedText(Graphics2D, float, float, int, int)} 138 */ 139 @Deprecated(since = "9") 140 @Override 141 protected int drawSelectedText(Graphics g, int x, 142 int y, int p0, int p1) throws BadLocationException { 143 return (int) drawSelectedTextImpl(g, x, y, p0, p1, false); 144 } 145 146 @Override 147 protected float drawSelectedText(Graphics2D g, float x, float y, 148 int p0, int p1) throws BadLocationException 149 { 150 return drawSelectedTextImpl(g, x, y, p0, p1, true); 151 } 152 153 @SuppressWarnings("deprecation") 154 private float drawSelectedTextImpl(Graphics g, float x, float y, 155 int p0, int p1, 156 boolean useFPAPI) 157 throws BadLocationException { 158 g.setColor(selected); 159 Container c = getContainer(); 160 if (c instanceof JPasswordField) { 161 JPasswordField f = (JPasswordField) c; 162 if (!f.echoCharIsSet()) { 163 boolean useDrawUnselectedFPAPI = useFPAPI 164 && drawSelectedTextOverridden 165 && g instanceof Graphics2D; 166 return (useFPAPI) 167 ? super.drawSelectedText((Graphics2D) g, x, y, p0, p1) 168 : super.drawSelectedText(g, (int) x, (int) y, p0, p1); 169 } 170 char echoChar = f.getEchoChar(); 171 int n = p1 - p0; 172 boolean useEchoCharFPAPI = useFPAPI 173 && drawEchoCharacterOverridden 174 && g instanceof Graphics2D; 175 for (int i = 0; i < n; i++) { 176 x = (useEchoCharFPAPI) 177 ? drawEchoCharacter((Graphics2D) g, x, y, echoChar) 178 : drawEchoCharacter(g, (int) x, (int) y, echoChar); 179 180 } 181 } 182 return x; 183 } 184 185 /** 186 * Renders the echo character, or whatever graphic should be used 187 * to display the password characters. The color in the Graphics 188 * object is set to the appropriate foreground color for selected 189 * or unselected text. 190 * 191 * @param g the graphics context 192 * @param x the starting X coordinate >= 0 193 * @param y the starting Y coordinate >= 0 194 * @param c the echo character 195 * @return the updated X position >= 0 196 * 197 * @deprecated replaced by 198 * {@link #drawEchoCharacter(Graphics2D, float, float, char)} 199 */ 200 @Deprecated(since = "9") 201 protected int drawEchoCharacter(Graphics g, int x, int y, char c) { 202 return (int) drawEchoCharacterImpl(g, x, y, c, false); 203 } 204 205 /** 206 * Renders the echo character, or whatever graphic should be used 207 * to display the password characters. The color in the Graphics 208 * object is set to the appropriate foreground color for selected 209 * or unselected text. 210 * 211 * @param g the graphics context 212 * @param x the starting X coordinate {@code >= 0} 213 * @param y the starting Y coordinate {@code >= 0} 214 * @param c the echo character 215 * @return the updated X position {@code >= 0} 216 * 217 * @since 9 218 */ 219 protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) { 220 return drawEchoCharacterImpl(g, x, y, c, true); 221 } 222 223 private float drawEchoCharacterImpl(Graphics g, float x, float y, 224 char c, boolean useFPAPI) { 225 ONE[0] = c; 226 SwingUtilities2.drawChars(Utilities.getJComponent(this), 227 g, ONE, 0, 1, x, y); 228 if (useFPAPI) { 229 return x + g.getFontMetrics().charWidth(c); 230 } else { 231 FontRenderContext frc = g.getFontMetrics().getFontRenderContext(); 232 return x + (float) g.getFont().getStringBounds(ONE, 0, 1, frc).getWidth(); 233 } 234 } 235 236 /** 237 * Provides a mapping from the document model coordinate space 238 * to the coordinate space of the view mapped to it. 239 * 240 * @param pos the position to convert >= 0 241 * @param a the allocated region to render into 242 * @return the bounding box of the given position 243 * @exception BadLocationException if the given position does not 244 * represent a valid location in the associated document 245 * @see View#modelToView 246 */ 247 public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException { 248 Container c = getContainer(); 249 if (c instanceof JPasswordField) { 250 JPasswordField f = (JPasswordField) c; 251 if (! f.echoCharIsSet()) { 252 return super.modelToView(pos, a, b); 253 } 254 char echoChar = f.getEchoChar(); 255 FontMetrics m = f.getFontMetrics(f.getFont()); 256 257 Rectangle alloc = adjustAllocation(a).getBounds(); 258 int dx = (pos - getStartOffset()) * m.charWidth(echoChar); 259 alloc.x += dx; 260 alloc.width = 1; 261 return alloc; 262 } 263 return null; 264 } 265 266 /** 267 * Provides a mapping from the view coordinate space to the logical 268 * coordinate space of the model. 269 * 270 * @param fx the X coordinate >= 0.0f 271 * @param fy the Y coordinate >= 0.0f 272 * @param a the allocated region to render into 273 * @return the location within the model that best represents the 274 * given point in the view 275 * @see View#viewToModel 276 */ 277 public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) { 278 bias[0] = Position.Bias.Forward; 279 int n = 0; 280 Container c = getContainer(); 281 if (c instanceof JPasswordField) { 282 JPasswordField f = (JPasswordField) c; 283 if (! f.echoCharIsSet()) { 284 return super.viewToModel(fx, fy, a, bias); 285 } 286 char echoChar = f.getEchoChar(); 287 int charWidth = f.getFontMetrics(f.getFont()).charWidth(echoChar); 288 a = adjustAllocation(a); 289 Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a : 290 a.getBounds(); 291 n = (charWidth > 0 ? 292 ((int)fx - alloc.x) / charWidth : Integer.MAX_VALUE); 293 if (n < 0) { 294 n = 0; 295 } 296 else if (n > (getStartOffset() + getDocument().getLength())) { 297 n = getDocument().getLength() - getStartOffset(); 298 } 299 } 300 return getStartOffset() + n; 301 } 302 303 /** 304 * Determines the preferred span for this view along an 305 * axis. 306 * 307 * @param axis may be either View.X_AXIS or View.Y_AXIS 308 * @return the span the view would like to be rendered into >= 0. 309 * Typically the view is told to render into the span 310 * that is returned, although there is no guarantee. 311 * The parent may choose to resize or break the view. 312 */ 313 public float getPreferredSpan(int axis) { 314 switch (axis) { 315 case View.X_AXIS: 316 Container c = getContainer(); 317 if (c instanceof JPasswordField) { 318 JPasswordField f = (JPasswordField) c; 319 if (f.echoCharIsSet()) { 320 char echoChar = f.getEchoChar(); 321 FontMetrics m = f.getFontMetrics(f.getFont()); 322 Document doc = getDocument(); 323 return m.charWidth(echoChar) * getDocument().getLength(); 324 } 325 } 326 } 327 return super.getPreferredSpan(axis); 328 } 329 330 static char[] ONE = new char[1]; 331 332 private final boolean drawEchoCharacterOverridden = 333 getFPMethodOverridden(getClass(), "drawEchoCharacter", FPMethodArgs.GNNC); 334} 335