FileDocCategorySizeDatePackage
TextField.javaAPI DocphoneME MR2 API (J2ME)49751Wed May 02 18:00:24 BST 2007javax.microedition.lcdui

TextField.java

/*
 *   
 *
 * Copyright  1990-2007 Sun Microsystems, Inc. All Rights Reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
 * 
 * This program 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.
 * 
 * This program 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 at /legal/license.txt).
 * 
 * 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 Sun Microsystems, Inc., 4150 Network Circle, Santa
 * Clara, CA 95054 or visit www.sun.com if you need additional
 * information or have any questions.
 */

package javax.microedition.lcdui;

import com.sun.midp.lcdui.DynamicCharacterArray;

/**
 * A <code>TextField</code> is an editable text component that may be
 * placed into
 * a {@link Form Form}. It can be
 * given a piece of text that is used as the initial value.
 *
 * <P>A <code>TextField</code> has a maximum size, which is the
 * maximum number of characters
 * that can be stored in the object at any time (its capacity). This limit is
 * enforced when the <code>TextField</code> instance is constructed,
 * when the user is editing text within the <code>TextField</code>, as well as
 * when the application program calls methods on the
 * <code>TextField</code> that modify its
 * contents. The maximum size is the maximum stored capacity and is unrelated
 * to the number of characters that may be displayed at any given time.
 * The number of characters displayed and their arrangement into rows and
 * columns are determined by the device. </p>
 *
 * <p>The implementation may place a boundary on the maximum size, and the
 * maximum size actually assigned may be smaller than the application had
 * requested.  The value actually assigned will be reflected in the value
 * returned by {@link #getMaxSize() getMaxSize()}.  A defensively-written
 * application should compare this value to the maximum size requested and be
 * prepared to handle cases where they differ.</p>
 *
 * <a name="constraints"></a>
 * <h3>Input Constraints</h3>
 *
 * <P>The <code>TextField</code> shares the concept of <em>input
 * constraints</em> with the {@link TextBox TextBox} class. The different
 * constraints allow the application to request that the user's input be
 * restricted in a variety of ways. The implementation is required to
 * restrict the user's input as requested by the application. For example, if
 * the application requests the <code>NUMERIC</code> constraint on a
 * <code>TextField</code>, the
 * implementation must allow only numeric characters to be entered. </p>
 *
 * <p>The <em>actual contents</em> of the text object are set and modified by
 * and are
 * reported to the application through the <code>TextBox</code> and
 * <code>TextField</code> APIs.  The <em>displayed contents</em> may differ
 * from the actual contents if the implementation has chosen to provide
 * special formatting suitable for the text object's constraint setting.
 * For example, a <code>PHONENUMBER</code> field might be displayed with
 * digit separators and punctuation as
 * appropriate for the phone number conventions in use, grouping the digits
 * into country code, area code, prefix, etc. Any spaces or punctuation
 * provided are not considered part of the text object's actual contents. For
 * example, a text object with the <code>PHONENUMBER</code>
 * constraint might display as
 * follows:</p>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *     <pre><code>
 *     (408) 555-1212    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 *
 * <p>but the actual contents of the object visible to the application
 * through the APIs would be the string
 * "<code>4085551212</code>".
 * The <code>size</code> method reflects the number of characters in the
 * actual contents, not the number of characters that are displayed, so for
 * this example the <code>size</code> method would return <code>10</code>.</p>
 *
 * <p>Some constraints, such as <code>DECIMAL</code>, require the
 * implementation to perform syntactic validation of the contents of the text
 * object.  The syntax checking is performed on the actual contents of the
 * text object, which may differ from the displayed contents as described
 * above.  Syntax checking is performed on the initial contents passed to the
 * constructors, and it is also enforced for all method calls that affect the
 * contents of the text object.  The methods and constructors throw
 * <code>IllegalArgumentException</code> if they would result in the contents
 * of the text object not conforming to the required syntax.</p>
 *
 * <p>The value passed to the {@link #setConstraints setConstraints()} method
 * consists of a restrictive constraint setting described above, as well as a
 * variety of flag bits that modify the behavior of text entry and display.
 * The value of the restrictive constraint setting is in the low order
 * <code>16</code> bits
 * of the value, and it may be extracted by combining the constraint value
 * with the <code>CONSTRAINT_MASK</code> constant using the bit-wise
 * <code>AND</code> (<code>&</code>) operator.
 * The restrictive constraint settings are as follows:
 *
 * <blockquote><code>
 * ANY<br>
 * EMAILADDR<br>
 * NUMERIC<br>
 * PHONENUMBER<br>
 * URL<br>
 * DECIMAL<br>
 * </code></blockquote>
 *
 * <p>The modifier flags reside in the high order <code>16</code> bits
 * of the constraint
 * value, that is, those in the complement of the
 * <code>CONSTRAINT_MASK</code> constant.
 * The modifier flags may be tested individually by combining the constraint
 * value with a modifier flag using the bit-wise <code>AND</code>
 * (<code>&</code>) operator.  The
 * modifier flags are as follows:
 *
 * <blockquote><code>
 * PASSWORD<br>
 * UNEDITABLE<br>
 * SENSITIVE<br>
 * NON_PREDICTIVE<br>
 * INITIAL_CAPS_WORD<br>
 * INITIAL_CAPS_SENTENCE<br>
 * </code></blockquote>
 *
 * <a name="modes"></a>
 * <h3>Input Modes</h3>
 *
 * <p>The <code>TextField</code> shares the concept of <em>input
 * modes</em> with the {@link
 * TextBox TextBox} class.  The application can request that the
 * implementation use a particular input mode when the user initiates editing
 * of a <code>TextField</code> or <code>TextBox</code>.  The input
 * mode is a concept that exists within
 * the user interface for text entry on a particular device.  The application
 * does not request an input mode directly, since the user interface for text
 * entry is not standardized across devices.  Instead, the application can
 * request that the entry of certain characters be made convenient.  It can do
 * this by passing the name of a Unicode character subset to the {@link
 * #setInitialInputMode setInitialInputMode()} method.  Calling this method
 * requests that the implementation set the mode of the text entry user
 * interface so that it is convenient for the user to enter characters in this
 * subset.  The application can also request that the input mode have certain
 * behavioral characteristics by setting modifier flags in the constraints
 * value.
 *
 * <p>The requested input mode should be used whenever the user initiates the
 * editing of a <code>TextBox</code> or <code>TextField</code> object.
 * If the user had changed input
 * modes in a previous editing session, the application's requested input mode
 * should take precedence over the previous input mode set by the user.
 * However, the input mode is not restrictive, and the user is allowed to
 * change the input mode at any time during editing.  If editing is already in
 * progress, calls to the <code>setInitialInputMode</code> method do not
 * affect the current input mode, but instead take effect at the next time the
 * user initiates editing of this text object.
 *
 * <p>The initial input mode is a hint to the implementation.  If the
 * implementation cannot provide an input mode that satisfies the
 * application's request, it should use a default input mode.
 *
 * <P>The input mode that results from the application's request is not a
 * restriction on the set of characters the user is allowed to enter.  The
 * user MUST be allowed to switch input modes to enter any character that is
 * allowed within the current constraint setting.  The constraint
 * setting takes precedence over an input mode request, and the implementation
 * may refuse to supply a particular input mode if it is inconsistent with the
 * current constraint setting.
 *
 * <P>For example, if the current constraint is <code>ANY</code>, the call</P>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    setInitialInputMode("MIDP_UPPERCASE_LATIN");    </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 *
 * <p>should set the initial input mode to allow entry of uppercase Latin
 * characters.  This does not restrict input to these characters, and the user
 * will be able to enter other characters by switching the input mode to allow
 * entry of numerals or lowercase Latin letters.  However, if the current
 * constraint is <code>NUMERIC</code>, the implementation may ignore
 * the request to set an
 * initial input mode allowing <code>MIDP_UPPERCASE_LATIN</code>
 * characters because these
 * characters are not allowed in a <code>TextField</code> whose
 * constraint is <code>NUMERIC</code>.  In
 * this case, the implementation may instead use an input mode that allows
 * entry of numerals, since such an input mode is most appropriate for entry
 * of data under the <code>NUMERIC</code> constraint.
 *
 * <P>A string is used to name the Unicode character subset passed as a
 * parameter to the
 * {@link #setInitialInputMode setInitialInputMode()} method.
 * String comparison is case sensitive.
 *
 * <P>Unicode character blocks can be named by adding the prefix
 * "<code>UCB</code>_" to the
 * the string names of fields representing Unicode character blocks as defined
 * in the J2SE class <code>java.lang.Character.UnicodeBlock</code>.  Any
 * Unicode character block may be named in this fashion.  For convenience, the
 * most common Unicode character blocks are listed below.
 *
 * <blockquote><code>
 * UCB_BASIC_LATIN<br>
 * UCB_GREEK<br>
 * UCB_CYRILLIC<br>
 * UCB_ARMENIAN<br>
 * UCB_HEBREW<br>
 * UCB_ARABIC<br>
 * UCB_DEVANAGARI<br>
 * UCB_BENGALI<br>
 * UCB_THAI<br>
 * UCB_HIRAGANA<br>
 * UCB_KATAKANA<br>
 * UCB_HANGUL_SYLLABLES<br>
 * </code></blockquote>
 *
 * <P>"Input subsets" as defined by the J2SE class
 * <code>java.awt.im.InputSubset</code> may be named by adding the prefix
 * "<code>IS_</code>" to the string names of fields
 * representing input subsets as defined
 * in that class.  Any defined input subset may be used.  For convenience, the
 * names of the currently defined input subsets are listed below.
 *
 * <blockquote><code>
 * IS_FULLWIDTH_DIGITS<br>
 * IS_FULLWIDTH_LATIN<br>
 * IS_HALFWIDTH_KATAKANA<br>
 * IS_HANJA<br>
 * IS_KANJI<br>
 * IS_LATIN<br>
 * IS_LATIN_DIGITS<br>
 * IS_SIMPLIFIED_HANZI<br>
 * IS_TRADITIONAL_HANZI<br>
 * </code></blockquote>
 *
 * <P>MIDP has also defined the following character subsets:
 *
 * <blockquote>
 * <code>MIDP_UPPERCASE_LATIN</code> - the subset of
 * <code>IS_LATIN</code> that corresponds to
 * uppercase Latin letters
 * </blockquote>
 * <blockquote>
 * <code>MIDP_LOWERCASE_LATIN</code> - the subset of
 * <code>IS_LATIN</code> that corresponds to
 * lowercase Latin letters
 * </blockquote>
 *
 * <p>
 * Finally, implementation-specific character subsets may be named with
 * strings that have a prefix of "<code>X_</code>".  In
 * order to avoid namespace conflicts,
 * it is recommended that implementation-specific names include the name of
 * the defining company or organization after the initial
 * "<code>X_</code>" prefix.
 *
 * <p> For example, a Japanese language application might have a particular
 * <code>TextField</code> that the application intends to be used
 * primarily for input of
 * words that are "loaned" from languages other than Japanese.  The
 * application might request an input mode facilitating Hiragana input by
 * issuing the following method call:</p>
 *
 * <TABLE BORDER="2">
 * <TR>
 * <TD ROWSPAN="1" COLSPAN="1">
 *    <pre><code>
 *    textfield.setInitialInputMode("UCB_HIRAGANA");       </code></pre>
 * </TD>
 * </TR>
 * </TABLE>
 * <h3>Implementation Note</h3>
 *
 * <p>Implementations need not compile in all the strings listed above.
 * Instead, they need only to compile in the strings that name Unicode
 * character subsets that they support.  If the subset name passed by the
 * application does not match a known subset name, the request should simply
 * be ignored without error, and a default input mode should be used.  This
 * lets implementations support this feature reasonably inexpensively.
 * However, it has the consequence that the application cannot tell whether
 * its request has been accepted, nor whether the Unicode character subset it
 * has requested is actually a valid subset.
 *
 * @since MIDP 1.0
 */

