Merge from mainline.
[official-gcc.git] / libjava / classpath / javax / swing / text / FieldView.java
blob0c2f0fef156f390613b1e6b5f86c6341a436b66a
1 /* FieldView.java --
2 Copyright (C) 2004, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING. If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library. Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module. An independent module is a module which is not derived from
33 or based on this library. If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so. If you do not wish to do so, delete this
36 exception statement from your version. */
39 package javax.swing.text;
41 import java.awt.Component;
42 import java.awt.Container;
43 import java.awt.FontMetrics;
44 import java.awt.Graphics;
45 import java.awt.Insets;
46 import java.awt.Rectangle;
47 import java.awt.Shape;
48 import java.awt.event.ActionEvent;
49 import java.awt.event.ActionListener;
51 import javax.swing.BoundedRangeModel;
52 import javax.swing.JTextField;
53 import javax.swing.event.ChangeEvent;
54 import javax.swing.event.ChangeListener;
55 import javax.swing.event.DocumentEvent;
57 public class FieldView extends PlainView
59 BoundedRangeModel horizontalVisibility;
61 /** Caches the preferred span of the X axis. It is invalidated by
62 * setting it to -1f. This is done when text in the document
63 * is inserted, removed or changed. The value is corrected as
64 * soon as calculateHorizontalSpan() is called.
66 float cachedSpan = -1f;
68 public FieldView(Element elem)
70 super(elem);
74 /** Checks whether the given container is a JTextField. If so
75 * it retrieves the textfield's horizontalVisibility instance.
77 * <p>This method should be only called when the view's container
78 * is valid. Naturally that would be the setParent() method however
79 * that method is not overridden in the RI and that is why we chose
80 * paint() instead.</p>
81 */
82 private void checkContainer()
84 Container c = getContainer();
86 if (c instanceof JTextField)
88 horizontalVisibility = ((JTextField) c).getHorizontalVisibility();
90 // Provokes a repaint when the BoundedRangeModel's values change
91 // (which is what the RI does).
92 horizontalVisibility.addChangeListener(new ChangeListener(){
93 public void stateChanged(ChangeEvent event) {
94 getContainer().repaint();
96 });
98 // It turned out that the span calculated at this point is wrong
99 // and needs to be recalculated (e.g. a different font setting is
100 // not taken into account).
101 calculateHorizontalSpan();
103 // Initializes the BoundedRangeModel properly.
104 updateVisibility();
109 private void updateVisibility()
111 JTextField tf = (JTextField) getContainer();
112 Insets insets = tf.getInsets();
114 int width = tf.getWidth() - insets.left - insets.right;
116 horizontalVisibility.setMaximum(Math.max((int) ((cachedSpan != -1f)
117 ? cachedSpan
118 : calculateHorizontalSpan()),
119 width));
121 horizontalVisibility.setExtent(width - 1);
124 protected FontMetrics getFontMetrics()
126 Component container = getContainer();
127 return container.getFontMetrics(container.getFont());
131 * Vertically centers the single line of text within the
132 * bounds of the input shape. The returned Rectangle is centered
133 * vertically within <code>shape</code> and has a height of the
134 * preferred span along the Y axis. Horizontal adjustment is done according
135 * to the horizontalAligment property of the component that is rendered.
137 * @param shape the shape within which the line is beeing centered
139 protected Shape adjustAllocation(Shape shape)
141 // Return null when the original allocation is null (like the RI).
142 if (shape == null)
143 return null;
145 Rectangle rectIn = shape.getBounds();
146 // vertical adjustment
147 int height = (int) getPreferredSpan(Y_AXIS);
148 int y = rectIn.y + (rectIn.height - height) / 2;
149 // horizontal adjustment
150 JTextField textField = (JTextField) getContainer();
151 int width = (int) ((cachedSpan != -1f) ? cachedSpan : calculateHorizontalSpan());
152 int x;
153 if (horizontalVisibility != null && horizontalVisibility.getExtent() < width)
154 x = rectIn.x - horizontalVisibility.getValue();
155 else
156 switch (textField.getHorizontalAlignment())
158 case JTextField.CENTER:
159 x = rectIn.x + (rectIn.width - width) / 2;
160 break;
161 case JTextField.RIGHT:
162 x = rectIn.x + (rectIn.width - width - 1);
163 break;
164 case JTextField.TRAILING:
165 if (textField.getComponentOrientation().isLeftToRight())
166 x = rectIn.x + (rectIn.width - width - 1);
167 else
168 x = rectIn.x;
169 break;
170 case JTextField.LEADING:
171 if (textField.getComponentOrientation().isLeftToRight())
172 x = rectIn.x;
173 else
174 x = rectIn.x + (rectIn.width - width - 1);
175 break;
176 case JTextField.LEFT:
177 default:
178 x = rectIn.x;
179 break;
182 return new Rectangle(x, y, width, height);
185 public float getPreferredSpan(int axis)
187 if (axis != X_AXIS && axis != Y_AXIS)
188 throw new IllegalArgumentException();
191 if (axis == Y_AXIS)
192 return super.getPreferredSpan(axis);
194 if (cachedSpan != -1f)
195 return cachedSpan;
197 return calculateHorizontalSpan();
200 /** Calculates and sets the horizontal span and stores the value
201 * in cachedSpan.
203 private float calculateHorizontalSpan()
205 Segment s = getLineBuffer();
206 Element elem = getElement();
210 elem.getDocument().getText(elem.getStartOffset(),
211 elem.getEndOffset() - 1,
214 return cachedSpan = Utilities.getTabbedTextWidth(s, getFontMetrics(), 0, this, s.offset);
216 catch (BadLocationException e)
218 // Should never happen
219 AssertionError ae = new AssertionError();
220 ae.initCause(e);
221 throw ae;
225 public int getResizeWeight(int axis)
227 return axis = axis == X_AXIS ? 1 : 0;
230 public Shape modelToView(int pos, Shape a, Position.Bias bias)
231 throws BadLocationException
233 Shape newAlloc = adjustAllocation(a);
234 return super.modelToView(pos, newAlloc, bias);
237 public void paint(Graphics g, Shape s)
239 if (horizontalVisibility == null)
240 checkContainer();
242 Shape newAlloc = adjustAllocation(s);
244 // Set a clip to prevent drawing outside of the allocation area.
245 // TODO: Is there a better way to achieve this?
246 Shape clip = g.getClip();
247 g.setClip(s);
248 super.paint(g, newAlloc);
249 g.setClip(clip);
252 public void insertUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
254 cachedSpan = -1f;
256 if (horizontalVisibility != null)
257 updateVisibility();
259 Shape newAlloc = adjustAllocation(shape);
261 super.insertUpdate(ev, newAlloc, vf);
262 getContainer().repaint();
265 public void removeUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
267 cachedSpan = -1f;
269 if (horizontalVisibility != null)
270 updateVisibility();
272 Shape newAlloc = adjustAllocation(shape);
273 super.removeUpdate(ev, newAlloc, vf);
274 getContainer().repaint();
277 public void changedUpdate(DocumentEvent ev, Shape shape, ViewFactory vf)
279 cachedSpan = -1f;
281 if (horizontalVisibility != null)
282 updateVisibility();
284 Shape newAlloc = adjustAllocation(shape);
285 super.changedUpdate(ev, newAlloc, vf);
286 getContainer().repaint();
289 public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias)
291 return super.viewToModel(fx, fy, adjustAllocation(a), bias);