/*
*
*
* Copyright 1990-2009 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;
}