public class TextField extends Item {

    /**
     * The user is allowed to enter any text.
     * <A HREF="Form.html#linebreak">Line breaks</A> may be entered.
     *
     * <P>Constant <code>0</code> is assigned to <code>ANY</code>.</P>
     */
    public final static int ANY = 0;

    /**
     * The user is allowed to enter an e-mail address.
     *
     * <P>Constant <code>1</code> is assigned to <code>EMAILADDR</code>.</P>
     */
    public final static int EMAILADDR = 1;

    /**
     * The user is allowed to enter only an integer value. The implementation
     * must restrict the contents either to be empty or to consist of an
     * optional minus sign followed by a string of one or more decimal
     * numerals.  Unless the value is empty, it will be successfully parsable
     * using {@link java.lang.Integer#parseInt(String)}.
     *
     * <P>The minus sign consumes space in the text object.  It is thus
     * impossible to enter negative numbers into a text object whose maximum
     * size is <code>1</code>.</P>
     *
     * <P>Constant <code>2</code> is assigned to <code>NUMERIC</code>.</P>
     */
    public final static int NUMERIC = 2;

    /**
     * The user is allowed to enter a phone number. The phone number is a
     * special
     * case, since a phone-based implementation may be linked to the
     * native phone
     * dialing application. The implementation may automatically start a phone
     * dialer application that is initialized so that pressing a single key
     * would be enough to make a call. The call must not made automatically
     * without requiring user's confirmation.  Implementations may also
     * provide a feature to look up the phone number in the device's phone or
     * address database.
     *
     * <P>The exact set of characters allowed is specific to the device and to
     * the device's network and may include non-numeric characters, such as a
     * "+" prefix character.</P>
     *
     * <P>Some platforms may provide the capability to initiate voice calls
     * using the {@link javax.microedition.midlet.MIDlet#platformRequest
     * MIDlet.platformRequest} method.</P>
     *
     * <P>Constant <code>3</code> is assigned to <code>PHONENUMBER</code>.</P>
     */
    public final static int PHONENUMBER = 3;

