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 */ 25 package javax.swing.text; 26 27 import sun.swing.SwingUtilities2; 28 import java.awt.*; 29 import java.awt.font.FontRenderContext; 30 import 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 */ 42 public class PasswordView extends FieldView { 43 44 /** 45 * Constructs a new view wrapped on an element. 46 * 47 * @param elem the element 48 */ PasswordView(Element elem)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 drawUnselectedText(Graphics g, int x, int y, int p0, int p1)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 drawUnselectedText(Graphics2D g, float x, float y, int p0, int p1)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") drawUnselectedTextImpl(Graphics g, float x, float y, int p0, int p1, boolean useFPAPI)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 drawSelectedText(Graphics g, int x, int y, int p0, int p1)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 drawSelectedText(Graphics2D g, float x, float y, int p0, int p1)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") drawSelectedTextImpl(Graphics g, float x, float y, int p0, int p1, boolean useFPAPI)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") drawEchoCharacter(Graphics g, int x, int y, char c)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 */ drawEchoCharacter(Graphics2D g, float x, float y, char c)219 protected float drawEchoCharacter(Graphics2D g, float x, float y, char c) { 220 return drawEchoCharacterImpl(g, x, y, c, true); 221 } 222 drawEchoCharacterImpl(Graphics g, float x, float y, char c, boolean useFPAPI)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 */ modelToView(int pos, Shape a, Position.Bias b)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 */ viewToModel(float fx, float fy, Shape a, Position.Bias[] bias)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 */ getPreferredSpan(int axis)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