001    /* PasswordView.java --
002     Copyright (C) 2004 Free Software Foundation, Inc.
003    
004     This file is part of GNU Classpath.
005    
006     GNU Classpath is free software; you can redistribute it and/or modify
007     it under the terms of the GNU General Public License as published by
008     the Free Software Foundation; either version 2, or (at your option)
009     any later version.
010    
011     GNU Classpath is distributed in the hope that it will be useful, but
012     WITHOUT ANY WARRANTY; without even the implied warranty of
013     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
014     General Public License for more details.
015    
016     You should have received a copy of the GNU General Public License
017     along with GNU Classpath; see the file COPYING.  If not, write to the
018     Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
019     02110-1301 USA.
020    
021     Linking this library statically or dynamically with other modules is
022     making a combined work based on this library.  Thus, the terms and
023     conditions of the GNU General Public License cover the whole
024     combination.
025    
026     As a special exception, the copyright holders of this library give you
027     permission to link this library with independent modules to produce an
028     executable, regardless of the license terms of these independent
029     modules, and to copy and distribute the resulting executable under
030     terms of your choice, provided that you also meet, for each linked
031     independent module, the terms and conditions of the license of that
032     module.  An independent module is a module which is not derived from
033     or based on this library.  If you modify this library, you may extend
034     this exception to your version of the library, but you are not
035     obligated to do so.  If you do not wish to do so, delete this
036     exception statement from your version. */
037    
038    
039    package javax.swing.text;
040    
041    import java.awt.Color;
042    import java.awt.FontMetrics;
043    import java.awt.Graphics;
044    import java.awt.Rectangle;
045    import java.awt.Shape;
046    
047    import javax.swing.JPasswordField;
048    
049    public class PasswordView
050      extends FieldView
051    {
052      /**
053       * Buffer for putting the echo char into it and
054       * then using it to draw it into the view.
055       */
056      private char[] oneCharBuffer = new char[1];
057    
058      public PasswordView(Element elem)
059      {
060        super(elem);
061      }
062    
063      /**
064       * Draws one echo character at a given position.
065       *
066       * @param g the <code>Graphics</code> object to draw to
067       * @param x the x-position
068       * @param y the y-position
069       * @param ch the echo character
070       *
071       * @return the next x position right of the drawn character
072       */
073      protected int drawEchoCharacter(Graphics g, int x, int y, char ch)
074      {
075        // Update font metrics.
076        updateMetrics();
077    
078        // Draw character.
079        oneCharBuffer[0] = ch;
080        g.drawChars(oneCharBuffer, 0, 1, x, y);
081    
082        // Return new x position right of drawn character.
083        return x + metrics.charWidth(ch);
084      }
085    
086      private char getEchoChar()
087      {
088        char ch = ((JPasswordField) getContainer()).getEchoChar();
089    
090        if (ch == 0)
091          ch = '*';
092    
093        return ch;
094      }
095    
096      /**
097       * Draws selected text at a given position.
098       *
099       * @param g the <code>Graphics</code> object to draw to
100       * @param x the x-position
101       * @param y the y-position
102       * @param p0 the position of the first character to draw
103       * @param p1 the position of the first character not to draw
104       *
105       * @return the next x position right of the drawn character
106       */
107      protected int drawSelectedText(Graphics g, int x, int y, int p0, int p1)
108        throws BadLocationException
109      {
110        // Update font metrics.
111        updateMetrics();
112    
113        // Get echo character.
114        char ch = getEchoChar();
115    
116        // Set color for selected text.
117        g.setColor(selectedColor);
118        g.setColor(Color.BLACK);
119    
120        // Draw echo character using drawEchoCharacter() method.
121        for (int index = p0; index < p1; ++index)
122          x = drawEchoCharacter(g, x, y, ch);
123        return x;
124      }
125    
126      /**
127       * Draws unselected text at a given position.
128       *
129       * @param g the <code>Graphics</code> object to draw to
130       * @param x the x-position of the start of the baseline
131       * @param y the y-position of the start of the baseline
132       * @param p0 the position of the first character to draw
133       * @param p1 the position of the first character not to draw
134       *
135       * @return the next x position right of the drawn character
136       */
137      protected int drawUnselectedText(Graphics g, int x, int y, int p0, int p1)
138        throws BadLocationException
139      {
140        // Update font metrics.
141        updateMetrics();
142    
143        // Get echo character.
144        char ch = getEchoChar();
145    
146        // Set color for unselected text.
147        g.setColor(unselectedColor);
148        g.setColor(Color.BLACK);
149    
150        // Draw echo character using drawEchoCharacter() method.
151        for (int index = p0; index < p1; ++index)
152          x = drawEchoCharacter(g, x, y, ch);
153        return x;
154      }
155    
156      /**
157       * Determines the preferred span for this view along an axis.
158       *
159       * @param axis to get the preferred span of
160       * @return the preferred span of the axis
161       */
162      public float getPreferredSpan(int axis)
163      {
164        if (axis != X_AXIS && axis != Y_AXIS)
165          throw new IllegalArgumentException();
166    
167        FontMetrics fm = getFontMetrics();
168    
169        if (axis == Y_AXIS)
170            return fm.getHeight();
171    
172        String text;
173        Element elem = getElement();
174    
175        try
176          {
177            text = elem.getDocument().getText(elem.getStartOffset(),
178                                              elem.getEndOffset());
179          }
180        catch (BadLocationException e)
181          {
182            // This should never happen.
183            text = "";
184          }
185        return fm.stringWidth(text);
186      }
187    
188      /**
189       * Provides a mapping from the document model coordinate space to the
190       * coordinate space of the view mapped to it.
191       *
192       * This method is overridden to provide a correct mapping with respect to the
193       * echo char and not to the real content.
194       *
195       * @param pos - the position to convert >= 0
196       * @param a - the allocated region to render into
197       * @param b - typesafe enumeration to indicate bias to a position in the model.
198       * @return the bounding box of the given position
199       * @throws BadLocationException if the given position does not
200       * represent a valid location in the associated document
201       */
202      public Shape modelToView(int pos, Shape a, Position.Bias b)
203        throws BadLocationException
204      {
205        Shape newAlloc = adjustAllocation(a);
206    
207        // Ensure metrics are up-to-date.
208        updateMetrics();
209    
210        // Get rectangle of the line containing position.
211        int lineIndex = getElement().getElementIndex(pos);
212        Rectangle rect = lineToRect(newAlloc, lineIndex);
213    
214        // Get the rectangle for position.
215        Element line = getElement().getElement(lineIndex);
216        int lineStart = line.getStartOffset();
217        Segment segment = getLineBuffer();
218        segment.array = new char[pos - lineStart];
219        char echoChar = getEchoChar();
220        for (int i = 0; i < segment.array.length; ++i)
221          segment.array[i] = echoChar;
222        segment.offset = 0;
223        segment.count = segment.array.length;
224    
225        int xoffset = Utilities.getTabbedTextWidth(segment, metrics, rect.x,
226                               this, lineStart);
227    
228        // Calc the real rectangle.
229        rect.x += xoffset;
230        rect.width = 1;
231        rect.height = metrics.getHeight();
232    
233        return rect;
234      }
235    
236      /**
237       * Provides a mapping from the view coordinate space to the logical
238       * coordinate space of the model.
239       *
240       * @param fx - the X coordinate >= 0.0f
241       * @param fy - the Y coordinate >= 0.0f
242       * @param a - the allocated region to render into
243       * @param bias - typesafe enumeration to indicate bias to a position in the model.
244       * @return the location within the model that best represents
245       * the given point in the view
246       *
247       */
248      public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias)
249      {
250        // FIXME: This only provides a view->model mapping for the real text
251        // content and does not respect the echo char.
252        return super.viewToModel(fx, fy, a, bias);
253      }
254    }