    /**
     * The user is allowed to enter a URL.
     *
     * <P>Constant <code>4</code> is assigned to <code>URL</code>.</P>
     */
    public final static int URL = 4;


    /**
     * The user is allowed to enter numeric values with optional decimal
     * fractions, for example "-123", "0.123", or
     * ".5".
     *
     * <p>The implementation may display a period "." or a
     * comma "," for the decimal fraction separator, depending on
     * the conventions in use on the device.  Similarly, the implementation
     * may display other device-specific characters as part of a decimal
     * string, such as spaces or commas for digit separators.  However, the
     * only characters allowed in the actual contents of the text object are
     * period ".", minus sign "-", and the decimal
     * digits.</p>
     *
     * <p>The actual contents of a <code>DECIMAL</code> text object may be
     * empty.  If the actual contents are not empty, they must conform to a
     * subset of the syntax for a <code>FloatingPointLiteral</code> as defined
     * by the <em>Java Language Specification</em>, section 3.10.2.  This
     * subset syntax is defined as follows: the actual contents
     * must consist of an optional minus sign
     * "-", followed by one or more whole-number decimal digits,
     * followed by an optional fraction separator, followed by zero or more
     * decimal fraction digits.  The whole-number decimal digits may be
     * omitted if the fraction separator and one or more decimal fraction
     * digits are present.</p>
     *
     * <p>The syntax defined above is also enforced whenever the application
     * attempts to set or modify the contents of the text object by calling
     * a constructor or a method.</p>
     *
     * <p>Parsing this string value into a numeric value suitable for
     * computation is the responsibility of the application.  If the contents
     * are not empty, the result can be parsed successfully by
     * <code>Double.valueOf</code> and related methods if they are present
     * in the runtime environment. </p>
     *
     * <p>The sign and the fraction separator consume space in the text
     * object.  Applications should account for this when assigning a maximum
     * size for the text object.</p>
     *
     * <P>Constant <code>5</code> is assigned to <code>DECIMAL</code>.</P>
     *
     */
    public static final int DECIMAL = 5;

