1. /*
  2. * @(#)PasswordView.java 1.18 03/01/23
  3. *
  4. * Copyright 2003 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package javax.swing.text;
  8. import java.awt.*;
  9. import javax.swing.JPasswordField;
  10. /**
  11. * Implements a View suitable for use in JPasswordField
  12. * UI implementations. This is basically a field ui that
  13. * renders its contents as the echo character specified
  14. * in the associated component (if it can narrow the
  15. * component to a JPasswordField).
  16. *
  17. * @author Timothy Prinzing
  18. * @version 1.18 01/23/03
  19. * @see View
  20. */
  21. public class PasswordView extends FieldView {
  22. /**
  23. * Constructs a new view wrapped on an element.
  24. *
  25. * @param elem the element
  26. */
  27. public PasswordView(Element elem) {
  28. super(elem);
  29. }
  30. /**
  31. * Renders the given range in the model as normal unselected
  32. * text. This sets the foreground color and echos the characters
  33. * using the value returned by getEchoChar().
  34. *
  35. * @param g the graphics context
  36. * @param x the starting X coordinate >= 0
  37. * @param y the starting Y coordinate >= 0
  38. * @param p0 the starting offset in the model >= 0
  39. * @param p1 the ending offset in the model >= p0
  40. * @return the X location of the end of the range >= 0
  41. * @exception BadLocationException if p0 or p1 are out of range
  42. */
  43. protected int drawUnselectedText(Graphics g, int x, int y,
  44. int p0, int p1) throws BadLocationException {
  45. Container c = getContainer();
  46. if (c instanceof JPasswordField) {
  47. JPasswordField f = (JPasswordField) c;
  48. if (! f.echoCharIsSet()) {
  49. return super.drawUnselectedText(g, x, y, p0, p1);
  50. }
  51. if (f.isEnabled()) {
  52. g.setColor(f.getForeground());
  53. }
  54. else {
  55. g.setColor(f.getDisabledTextColor());
  56. }
  57. char echoChar = f.getEchoChar();
  58. int n = p1 - p0;
  59. for (int i = 0; i < n; i++) {
  60. x = drawEchoCharacter(g, x, y, echoChar);
  61. }
  62. }
  63. return x;
  64. }
  65. /**
  66. * Renders the given range in the model as selected text. This
  67. * is implemented to render the text in the color specified in
  68. * the hosting component. It assumes the highlighter will render
  69. * the selected background. Uses the result of getEchoChar() to
  70. * display the characters.
  71. *
  72. * @param g the graphics context
  73. * @param x the starting X coordinate >= 0
  74. * @param y the starting Y coordinate >= 0
  75. * @param p0 the starting offset in the model >= 0
  76. * @param p1 the ending offset in the model >= p0
  77. * @return the X location of the end of the range >= 0
  78. * @exception BadLocationException if p0 or p1 are out of range
  79. */
  80. protected int drawSelectedText(Graphics g, int x,
  81. int y, int p0, int p1) throws BadLocationException {
  82. g.setColor(selected);
  83. Container c = getContainer();
  84. if (c instanceof JPasswordField) {
  85. JPasswordField f = (JPasswordField) c;
  86. if (! f.echoCharIsSet()) {
  87. return super.drawSelectedText(g, x, y, p0, p1);
  88. }
  89. char echoChar = f.getEchoChar();
  90. int n = p1 - p0;
  91. for (int i = 0; i < n; i++) {
  92. x = drawEchoCharacter(g, x, y, echoChar);
  93. }
  94. }
  95. return x;
  96. }
  97. /**
  98. * Renders the echo character, or whatever graphic should be used
  99. * to display the password characters. The color in the Graphics
  100. * object is set to the appropriate foreground color for selected
  101. * or unselected text.
  102. *
  103. * @param g the graphics context
  104. * @param x the starting X coordinate >= 0
  105. * @param y the starting Y coordinate >= 0
  106. * @param c the echo character
  107. * @return the updated X position >= 0
  108. */
  109. protected int drawEchoCharacter(Graphics g, int x, int y, char c) {
  110. ONE[0] = c;
  111. g.drawChars(ONE, 0, 1, x, y);
  112. return x + g.getFontMetrics().charWidth(c);
  113. }
  114. /**
  115. * Provides a mapping from the document model coordinate space
  116. * to the coordinate space of the view mapped to it.
  117. *
  118. * @param pos the position to convert >= 0
  119. * @param a the allocated region to render into
  120. * @return the bounding box of the given position
  121. * @exception BadLocationException if the given position does not
  122. * represent a valid location in the associated document
  123. * @see View#modelToView
  124. */
  125. public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
  126. Container c = getContainer();
  127. if (c instanceof JPasswordField) {
  128. JPasswordField f = (JPasswordField) c;
  129. if (! f.echoCharIsSet()) {
  130. return super.modelToView(pos, a, b);
  131. }
  132. char echoChar = f.getEchoChar();
  133. FontMetrics m = f.getFontMetrics(f.getFont());
  134. Rectangle alloc = adjustAllocation(a).getBounds();
  135. int dx = (pos - getStartOffset()) * m.charWidth(echoChar);
  136. alloc.x += dx;
  137. alloc.width = 1;
  138. return alloc;
  139. }
  140. return null;
  141. }
  142. /**
  143. * Provides a mapping from the view coordinate space to the logical
  144. * coordinate space of the model.
  145. *
  146. * @param fx the X coordinate >= 0.0f
  147. * @param fy the Y coordinate >= 0.0f
  148. * @param a the allocated region to render into
  149. * @return the location within the model that best represents the
  150. * given point in the view
  151. * @see View#viewToModel
  152. */
  153. public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
  154. bias[0] = Position.Bias.Forward;
  155. int n = 0;
  156. Container c = getContainer();
  157. if (c instanceof JPasswordField) {
  158. JPasswordField f = (JPasswordField) c;
  159. if (! f.echoCharIsSet()) {
  160. return super.viewToModel(fx, fy, a, bias);
  161. }
  162. char echoChar = f.getEchoChar();
  163. FontMetrics m = f.getFontMetrics(f.getFont());
  164. a = adjustAllocation(a);
  165. Rectangle alloc = (a instanceof Rectangle) ? (Rectangle)a :
  166. a.getBounds();
  167. n = ((int)fx - alloc.x) / m.charWidth(echoChar);
  168. if (n < 0) {
  169. n = 0;
  170. }
  171. else if (n > (getStartOffset() + getDocument().getLength())) {
  172. n = getDocument().getLength() - getStartOffset();
  173. }
  174. }
  175. return getStartOffset() + n;
  176. }
  177. /**
  178. * Determines the preferred span for this view along an
  179. * axis.
  180. *
  181. * @param axis may be either View.X_AXIS or View.Y_AXIS
  182. * @return the span the view would like to be rendered into >= 0.
  183. * Typically the view is told to render into the span
  184. * that is returned, although there is no guarantee.
  185. * The parent may choose to resize or break the view.
  186. */
  187. public float getPreferredSpan(int axis) {
  188. switch (axis) {
  189. case View.X_AXIS:
  190. Container c = getContainer();
  191. if (c instanceof JPasswordField) {
  192. JPasswordField f = (JPasswordField) c;
  193. if (f.echoCharIsSet()) {
  194. char echoChar = f.getEchoChar();
  195. FontMetrics m = f.getFontMetrics(f.getFont());
  196. Document doc = getDocument();
  197. return m.charWidth(echoChar) * getDocument().getLength();
  198. }
  199. }
  200. }
  201. return super.getPreferredSpan(axis);
  202. }
  203. static char[] ONE = new char[1];
  204. }