/* |
|
* Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. |
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
* |
|
* This code is free software; you can redistribute it and/or modify it |
|
* under the terms of the GNU General Public License version 2 only, as |
|
* published by the Free Software Foundation. Oracle designates this |
|
* particular file as subject to the "Classpath" exception as provided |
|
* by Oracle in the LICENSE file that accompanied this code. |
|
* |
|
* This code is distributed in the hope that it will be useful, but WITHOUT |
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
* version 2 for more details (a copy is included in the LICENSE file that |
|
* accompanied this code). |
|
* |
|
* You should have received a copy of the GNU General Public License version |
|
* 2 along with this work; if not, write to the Free Software Foundation, |
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
* |
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
* or visit www.oracle.com if you need additional information or have any |
|
* questions. |
|
*/ |
|
package javax.swing.plaf.basic; |
|
import java.beans.*; |
|
import java.awt.*; |
|
import java.awt.event.KeyEvent; |
|
import java.awt.event.InputEvent; |
|
import javax.swing.*; |
|
import javax.swing.event.DocumentEvent; |
|
import javax.swing.text.*; |
|
import javax.swing.plaf.*; |
|
/** |
|
* Provides the look and feel for a plain text editor. In this |
|
* implementation the default UI is extended to act as a simple |
|
* view factory. |
|
* <p> |
|
* <strong>Warning:</strong> |
|
* Serialized objects of this class will not be compatible with |
|
* future Swing releases. The current serialization support is |
|
* appropriate for short term storage or RMI between applications running |
|
* the same version of Swing. As of 1.4, support for long term storage |
|
* of all JavaBeans™ |
|
* has been added to the <code>java.beans</code> package. |
|
* Please see {@link java.beans.XMLEncoder}. |
|
* |
|
* @author Timothy Prinzing |
|
*/ |
|
public class BasicTextAreaUI extends BasicTextUI { |
|
/** |
|
* Creates a UI for a JTextArea. |
|
* |
|
* @param ta a text area |
|
* @return the UI |
|
*/ |
|
public static ComponentUI createUI(JComponent ta) { |
|
return new BasicTextAreaUI(); |
|
} |
|
/** |
|
* Constructs a new BasicTextAreaUI object. |
|
*/ |
|
public BasicTextAreaUI() { |
|
super(); |
|
} |
|
/** |
|
* Fetches the name used as a key to look up properties through the |
|
* UIManager. This is used as a prefix to all the standard |
|
* text properties. |
|
* |
|
* @return the name ("TextArea") |
|
*/ |
|
protected String getPropertyPrefix() { |
|
return "TextArea"; |
|
} |
|
protected void installDefaults() { |
|
super.installDefaults(); |
|
//the fix for 4785160 is undone |
|
} |
|
/** |
|
* This method gets called when a bound property is changed |
|
* on the associated JTextComponent. This is a hook |
|
* which UI implementations may change to reflect how the |
|
* UI displays bound properties of JTextComponent subclasses. |
|
* This is implemented to rebuild the View when the |
|
* <em>WrapLine</em> or the <em>WrapStyleWord</em> property changes. |
|
* |
|
* @param evt the property change event |
|
*/ |
|
protected void propertyChange(PropertyChangeEvent evt) { |
|
super.propertyChange(evt); |
|
if (evt.getPropertyName().equals("lineWrap") || |
|
evt.getPropertyName().equals("wrapStyleWord") || |
|
evt.getPropertyName().equals("tabSize")) { |
|
// rebuild the view |
|
modelChanged(); |
|
} else if ("editable".equals(evt.getPropertyName())) { |
|
updateFocusTraversalKeys(); |
|
} |
|
} |
|
/** |
|
* The method is overridden to take into account caret width. |
|
* |
|
* @param c the editor component |
|
* @return the preferred size |
|
* @throws IllegalArgumentException if invalid value is passed |
|
* |
|
* @since 1.5 |
|
*/ |
|
public Dimension getPreferredSize(JComponent c) { |
|
return super.getPreferredSize(c); |
|
//the fix for 4785160 is undone |
|
} |
|
/** |
|
* The method is overridden to take into account caret width. |
|
* |
|
* @param c the editor component |
|
* @return the minimum size |
|
* @throws IllegalArgumentException if invalid value is passed |
|
* |
|
* @since 1.5 |
|
*/ |
|
public Dimension getMinimumSize(JComponent c) { |
|
return super.getMinimumSize(c); |
|
//the fix for 4785160 is undone |
|
} |
|
/** |
|
* Creates the view for an element. Returns a WrappedPlainView or |
|
* PlainView. |
|
* |
|
* @param elem the element |
|
* @return the view |
|
*/ |
|
public View create(Element elem) { |
|
Document doc = elem.getDocument(); |
|
Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/); |
|
if ((i18nFlag != null) && i18nFlag.equals(Boolean.TRUE)) { |
|
// build a view that support bidi |
|
return createI18N(elem); |
|
} else { |
|
JTextComponent c = getComponent(); |
|
if (c instanceof JTextArea) { |
|
JTextArea area = (JTextArea) c; |
|
View v; |
|
if (area.getLineWrap()) { |
|
v = new WrappedPlainView(elem, area.getWrapStyleWord()); |
|
} else { |
|
v = new PlainView(elem); |
|
} |
|
return v; |
|
} |
|
} |
|
return null; |
|
} |
|
View createI18N(Element elem) { |
|
String kind = elem.getName(); |
|
if (kind != null) { |
|
if (kind.equals(AbstractDocument.ContentElementName)) { |
|
return new PlainParagraph(elem); |
|
} else if (kind.equals(AbstractDocument.ParagraphElementName)) { |
|
return new BoxView(elem, View.Y_AXIS); |
|
} |
|
} |
|
return null; |
|
} |
|
/** |
|
* Returns the baseline. |
|
* |
|
* @throws NullPointerException {@inheritDoc} |
|
* @throws IllegalArgumentException {@inheritDoc} |
|
* @see javax.swing.JComponent#getBaseline(int, int) |
|
* @since 1.6 |
|
*/ |
|
public int getBaseline(JComponent c, int width, int height) { |
|
super.getBaseline(c, width, height); |
|
Object i18nFlag = ((JTextComponent)c).getDocument(). |
|
getProperty("i18n"); |
|
Insets insets = c.getInsets(); |
|
if (Boolean.TRUE.equals(i18nFlag)) { |
|
View rootView = getRootView((JTextComponent)c); |
|
if (rootView.getViewCount() > 0) { |
|
height = height - insets.top - insets.bottom; |
|
int baseline = insets.top; |
|
int fieldBaseline = BasicHTML.getBaseline( |
|
rootView.getView(0), width - insets.left - |
|
insets.right, height); |
|
if (fieldBaseline < 0) { |
|
return -1; |
|
} |
|
return baseline + fieldBaseline; |
|
} |
|
return -1; |
|
} |
|
FontMetrics fm = c.getFontMetrics(c.getFont()); |
|
return insets.top + fm.getAscent(); |
|
} |
|
/** |
|
* Returns an enum indicating how the baseline of the component |
|
* changes as the size changes. |
|
* |
|
* @throws NullPointerException {@inheritDoc} |
|
* @see javax.swing.JComponent#getBaseline(int, int) |
|
* @since 1.6 |
|
*/ |
|
public Component.BaselineResizeBehavior getBaselineResizeBehavior( |
|
JComponent c) { |
|
super.getBaselineResizeBehavior(c); |
|
return Component.BaselineResizeBehavior.CONSTANT_ASCENT; |
|
} |
|
/** |
|
* Paragraph for representing plain-text lines that support |
|
* bidirectional text. |
|
*/ |
|
static class PlainParagraph extends ParagraphView { |
|
PlainParagraph(Element elem) { |
|
super(elem); |
|
layoutPool = new LogicalView(elem); |
|
layoutPool.setParent(this); |
|
} |
|
public void setParent(View parent) { |
|
super.setParent(parent); |
|
if (parent != null) { |
|
setPropertiesFromAttributes(); |
|
} |
|
} |
|
protected void setPropertiesFromAttributes() { |
|
Component c = getContainer(); |
|
if ((c != null) && (! c.getComponentOrientation().isLeftToRight())) { |
|
setJustification(StyleConstants.ALIGN_RIGHT); |
|
} else { |
|
setJustification(StyleConstants.ALIGN_LEFT); |
|
} |
|
} |
|
/** |
|
* Fetch the constraining span to flow against for |
|
* the given child index. |
|
*/ |
|
public int getFlowSpan(int index) { |
|
Component c = getContainer(); |
|
if (c instanceof JTextArea) { |
|
JTextArea area = (JTextArea) c; |
|
if (! area.getLineWrap()) { |
|
// no limit if unwrapped |
|
return Integer.MAX_VALUE; |
|
} |
|
} |
|
return super.getFlowSpan(index); |
|
} |
|
protected SizeRequirements calculateMinorAxisRequirements(int axis, |
|
SizeRequirements r) { |
|
SizeRequirements req = super.calculateMinorAxisRequirements(axis, r); |
|
Component c = getContainer(); |
|
if (c instanceof JTextArea) { |
|
JTextArea area = (JTextArea) c; |
|
if (! area.getLineWrap()) { |
|
// min is pref if unwrapped |
|
req.minimum = req.preferred; |
|
} else { |
|
req.minimum = 0; |
|
req.preferred = getWidth(); |
|
if (req.preferred == Integer.MAX_VALUE) { |
|
// We have been initially set to MAX_VALUE, but we |
|
// don't want this as our preferred. |
|
req.preferred = 100; |
|
} |
|
} |
|
} |
|
return req; |
|
} |
|
/** |
|
* Sets the size of the view. If the size has changed, layout |
|
* is redone. The size is the full size of the view including |
|
* the inset areas. |
|
* |
|
* @param width the width >= 0 |
|
* @param height the height >= 0 |
|
*/ |
|
public void setSize(float width, float height) { |
|
if ((int) width != getWidth()) { |
|
preferenceChanged(null, true, true); |
|
} |
|
super.setSize(width, height); |
|
} |
|
/** |
|
* This class can be used to represent a logical view for |
|
* a flow. It keeps the children updated to reflect the state |
|
* of the model, gives the logical child views access to the |
|
* view hierarchy, and calculates a preferred span. It doesn't |
|
* do any rendering, layout, or model/view translation. |
|
*/ |
|
static class LogicalView extends CompositeView { |
|
LogicalView(Element elem) { |
|
super(elem); |
|
} |
|
protected int getViewIndexAtPosition(int pos) { |
|
Element elem = getElement(); |
|
if (elem.getElementCount() > 0) { |
|
return elem.getElementIndex(pos); |
|
} |
|
return 0; |
|
} |
|
protected boolean updateChildren(DocumentEvent.ElementChange ec, |
|
DocumentEvent e, ViewFactory f) { |
|
return false; |
|
} |
|
protected void loadChildren(ViewFactory f) { |
|
Element elem = getElement(); |
|
if (elem.getElementCount() > 0) { |
|
super.loadChildren(f); |
|
} else { |
|
View v = new GlyphView(elem); |
|
append(v); |
|
} |
|
} |
|
public float getPreferredSpan(int axis) { |
|
if( getViewCount() != 1 ) |
|
throw new Error("One child view is assumed."); |
|
View v = getView(0); |
|
return v.getPreferredSpan(axis); |
|
} |
|
/** |
|
* Forward the DocumentEvent to the given child view. This |
|
* is implemented to reparent the child to the logical view |
|
* (the children may have been parented by a row in the flow |
|
* if they fit without breaking) and then execute the superclass |
|
* behavior. |
|
* |
|
* @param v the child view to forward the event to. |
|
* @param e the change information from the associated document |
|
* @param a the current allocation of the view |
|
* @param f the factory to use to rebuild if the view has children |
|
* @see #forwardUpdate |
|
* @since 1.3 |
|
*/ |
|
protected void forwardUpdateToView(View v, DocumentEvent e, |
|
Shape a, ViewFactory f) { |
|
v.setParent(this); |
|
super.forwardUpdateToView(v, e, a, f); |
|
} |
|
// The following methods don't do anything useful, they |
|
// simply keep the class from being abstract. |
|
public void paint(Graphics g, Shape allocation) { |
|
} |
|
protected boolean isBefore(int x, int y, Rectangle alloc) { |
|
return false; |
|
} |
|
protected boolean isAfter(int x, int y, Rectangle alloc) { |
|
return false; |
|
} |
|
protected View getViewAtPoint(int x, int y, Rectangle alloc) { |
|
return null; |
|
} |
|
protected void childAllocation(int index, Rectangle a) { |
|
} |
|
} |
|
} |
|
} |