    /**
     * Indicates that the text entered is confidential data that should be
     * obscured whenever possible.  The contents may be visible while the
     * user is entering data.  However, the contents must never be divulged
     * to the user.  In particular, the existing contents must not be shown
     * when the user edits the contents.  The means by which the contents
     * are obscured is implementation-dependent.  For example, each
     * character of the data might be masked with a
     * "<code>*</code>" character.  The
     * <code>PASSWORD</code> modifier is useful for entering
     * confidential information
     * such as passwords or personal identification numbers (PINs).
     *
     * <p>Data entered into a <code>PASSWORD</code> field is treated
     * similarly to <code>SENSITIVE</code>
     * in that the implementation must never store the contents into a
     * dictionary or table for use in predictive, auto-completing, or other
     * accelerated input schemes.  If the <code>PASSWORD</code> bit is
     * set in a constraint
     * value, the <code>SENSITIVE</code> and
     * <code>NON_PREDICTIVE</code> bits are also considered to be
     * set, regardless of their actual values.  In addition, the
     * <code>INITIAL_CAPS_WORD</code> and
     * <code>INITIAL_CAPS_SENTENCE</code> flag bits should be ignored
     * even if they are set.</p>
     *
     * <p>The <code>PASSWORD</code> modifier can be combined with
     * other input constraints
     * by using the bit-wise <code>OR</code> operator (<code>|</code>).
     * The <code>PASSWORD</code> modifier is not
     * useful with some constraint values such as
     * <code>EMAILADDR</code>, <code>PHONENUMBER</code>,
     * and <code>URL</code>. These combinations are legal, however,
     * and no exception is
     * thrown if such a constraint is specified.</p>
     *
     * <p>Constant <code>0x10000</code> is assigned to
     * <code>PASSWORD</code>.</p>
     */
    public static final int PASSWORD = 0x10000;

    /**
     * Indicates that editing is currently disallowed.  When this flag is set,
     * the implementation must prevent the user from changing the text
     * contents of this object.  The implementation should also provide a
     * visual indication that the object's text cannot be edited.  The intent
     * of this flag is that this text object has the potential to be edited,
     * and that there are circumstances where the application will clear this
     * flag and allow the user to edit the contents.
     *
     * <p>The <code>UNEDITABLE</code> modifier can be combined with
     * other input constraints
     * by using the bit-wise <code>OR</code> operator (<code>|</code>).
     *
     * <p>Constant <code>0x20000</code> is assigned to <code>UNEDITABLE</code>.
     *
     */
    public static final int UNEDITABLE = 0x20000;

    /**
     * Indicates that the text entered is sensitive data that the
     * implementation must never store into a dictionary or table for use in
     * predictive, auto-completing, or other accelerated input schemes.  A
     * credit card number is an example of sensitive data.
     *
     * <p>The <code>SENSITIVE</code> modifier can be combined with other input
     * constraints by using the bit-wise <code>OR</code> operator
     * (<code>|</code>).</p>
     *
     * <p>Constant <code>0x40000</code> is assigned to
     * <code>SENSITIVE</code>.</p>
     *
     */
    public static final int SENSITIVE = 0x40000;

    /**
     * Indicates that the text entered does not consist of words that are
     * likely to be found in dictionaries typically used by predictive input
     * schemes.  If this bit is clear, the implementation is allowed to (but
     * is not required to) use predictive input facilities.  If this bit is
     * set, the implementation should not use any predictive input facilities,
     * but it instead should allow character-by-character text entry.
     *
     * <p>The <code>NON_PREDICTIVE</code> modifier can be combined
     * with other input
     * constraints by using the bit-wise <code>OR</code> operator
     * (<code>|</code>).
     *
     * <P>Constant <code>0x80000</code> is assigned to
     * <code>NON_PREDICTIVE</code>.</P>
     *
     */
    public static final int NON_PREDICTIVE = 0x80000;

    /**
     * This flag is a hint to the implementation that during text editing, the
     * initial letter of each word should be capitalized.  This hint should be
     * honored only on devices for which automatic capitalization is
     * appropriate and when the character set of the text being edited has the
     * notion of upper case and lower case letters.  The definition of
     * word boundaries is implementation-specific.
     *
     * <p>If the application specifies both the
     * <code>INITIAL_CAPS_WORD</code> and the
     * <code>INITIAL_CAPS_SENTENCE</code> flags,
     * <code>INITIAL_CAPS_WORD</code> behavior should be used.
     *
     * <p>The <code>INITIAL_CAPS_WORD</code> modifier can be combined
     * with other input
     * constraints by using the bit-wise <code>OR</code> operator
     * (<code>|</code>).
     *
     * <p>Constant <code>0x100000</code> is assigned to
     * <code>INITIAL_CAPS_WORD</code>.
     *
     */
    public static final int INITIAL_CAPS_WORD = 0x100000;

