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