blob: 0ea34b9db6183b9688b1829f05dde91b8ec2438a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25package javax.swing.plaf.basic;
26
27import java.beans.*;
28import java.awt.*;
29import java.awt.event.KeyEvent;
30import java.awt.event.InputEvent;
31import javax.swing.*;
32import javax.swing.event.DocumentEvent;
33import javax.swing.text.*;
34import javax.swing.plaf.*;
35
36/**
37 * Provides the look and feel for a plain text editor. In this
38 * implementation the default UI is extended to act as a simple
39 * view factory.
40 * <p>
41 * <strong>Warning:</strong>
42 * Serialized objects of this class will not be compatible with
43 * future Swing releases. The current serialization support is
44 * appropriate for short term storage or RMI between applications running
45 * the same version of Swing. As of 1.4, support for long term storage
46 * of all JavaBeans<sup><font size="-2">TM</font></sup>
47 * has been added to the <code>java.beans</code> package.
48 * Please see {@link java.beans.XMLEncoder}.
49 *
50 * @author Timothy Prinzing
51 */
52public class BasicTextAreaUI extends BasicTextUI {
53
54 /**
55 * Creates a UI for a JTextArea.
56 *
57 * @param ta a text area
58 * @return the UI
59 */
60 public static ComponentUI createUI(JComponent ta) {
61 return new BasicTextAreaUI();
62 }
63
64 /**
65 * Constructs a new BasicTextAreaUI object.
66 */
67 public BasicTextAreaUI() {
68 super();
69 }
70
71 /**
72 * Fetches the name used as a key to look up properties through the
73 * UIManager. This is used as a prefix to all the standard
74 * text properties.
75 *
76 * @return the name ("TextArea")
77 */
78 protected String getPropertyPrefix() {
79 return "TextArea";
80 }
81
82 protected void installDefaults() {
83 super.installDefaults();
84 //the fix for 4785160 is undone
85 }
86
87 /**
88 * This method gets called when a bound property is changed
89 * on the associated JTextComponent. This is a hook
90 * which UI implementations may change to reflect how the
91 * UI displays bound properties of JTextComponent subclasses.
92 * This is implemented to rebuild the View when the
93 * <em>WrapLine</em> or the <em>WrapStyleWord</em> property changes.
94 *
95 * @param evt the property change event
96 */
97 protected void propertyChange(PropertyChangeEvent evt) {
98 super.propertyChange(evt);
99 if (evt.getPropertyName().equals("lineWrap") ||
100 evt.getPropertyName().equals("wrapStyleWord") ||
101 evt.getPropertyName().equals("tabSize")) {
102 // rebuild the view
103 modelChanged();
104 } else if ("editable".equals(evt.getPropertyName())) {
105 updateFocusTraversalKeys();
106 }
107 }
108
109
110 /**
111 * The method is overridden to take into account caret width.
112 *
113 * @param c the editor component
114 * @return the preferred size
115 * @throws IllegalArgumentException if invalid value is passed
116 *
117 * @since 1.5
118 */
119 public Dimension getPreferredSize(JComponent c) {
120 return super.getPreferredSize(c);
121 //the fix for 4785160 is undone
122 }
123
124 /**
125 * The method is overridden to take into account caret width.
126 *
127 * @param c the editor component
128 * @return the minimum size
129 * @throws IllegalArgumentException if invalid value is passed
130 *
131 * @since 1.5
132 */
133 public Dimension getMinimumSize(JComponent c) {
134 return super.getMinimumSize(c);
135 //the fix for 4785160 is undone
136 }
137
138 /**
139 * Creates the view for an element. Returns a WrappedPlainView or
140 * PlainView.
141 *
142 * @param elem the element
143 * @return the view
144 */
145 public View create(Element elem) {
146 Document doc = elem.getDocument();
147 Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
148 if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) {
149 // build a view that support bidi
150 return createI18N(elem);
151 } else {
152 JTextComponent c = getComponent();
153 if (c instanceof JTextArea) {
154 JTextArea area = (JTextArea) c;
155 View v;
156 if (area.getLineWrap()) {
157 v = new WrappedPlainView(elem, area.getWrapStyleWord());
158 } else {
159 v = new PlainView(elem);
160 }
161 return v;
162 }
163 }
164 return null;
165 }
166
167 View createI18N(Element elem) {
168 String kind = elem.getName();
169 if (kind != null) {
170 if (kind.equals(AbstractDocument.ContentElementName)) {
171 return new PlainParagraph(elem);
172 } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
173 return new BoxView(elem, View.Y_AXIS);
174 }
175 }
176 return null;
177 }
178
179 /**
180 * Returns the baseline.
181 *
182 * @throws NullPointerException {@inheritDoc}
183 * @throws IllegalArgumentException {@inheritDoc}
184 * @see javax.swing.JComponent#getBaseline(int, int)
185 * @since 1.6
186 */
187 public int getBaseline(JComponent c, int width, int height) {
188 super.getBaseline(c, width, height);
189 Object i18nFlag = ((JTextComponent)c).getDocument().
190 getProperty("i18n");
191 Insets insets = c.getInsets();
192 if (Boolean.TRUE.equals(i18nFlag)) {
193 View rootView = getRootView((JTextComponent)c);
194 if (rootView.getViewCount() > 0) {
195 height = height - insets.top - insets.bottom;
196 int baseline = insets.top;
197 int fieldBaseline = BasicHTML.getBaseline(
198 rootView.getView(0), width - insets.left -
199 insets.right, height);
200 if (fieldBaseline < 0) {
201 return -1;
202 }
203 return baseline + fieldBaseline;
204 }
205 return -1;
206 }
207 FontMetrics fm = c.getFontMetrics(c.getFont());
208 return insets.top + fm.getAscent();
209 }
210
211 /**
212 * Returns an enum indicating how the baseline of the component
213 * changes as the size changes.
214 *
215 * @throws NullPointerException {@inheritDoc}
216 * @see javax.swing.JComponent#getBaseline(int, int)
217 * @since 1.6
218 */
219 public Component.BaselineResizeBehavior getBaselineResizeBehavior(
220 JComponent c) {
221 super.getBaselineResizeBehavior(c);
222 return Component.BaselineResizeBehavior.CONSTANT_ASCENT;
223 }
224
225
226 /**
227 * Paragraph for representing plain-text lines that support
228 * bidirectional text.
229 */
230 static class PlainParagraph extends ParagraphView {
231
232 PlainParagraph(Element elem) {
233 super(elem);
234 layoutPool = new LogicalView(elem);
235 layoutPool.setParent(this);
236 }
237
238 public void setParent(View parent) {
239 super.setParent(parent);
240 if (parent != null) {
241 setPropertiesFromAttributes();
242 }
243 }
244
245 protected void setPropertiesFromAttributes() {
246 Component c = getContainer();
247 if ((c != null) && (! c.getComponentOrientation().isLeftToRight())) {
248 setJustification(StyleConstants.ALIGN_RIGHT);
249 } else {
250 setJustification(StyleConstants.ALIGN_LEFT);
251 }
252 }
253
254 /**
255 * Fetch the constraining span to flow against for
256 * the given child index.
257 */
258 public int getFlowSpan(int index) {
259 Component c = getContainer();
260 if (c instanceof JTextArea) {
261 JTextArea area = (JTextArea) c;
262 if (! area.getLineWrap()) {
263 // no limit if unwrapped
264 return Integer.MAX_VALUE;
265 }
266 }
267 return super.getFlowSpan(index);
268 }
269
270 protected SizeRequirements calculateMinorAxisRequirements(int axis,
271 SizeRequirements r) {
272 SizeRequirements req = super.calculateMinorAxisRequirements(axis, r);
273 Component c = getContainer();
274 if (c instanceof JTextArea) {
275 JTextArea area = (JTextArea) c;
276 if (! area.getLineWrap()) {
277 // min is pref if unwrapped
278 req.minimum = req.preferred;
279 } else {
280 req.minimum = 0;
281 req.preferred = getWidth();
282 if (req.preferred == Integer.MAX_VALUE) {
283 // We have been initially set to MAX_VALUE, but we
284 // don't want this as our preferred.
285 req.preferred = 100;
286 }
287 }
288 }
289 return req;
290 }
291
292 /**
293 * Sets the size of the view. If the size has changed, layout
294 * is redone. The size is the full size of the view including
295 * the inset areas.
296 *
297 * @param width the width >= 0
298 * @param height the height >= 0
299 */
300 public void setSize(float width, float height) {
301 if ((int) width != getWidth()) {
302 preferenceChanged(null, true, true);
303 }
304 super.setSize(width, height);
305 }
306
307 /**
308 * This class can be used to represent a logical view for
309 * a flow. It keeps the children updated to reflect the state
310 * of the model, gives the logical child views access to the
311 * view hierarchy, and calculates a preferred span. It doesn't
312 * do any rendering, layout, or model/view translation.
313 */
314 static class LogicalView extends CompositeView {
315
316 LogicalView(Element elem) {
317 super(elem);
318 }
319
320 protected int getViewIndexAtPosition(int pos) {
321 Element elem = getElement();
322 if (elem.getElementCount() > 0) {
323 return elem.getElementIndex(pos);
324 }
325 return 0;
326 }
327
328 protected boolean updateChildren(DocumentEvent.ElementChange ec,
329 DocumentEvent e, ViewFactory f) {
330 return false;
331 }
332
333 protected void loadChildren(ViewFactory f) {
334 Element elem = getElement();
335 if (elem.getElementCount() > 0) {
336 super.loadChildren(f);
337 } else {
338 View v = new GlyphView(elem);
339 append(v);
340 }
341 }
342
343 public float getPreferredSpan(int axis) {
344 if( getViewCount() != 1 )
345 throw new Error("One child view is assumed.");
346
347 View v = getView(0);
348 return v.getPreferredSpan(axis);
349 }
350
351 /**
352 * Forward the DocumentEvent to the given child view. This
353 * is implemented to reparent the child to the logical view
354 * (the children may have been parented by a row in the flow
355 * if they fit without breaking) and then execute the superclass
356 * behavior.
357 *
358 * @param v the child view to forward the event to.
359 * @param e the change information from the associated document
360 * @param a the current allocation of the view
361 * @param f the factory to use to rebuild if the view has children
362 * @see #forwardUpdate
363 * @since 1.3
364 */
365 protected void forwardUpdateToView(View v, DocumentEvent e,
366 Shape a, ViewFactory f) {
367 v.setParent(this);
368 super.forwardUpdateToView(v, e, a, f);
369 }
370
371 // The following methods don't do anything useful, they
372 // simply keep the class from being abstract.
373
374 public void paint(Graphics g, Shape allocation) {
375 }
376
377 protected boolean isBefore(int x, int y, Rectangle alloc) {
378 return false;
379 }
380
381 protected boolean isAfter(int x, int y, Rectangle alloc) {
382 return false;
383 }
384
385 protected View getViewAtPoint(int x, int y, Rectangle alloc) {
386 return null;
387 }
388
389 protected void childAllocation(int index, Rectangle a) {
390 }
391 }
392 }
393
394}