0N/A/*
2362N/A * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/Apackage javax.swing.plaf.basic;
0N/A
0N/Aimport java.awt.*;
0N/Aimport java.awt.event.KeyEvent;
0N/Aimport java.awt.event.FocusEvent;
0N/Aimport java.awt.event.InputEvent;
0N/Aimport java.beans.PropertyChangeEvent;
0N/Aimport java.io.Reader;
0N/Aimport javax.swing.*;
0N/Aimport javax.swing.border.*;
0N/Aimport javax.swing.event.*;
0N/Aimport javax.swing.text.*;
0N/Aimport javax.swing.plaf.*;
0N/Aimport sun.swing.DefaultLookup;
0N/A
0N/A/**
0N/A * Basis of a look and feel for a JTextField.
0N/A * <p>
0N/A * <strong>Warning:</strong>
0N/A * Serialized objects of this class will not be compatible with
0N/A * future Swing releases. The current serialization support is
0N/A * appropriate for short term storage or RMI between applications running
0N/A * the same version of Swing. As of 1.4, support for long term storage
0N/A * of all JavaBeans<sup><font size="-2">TM</font></sup>
0N/A * has been added to the <code>java.beans</code> package.
0N/A * Please see {@link java.beans.XMLEncoder}.
0N/A *
0N/A * @author Timothy Prinzing
0N/A */
0N/Apublic class BasicTextFieldUI extends BasicTextUI {
0N/A
0N/A /**
0N/A * Creates a UI for a JTextField.
0N/A *
0N/A * @param c the text field
0N/A * @return the UI
0N/A */
0N/A public static ComponentUI createUI(JComponent c) {
0N/A return new BasicTextFieldUI();
0N/A }
0N/A
0N/A /**
0N/A * Creates a new BasicTextFieldUI.
0N/A */
0N/A public BasicTextFieldUI() {
0N/A super();
0N/A }
0N/A
0N/A /**
0N/A * Fetches the name used as a key to lookup properties through the
0N/A * UIManager. This is used as a prefix to all the standard
0N/A * text properties.
0N/A *
0N/A * @return the name ("TextField")
0N/A */
0N/A protected String getPropertyPrefix() {
0N/A return "TextField";
0N/A }
0N/A
0N/A /**
0N/A * Creates a view (FieldView) based on an element.
0N/A *
0N/A * @param elem the element
0N/A * @return the view
0N/A */
0N/A public View create(Element elem) {
0N/A Document doc = elem.getDocument();
0N/A Object i18nFlag = doc.getProperty("i18n"/*AbstractDocument.I18NProperty*/);
0N/A if (Boolean.TRUE.equals(i18nFlag)) {
0N/A // To support bidirectional text, we build a more heavyweight
0N/A // representation of the field.
0N/A String kind = elem.getName();
0N/A if (kind != null) {
0N/A if (kind.equals(AbstractDocument.ContentElementName)) {
0N/A return new GlyphView(elem);
0N/A } else if (kind.equals(AbstractDocument.ParagraphElementName)) {
0N/A return new I18nFieldView(elem);
0N/A }
0N/A }
0N/A // this shouldn't happen, should probably throw in this case.
0N/A }
0N/A return new FieldView(elem);
0N/A }
0N/A
0N/A /**
0N/A * Returns the baseline.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @throws IllegalArgumentException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public int getBaseline(JComponent c, int width, int height) {
0N/A super.getBaseline(c, width, height);
0N/A View rootView = getRootView((JTextComponent)c);
0N/A if (rootView.getViewCount() > 0) {
0N/A Insets insets = c.getInsets();
0N/A height = height - insets.top - insets.bottom;
0N/A if (height > 0) {
0N/A int baseline = insets.top;
0N/A View fieldView = rootView.getView(0);
0N/A int vspan = (int)fieldView.getPreferredSpan(View.Y_AXIS);
0N/A if (height != vspan) {
0N/A int slop = height - vspan;
0N/A baseline += slop / 2;
0N/A }
0N/A if (fieldView instanceof I18nFieldView) {
0N/A int fieldBaseline = BasicHTML.getBaseline(
0N/A fieldView, width - insets.left - insets.right,
0N/A height);
0N/A if (fieldBaseline < 0) {
0N/A return -1;
0N/A }
0N/A baseline += fieldBaseline;
0N/A }
0N/A else {
0N/A FontMetrics fm = c.getFontMetrics(c.getFont());
0N/A baseline += fm.getAscent();
0N/A }
0N/A return baseline;
0N/A }
0N/A }
0N/A return -1;
0N/A }
0N/A
0N/A /**
0N/A * Returns an enum indicating how the baseline of the component
0N/A * changes as the size changes.
0N/A *
0N/A * @throws NullPointerException {@inheritDoc}
0N/A * @see javax.swing.JComponent#getBaseline(int, int)
0N/A * @since 1.6
0N/A */
0N/A public Component.BaselineResizeBehavior getBaselineResizeBehavior(
0N/A JComponent c) {
0N/A super.getBaselineResizeBehavior(c);
0N/A return Component.BaselineResizeBehavior.CENTER_OFFSET;
0N/A }
0N/A
0N/A
0N/A /**
0N/A * A field view that support bidirectional text via the
0N/A * support provided by ParagraphView.
0N/A */
0N/A static class I18nFieldView extends ParagraphView {
0N/A
0N/A I18nFieldView(Element elem) {
0N/A super(elem);
0N/A }
0N/A
0N/A /**
0N/A * Fetch the constraining span to flow against for
0N/A * the given child index. There is no limit for
0N/A * a field since it scrolls, so this is implemented to
0N/A * return <code>Integer.MAX_VALUE</code>.
0N/A */
0N/A public int getFlowSpan(int index) {
0N/A return Integer.MAX_VALUE;
0N/A }
0N/A
0N/A protected void setJustification(int j) {
0N/A // Justification is done in adjustAllocation(), so disable
0N/A // ParagraphView's justification handling by doing nothing here.
0N/A }
0N/A
0N/A static boolean isLeftToRight( java.awt.Component c ) {
0N/A return c.getComponentOrientation().isLeftToRight();
0N/A }
0N/A
0N/A /**
0N/A * Adjusts the allocation given to the view
0N/A * to be a suitable allocation for a text field.
0N/A * If the view has been allocated more than the
0N/A * preferred span vertically, the allocation is
0N/A * changed to be centered vertically. Horizontally
0N/A * the view is adjusted according to the horizontal
0N/A * alignment property set on the associated JTextField
0N/A * (if that is the type of the hosting component).
0N/A *
0N/A * @param a the allocation given to the view, which may need
0N/A * to be adjusted.
0N/A * @return the allocation that the superclass should use.
0N/A */
0N/A Shape adjustAllocation(Shape a) {
0N/A if (a != null) {
0N/A Rectangle bounds = a.getBounds();
0N/A int vspan = (int) getPreferredSpan(Y_AXIS);
0N/A int hspan = (int) getPreferredSpan(X_AXIS);
0N/A if (bounds.height != vspan) {
0N/A int slop = bounds.height - vspan;
0N/A bounds.y += slop / 2;
0N/A bounds.height -= slop;
0N/A }
0N/A
0N/A // horizontal adjustments
0N/A Component c = getContainer();
0N/A if (c instanceof JTextField) {
0N/A JTextField field = (JTextField) c;
0N/A BoundedRangeModel vis = field.getHorizontalVisibility();
0N/A int max = Math.max(hspan, bounds.width);
0N/A int value = vis.getValue();
0N/A int extent = Math.min(max, bounds.width - 1);
0N/A if ((value + extent) > max) {
0N/A value = max - extent;
0N/A }
0N/A vis.setRangeProperties(value, extent, vis.getMinimum(),
0N/A max, false);
0N/A if (hspan < bounds.width) {
0N/A // horizontally align the interior
0N/A int slop = bounds.width - 1 - hspan;
0N/A
0N/A int align = ((JTextField)c).getHorizontalAlignment();
0N/A if(isLeftToRight(c)) {
0N/A if(align==LEADING) {
0N/A align = LEFT;
0N/A }
0N/A else if(align==TRAILING) {
0N/A align = RIGHT;
0N/A }
0N/A }
0N/A else {
0N/A if(align==LEADING) {
0N/A align = RIGHT;
0N/A }
0N/A else if(align==TRAILING) {
0N/A align = LEFT;
0N/A }
0N/A }
0N/A
0N/A switch (align) {
0N/A case SwingConstants.CENTER:
0N/A bounds.x += slop / 2;
0N/A bounds.width -= slop;
0N/A break;
0N/A case SwingConstants.RIGHT:
0N/A bounds.x += slop;
0N/A bounds.width -= slop;
0N/A break;
0N/A }
0N/A } else {
0N/A // adjust the allocation to match the bounded range.
0N/A bounds.width = hspan;
0N/A bounds.x -= vis.getValue();
0N/A }
0N/A }
0N/A return bounds;
0N/A }
0N/A return null;
0N/A }
0N/A
0N/A /**
0N/A * Update the visibility model with the associated JTextField
0N/A * (if there is one) to reflect the current visibility as a
0N/A * result of changes to the document model. The bounded
0N/A * range properties are updated. If the view hasn't yet been
0N/A * shown the extent will be zero and we just set it to be full
0N/A * until determined otherwise.
0N/A */
0N/A void updateVisibilityModel() {
0N/A Component c = getContainer();
0N/A if (c instanceof JTextField) {
0N/A JTextField field = (JTextField) c;
0N/A BoundedRangeModel vis = field.getHorizontalVisibility();
0N/A int hspan = (int) getPreferredSpan(X_AXIS);
0N/A int extent = vis.getExtent();
0N/A int maximum = Math.max(hspan, extent);
0N/A extent = (extent == 0) ? maximum : extent;
0N/A int value = maximum - extent;
0N/A int oldValue = vis.getValue();
0N/A if ((oldValue + extent) > maximum) {
0N/A oldValue = maximum - extent;
0N/A }
0N/A value = Math.max(0, Math.min(value, oldValue));
0N/A vis.setRangeProperties(value, extent, 0, maximum, false);
0N/A }
0N/A }
0N/A
0N/A // --- View methods -------------------------------------------
0N/A
0N/A /**
0N/A * Renders using the given rendering surface and area on that surface.
0N/A * The view may need to do layout and create child views to enable
0N/A * itself to render into the given allocation.
0N/A *
0N/A * @param g the rendering surface to use
0N/A * @param a the allocated region to render into
0N/A *
0N/A * @see View#paint
0N/A */
0N/A public void paint(Graphics g, Shape a) {
0N/A Rectangle r = (Rectangle) a;
0N/A g.clipRect(r.x, r.y, r.width, r.height);
0N/A super.paint(g, adjustAllocation(a));
0N/A }
0N/A
0N/A /**
0N/A * Determines the resizability of the view along the
0N/A * given axis. A value of 0 or less is not resizable.
0N/A *
0N/A * @param axis View.X_AXIS or View.Y_AXIS
0N/A * @return the weight -> 1 for View.X_AXIS, else 0
0N/A */
0N/A public int getResizeWeight(int axis) {
0N/A if (axis == View.X_AXIS) {
0N/A return 1;
0N/A }
0N/A return 0;
0N/A }
0N/A
0N/A /**
0N/A * Provides a mapping from the document model coordinate space
0N/A * to the coordinate space of the view mapped to it.
0N/A *
0N/A * @param pos the position to convert >= 0
0N/A * @param a the allocated region to render into
0N/A * @return the bounding box of the given position
0N/A * @exception BadLocationException if the given position does not
0N/A * represent a valid location in the associated document
0N/A * @see View#modelToView
0N/A */
0N/A public Shape modelToView(int pos, Shape a, Position.Bias b) throws BadLocationException {
0N/A return super.modelToView(pos, adjustAllocation(a), b);
0N/A }
0N/A
0N/A /**
0N/A * Provides a mapping from the document model coordinate space
0N/A * to the coordinate space of the view mapped to it.
0N/A *
0N/A * @param p0 the position to convert >= 0
0N/A * @param b0 the bias toward the previous character or the
0N/A * next character represented by p0, in case the
0N/A * position is a boundary of two views.
0N/A * @param p1 the position to convert >= 0
0N/A * @param b1 the bias toward the previous character or the
0N/A * next character represented by p1, in case the
0N/A * position is a boundary of two views.
0N/A * @param a the allocated region to render into
0N/A * @return the bounding box of the given position is returned
0N/A * @exception BadLocationException if the given position does
0N/A * not represent a valid location in the associated document
0N/A * @exception IllegalArgumentException for an invalid bias argument
0N/A * @see View#viewToModel
0N/A */
0N/A public Shape modelToView(int p0, Position.Bias b0,
0N/A int p1, Position.Bias b1, Shape a)
0N/A throws BadLocationException
0N/A {
0N/A return super.modelToView(p0, b0, p1, b1, adjustAllocation(a));
0N/A }
0N/A
0N/A /**
0N/A * Provides a mapping from the view coordinate space to the logical
0N/A * coordinate space of the model.
0N/A *
0N/A * @param fx the X coordinate >= 0.0f
0N/A * @param fy the Y coordinate >= 0.0f
0N/A * @param a the allocated region to render into
0N/A * @return the location within the model that best represents the
0N/A * given point in the view
0N/A * @see View#viewToModel
0N/A */
0N/A public int viewToModel(float fx, float fy, Shape a, Position.Bias[] bias) {
0N/A return super.viewToModel(fx, fy, adjustAllocation(a), bias);
0N/A }
0N/A
0N/A /**
0N/A * Gives notification that something was inserted into the document
0N/A * in a location that this view is responsible for.
0N/A *
0N/A * @param changes the change information from the associated document
0N/A * @param a the current allocation of the view
0N/A * @param f the factory to use to rebuild if the view has children
0N/A * @see View#insertUpdate
0N/A */
0N/A public void insertUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
0N/A super.insertUpdate(changes, adjustAllocation(a), f);
0N/A updateVisibilityModel();
0N/A }
0N/A
0N/A /**
0N/A * Gives notification that something was removed from the document
0N/A * in a location that this view is responsible for.
0N/A *
0N/A * @param changes the change information from the associated document
0N/A * @param a the current allocation of the view
0N/A * @param f the factory to use to rebuild if the view has children
0N/A * @see View#removeUpdate
0N/A */
0N/A public void removeUpdate(DocumentEvent changes, Shape a, ViewFactory f) {
0N/A super.removeUpdate(changes, adjustAllocation(a), f);
0N/A updateVisibilityModel();
0N/A }
0N/A
0N/A }
0N/A
0N/A}