    /**
     * This flag is a hint to the implementation that during text editing, the
     * initial letter of each sentence should be capitalized.  This hint
     * should be honored only on devices for which automatic capitalization is
     * appropriate and when the character set of the text being edited has the
     * notion of upper case and lower case letters.  The definition of
     * sentence boundaries is implementation-specific.
     *
     * <p>If the application specifies both the
     * <code>INITIAL_CAPS_WORD</code> and the
     * <code>INITIAL_CAPS_SENTENCE</code> flags,
     * <code>INITIAL_CAPS_WORD</code> behavior should be used.
     *
     * <p>The <code>INITIAL_CAPS_SENTENCE</code> modifier can be
     * combined with other input
     * constraints by using the bit-wise <code>OR</code> operator
     * (<code>|</code>).
     *
     * <p>Constant <code>0x200000</code> is assigned to
     * <code>INITIAL_CAPS_SENTENCE</code>.
     *
     */
    public static final int INITIAL_CAPS_SENTENCE = 0x200000;

    /**
     * The mask value for determining the constraint mode. The application
     * should
     * use the bit-wise <code>AND</code> operation with a value returned by
     * <code>getConstraints()</code> and
     * <code>CONSTRAINT_MASK</code> in order to retrieve the current
     * constraint mode,
     * in order to remove any modifier flags such as the
     * <code>PASSWORD</code> flag.
     *
     * <P>Constant <code>0xFFFF</code> is assigned to
     * <code>CONSTRAINT_MASK</code>.</P>
     */
    public final static int CONSTRAINT_MASK = 0xFFFF;

    /**
     * Creates a new <code>TextField</code> object with the given label, initial
     * contents, maximum size in characters, and constraints.
     * If the text parameter is <code>null</code>, the
     * <code>TextField</code> is created empty.
     * The <code>maxSize</code> parameter must be greater than zero.
     * An <code>IllegalArgumentException</code> is thrown if the
     * length of the initial contents string exceeds <code>maxSize</code>.
     * However,
     * the implementation may assign a maximum size smaller than the 
     * application had requested.  If this occurs, and if the length of the 
     * contents exceeds the newly assigned maximum size, the contents are 
     * truncated from the end in order to fit, and no exception is thrown.
     *
     * @param label item label
     * @param text the initial contents, or <code>null</code> if the
     * <code>TextField</code> is to be empty
     * @param maxSize the maximum capacity in characters
     * @param constraints see <a href="#constraints">input constraints</a>
     *
     * @throws IllegalArgumentException if <code>maxSize</code> is zero or less
     * @throws IllegalArgumentException if the value of the constraints
     * parameter
     * is invalid
     * @throws IllegalArgumentException if <code>text</code> is illegal
     * for the specified constraints
     * @throws IllegalArgumentException if the length of the string exceeds
     * the requested maximum capacity 
     */
    public TextField(String label, String text, int maxSize, 
                     int constraints) {

        super(label);

        synchronized (Display.LCDUILock) {

            // IllegalArgumentException thrown here
            buffer = new DynamicCharacterArray(maxSize); 

	    // Constraint value is checked here. Since textFieldLF is not
	    // yet created, no LF notification will happen.
            setConstraintsImpl(constraints);

	    // Create a LF with empty content
            itemLF = textFieldLF = LFFactory.getFactory().getTextFieldLF(this);

            // this will use inputClient
	    // Right now setCharsImpl notifies LF a content change.
	    // If LF is created as an absolutely last thing then
            // setCharsImple here does not need the notification.
            if (text == null) {
		setCharsImpl(null, 0, 0);
            } else {
                setCharsImpl(text.toCharArray(), 0, text.length());
            }
        }
    }

    /**
     * Gets the contents of the <code>TextField</code> as a string value.
     *
     * @return the current contents
     * @see #setString
     */
    public String getString() {
        synchronized (Display.LCDUILock) {
	    textFieldLF.lUpdateContents();
            return buffer.toString();
        }
    }

    /**
     * Sets the contents of the <code>TextField</code> as a string
     * value, replacing the
     * previous contents.
     *
     * @param text the new value of the <code>TextField</code>, or
     * <code>null</code> if the TextField is to be made empty
     * @throws IllegalArgumentException if <code>text</code>
     * is illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws IllegalArgumentException if the text would exceed the current
     * maximum capacity
     * @see #getString
     */
    public void setString(String text) {

        synchronized (Display.LCDUILock) {
            if (text == null || text.length() == 0) {
                setCharsImpl(null, 0, 0);
            } else {
                setCharsImpl(text.toCharArray(), 0, text.length());
            }
        }
    }

    /**
     * Copies the contents of the <code>TextField</code> into a
     * character array starting at
     * index zero. Array elements beyond the characters copied are left
     * unchanged.
     *
     * @param data the character array to receive the value
     * @return the number of characters copied
     * @throws ArrayIndexOutOfBoundsException if the array is too short for the
     * contents
     * @throws NullPointerException if <code>data</code> is <code>null</code>
     * @see #setChars
     */
    public int getChars(char[] data) {

        synchronized (Display.LCDUILock) {
	    
	    textFieldLF.lUpdateContents();

            try {
                buffer.getChars(0, buffer.length(), data, 0);
            } catch (IndexOutOfBoundsException e) {
                throw new ArrayIndexOutOfBoundsException(e.getMessage());
            }

            return buffer.length();
        }
    }

