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