    /**
     * Sets the contents of the <code>TextField</code> from a
     * character array, replacing the
     * previous contents. Characters are copied from the region of the
     * <code>data</code> array
     * starting at array index <code>offset</code> and running for
     * <code>length</code> characters.
     * If the data array is <code>null</code>, the <code>TextField</code>
     * is set to be empty and the other parameters are ignored.
     *
     * <p>The <code>offset</code> and <code>length</code> parameters must
     * specify a valid range of characters within
     * the character array <code>data</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(data.length)]</code>, inclusive.
     * The <code>length</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + length) <= data.length</code>.</p>
     * 
     * @param data the source of the character data
     * @param offset the beginning of the region of characters to copy
     * @param length the number of characters to copy
     * @throws ArrayIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not specify
     * a valid range within the data array
     * @throws IllegalArgumentException if <code>data</code>
     * is illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws IllegalArgumentException if the text would exceed the current
     * maximum capacity
     * @see #getChars
     */
    public void setChars(char[] data, int offset, int length) {

        synchronized (Display.LCDUILock) {
            setCharsImpl(data, offset, length);
        }
    }

    /**
     * Inserts a string into the contents of the
     * <code>TextField</code>.  The string is
     * inserted just prior to the character indicated by the
     * <code>position</code> parameter, where zero specifies the first
     * character of the contents of the <code>TextField</code>.  If
     * <code>position</code> is
     * less than or equal to zero, the insertion occurs at the beginning of
     * the contents, thus effecting a prepend operation.  If
     * <code>position</code> is greater than or equal to the current size of
     * the contents, the insertion occurs immediately after the end of the
     * contents, thus effecting an append operation.  For example,
     * <code>text.insert(s, text.size())</code> always appends the string
     * <code>s</code> to the current contents.
     *
     * <p>The current size of the contents is increased by the number of
     * inserted characters. The resulting string must fit within the current
     * maximum capacity. </p>
     *
     * <p>If the application needs to simulate typing of characters it can
     * determining the location of the current insertion point
     * ("caret")
     * using the with {@link #getCaretPosition() getCaretPosition()} method.
     * For example,
     * <code>text.insert(s, text.getCaretPosition())</code> inserts the string
     * <code>s</code> at the current caret position.</p>
     *
     * @param src the <code>String</code> to be inserted
     * @param position the position at which insertion is to occur
     *
     * @throws IllegalArgumentException if the resulting contents
     * would be illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws IllegalArgumentException if the insertion would exceed
     * the current
     * maximum capacity
     * @throws NullPointerException if <code>src</code> is <code>null</code>
     */
    public void insert(String src, int position) {
        synchronized (Display.LCDUILock) {
            // NullPointerException will be thrown by src.toCharArray
            insertImpl(src.toCharArray(), 0, src.length(), position);
        }
    }

    /**
     * Inserts a subrange of an array of characters into the contents of
     * the <code>TextField</code>.  The <code>offset</code> and
     * <code>length</code> parameters indicate the subrange
     * of the data array to be used for insertion. Behavior is otherwise
     * identical to {@link #insert(String, int) insert(String, int)}.
     *
     * <p>The <code>offset</code> and <code>length</code> parameters must
     * specify a valid range of characters within
     * the character array <code>data</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(data.length)]</code>, inclusive.
     * The <code>length</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + length) <= data.length</code>.</p>
     * 
     * @param data the source of the character data
     * @param offset the beginning of the region of characters to copy
     * @param length the number of characters to copy
     * @param position the position at which insertion is to occur
     *
     * @throws ArrayIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not specify
     * a valid range within the <code>data</code> array
     * @throws IllegalArgumentException if the resulting contents
     * would be illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws IllegalArgumentException if the insertion would exceed
     * the current
     * maximum capacity
     * @throws NullPointerException if <code>data</code> is <code>null</code>
     */
    public void insert(char[] data, int offset, int length, int position)  {
        synchronized (Display.LCDUILock) {
            insertImpl(data, offset, length, position);
        }
    }

    /**
     * Deletes characters from the <code>TextField</code>.
     *
     * <p>The <code>offset</code> and <code>length</code> parameters must
     * specify a valid range of characters within
     * the contents of the <code>TextField</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(size())]</code>, inclusive.
     * The <code>length</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + length) <= size()</code>.</p>
     * 
     * @param offset the beginning of the region to be deleted
     * @param length the number of characters to be deleted
     *
     * @throws IllegalArgumentException if the resulting contents
     * would be illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws StringIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not
     * specify a valid range within the contents of the <code>TextField</code>
     */
    public void delete(int offset, int length) {
        synchronized (Display.LCDUILock) {
	    deleteImpl(offset, length);
        }
    }

    /**
     * Returns the maximum size (number of characters) that can be
     * stored in this <code>TextField</code>.
     * @return the maximum size in characters
     * @see #setMaxSize
     */
    public int getMaxSize() {
        synchronized (Display.LCDUILock) {
            return buffer.capacity();
        }
    }

    /**
     * Sets the maximum size (number of characters) that can be contained
     * in this
     * <code>TextField</code>. If the current contents of the
     * <code>TextField</code> are larger than
     * <code>maxSize</code>, the contents are truncated to fit.
     *
     * @param maxSize the new maximum size
     *
     * @return assigned maximum capacity - may be smaller than requested.
     * @throws IllegalArgumentException if <code>maxSize</code> is zero or less.
     * @throws IllegalArgumentException if the contents
     * after truncation would be illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @see #getMaxSize
     */
    public int setMaxSize(int maxSize) {
        synchronized (Display.LCDUILock) {

	    textFieldLF.lUpdateContents();

            int oldCapacity = buffer.capacity();

            if (oldCapacity == maxSize) {
		return maxSize;
	    }

            buffer.setCapacity(maxSize);
                
            if (!textFieldLF.lValidate(buffer, constraints)) {
                buffer.setCapacity(oldCapacity);
                throw new IllegalArgumentException();
            }
             
	    // Notify LF that contents has changed due to maxSize   
            textFieldLF.lSetMaxSize(maxSize);
                
            return buffer.capacity();
        }
    }

    /**
     * Gets the number of characters that are currently stored in this
     * <code>TextField</code>.
     * @return number of characters in the <code>TextField</code>
     */
    public int size() {
        synchronized (Display.LCDUILock) {
	    textFieldLF.lUpdateContents();
            return buffer.length();
        }
    }

    /**
     * Gets the current input position.  For some UIs this may block and ask
     * the user for the intended caret position, and on other UIs this may
     * simply return the current caret position.
     *
     * @return the current caret position, <code>0</code> if at the beginning
     */
    public int getCaretPosition() {
        synchronized (Display.LCDUILock) {
            return textFieldLF.lGetCaretPosition();
        }
    }

    /**
     * Sets the input constraints of the <code>TextField</code>. If
     * the the current contents
     * of the <code>TextField</code> do not match the new
     * <code>constraints</code>, the contents are
     * set to empty.
     *
     * @param constraints see <a href="#constraints">input constraints</a>
     *
     * @throws IllegalArgumentException if constraints is not any of the ones
     * specified in <a href="TextField.html#constraints">input constraints</a>
     * @see #getConstraints
     */
    public void setConstraints(int constraints)  {
        synchronized (Display.LCDUILock) {
            setConstraintsImpl(constraints);
        }
    }
  
    /**
     * Gets the current input constraints of the <code>TextField</code>.
     *
     * @return the current constraints value (see
     * <a href="#constraints">input constraints</a>)
     * @see #setConstraints
     */
    public int getConstraints() {
	return constraints;
    }

    /**
     * Sets a hint to the implementation as to the input mode that should be 
     * used when the user initiates editing of this <code>TextField</code>.  The
     * <code>characterSubset</code> parameter names a subset of Unicode 
     * characters that is used by the implementation to choose an initial 
     * input mode.  If <code>null</code> is passed, the implementation should 
     * choose a default input mode.
     *
     * <p>See <a href="#modes">Input Modes</a> for a full explanation of input 
     * modes. </p>
     *
     * @param characterSubset a string naming a Unicode character subset,
     * or <code>null</code>
     *
     */
    public void setInitialInputMode(String characterSubset) {
        synchronized (Display.LCDUILock) {
            initialInputMode = characterSubset;
            textFieldLF.lSetInitialInputMode(initialInputMode);            
        }
    }

    // ========================================================================
    // package private methods
    // ========================================================================

    /**
     * Creates a new <code>TextField</code> object with the given label, initial
     * contents, maximum size in characters, and constraints.  Behaves
     * the same as the public <code>TextField</code> constructor above except
     * for an additional argument <code>forTextBox</code> which signals 
     * this <code>TextField</code> will be used alone as a 
     * <code>TextBox</code> widget.
     * @param label item label
     * @param text the initial contents, or <code>null</code> if the
     * <code>TextField</code> is to be empty
     * @param maxSize the maximum capacity in characters
     * @param constraints see <a href="#constraints">input constraints</a>
     * @param forTextBox true if this textField will be used to implement
     *        a TextBox object.  when false, this method's results are
     *        identical to the public <code>TextField</code> constructor.
     * @throws IllegalArgumentException if <code>maxSize</code> is zero or less
     * @throws IllegalArgumentException if the value of the constraints
     * parameter
     * is invalid
     * @throws IllegalArgumentException if <code>text</code> is illegal
     * for the specified constraints
     * @throws IllegalArgumentException if the length of the string exceeds
     * the requested maximum capacity 
     */    
    TextField(String label, String text, int maxSize, 
	      int constraints, boolean forTextBox) {

        super(label);

        synchronized (Display.LCDUILock) {

            // IllegalArgumentException thrown here
            buffer = new DynamicCharacterArray(maxSize);

	    // Constraint value is checked here. Since textFieldLF is not
	    // yet created, no LF notification will happen.
            setConstraintsImpl(constraints);

	    if (forTextBox) {
		itemLF = textFieldLF = LFFactory.getFactory().getTextBoxLF(this);
	    } else {
		// Create a LF with empty content
		itemLF = textFieldLF = LFFactory.getFactory().getTextFieldLF(this);
	    }
            //
            // this will use inputClient
	    // Right now setCharsImpl notifies LF a content change.
	    // If LF is created as an absolutely last thing then
            // setCharsImple here does not need the notification.
            if (text == null) {
                setCharsImpl(null, 0, 0);
            } else {
                setCharsImpl(text.toCharArray(), 0, text.length());
            }
        }
    }
    /**
     * Deletes characters from the <code>TextField</code>.
     *
     * <p>The <code>offset</code> and <code>length</code> parameters must
     * specify a valid range of characters within
     * the contents of the <code>TextField</code>.
     * The <code>offset</code> parameter must be within the
     * range <code>[0..(size())]</code>, inclusive.
     * The <code>length</code> parameter
     * must be a non-negative integer such that
     * <code>(offset + length) <= size()</code>.</p>
     * 
     * @param offset the beginning of the region to be deleted
     * @param length the number of characters to be deleted
     *
     * @throws IllegalArgumentException if the resulting contents
     * would be illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws StringIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not
     * specify a valid range within the contents of the <code>TextField</code>
     */
    void deleteImpl(int offset, int length) {

        if (length == 0) {
	    return;
	}

	// Update buffer with latest user input
	textFieldLF.lUpdateContents();

	// Keep old contents in case we need to restore below
	String oldContents = buffer.toString();

	// StringIndexOutOfBoundsException can be thrown here
        buffer.delete(offset, length);

        if (!textFieldLF.lValidate(buffer, constraints)) {
	    // Restore to old contents
	    buffer.delete(0, buffer.length()); 
	    buffer.insert(0, oldContents);
	    throw new IllegalArgumentException();
        }

	// Notify LF that contents has changed due to delete
	textFieldLF.lDelete(offset, length);
    }

    /**
     * Sets the contents of the <code>TextField</code> from a
     * character array, replacing the
     * previous contents.
     *
     * @param data the source of the character data
     * @param offset the beginning of the region of characters to copy
     * @param length the number of characters to copy
     * @throws ArrayIndexOutOfBoundsException if <code>offset</code>
     * and <code>length</code> do not specify
     * a valid range within the data array
     * @throws IllegalArgumentException if <code>data</code>
     * is illegal for the current
     * <a href="TextField.html#constraints">input constraints</a>
     * @throws IllegalArgumentException if the text would exceed the current
     * maximum capacity
     */
    void setCharsImpl(char[] data, int offset, int length) {

        if (data == null) {
            buffer.delete(0, buffer.length());
        } else {
            
            if (offset < 0 || offset > data.length
                || length < 0 || length > data.length
                || offset + length < 0
                || offset + length > data.length) {
                throw new ArrayIndexOutOfBoundsException();
            }
            
            if (length > buffer.capacity()) {
                throw new IllegalArgumentException();
            }
            
            if (length > 0) {
                DynamicCharacterArray dca = 
                    new DynamicCharacterArray(length);
                
                dca.set(data, offset, length);
                
                if (!textFieldLF.lValidate(dca, constraints)) {
                    throw new IllegalArgumentException();
                }
            }
            
            buffer.set(data, offset, length);
        }

	// Notify LF contents has changed due to setChars
	textFieldLF.lSetChars();
    }

    /**
     * Sets the input constraints of the <code>TextField</code>.
     * @param constraints see <a href="#constraints">input constraints</a>
     *
     * @throws IllegalArgumentException if constraints is not any of the ones
     * specified in <a href="TextField.html#constraints">input constraints</a>
     */
    void setConstraintsImpl(int constraints)  {

        if ((constraints & CONSTRAINT_MASK) < ANY || 
            (constraints & CONSTRAINT_MASK) > DECIMAL) { 
                throw new IllegalArgumentException();
        }
        
	this.constraints = constraints;

	// Since this function is called from Constructor before
	// LF is created, checking is necessary.
        if (textFieldLF == null) {
	    return;
	}

	textFieldLF.lSetConstraints();

	// If current contents doesn't satisfy new constraints,
	// set it to empty.
	textFieldLF.lUpdateContents();

	int curLen = buffer.length();
        if (curLen > 0 && !textFieldLF.lValidate(buffer, constraints)) {
            buffer.delete(0, curLen);
	    textFieldLF.lDelete(0, curLen);
        }
    }

    /**
     * Inserts data into the buffer.
     * 
     * @param data - data to be inserted
     * @param offset - <placeholder>
     * @param length - <placeholder>
     * @param position - <placeholder>
     */
    void insertImpl(char data[], int offset, int length, int position) {

	textFieldLF.lUpdateContents();

        int pos = buffer.insert(data, offset, length, position);

        if (!textFieldLF.lValidate(buffer, constraints)) {
            buffer.delete(pos, length); // reverse insertion
            throw new IllegalArgumentException();
        }

	// Notify LF contents has changed due a insertion
        textFieldLF.lInsert(data, offset, length, pos);
    }
    
    /**
     * Return whether the Item takes user input focus.
     *
     * @return Always return <code>true</code> so user can scroll
     * or highlight selection.
     */
    boolean acceptFocus() {
	return true;
    }
    
    /**
     * Notify the item to the effect that it has been recently deleted.
     * In addition to default action call TraverseOut for the TextField 
     */
     void itemDeleted() {
         textFieldLF.itemDeleted();
         super.itemDeleted();
     }

    /**
     * The look&feel associated with this TextField. 
     * Set in the constructor.
     */
    TextFieldLF textFieldLF; // = null

    /** buffer to store the text */
    DynamicCharacterArray buffer;
 
    /** Input constraints */
    int constraints;

    /** the initial input mode for when the text field gets focus */
    String initialInputMode = null; 
}