FileDocCategorySizeDatePackage
TextFieldLFImpl.javaAPI DocphoneME MR2 API (J2ME)61592Wed May 02 18:00:20 BST 2007javax.microedition.lcdui

TextFieldLFImpl

public class TextFieldLFImpl extends ItemLFImpl implements TextInputComponent, CommandListener, TextFieldLF
This is the look &s; feel implementation for TextField.

Fields Summary
protected TextField
tf
TextField instance associated with this view
protected com.sun.midp.lcdui.TextCursor
cursor
cursor to keep track of where to draw the cursor
protected boolean
editable
editable state of the text field
protected boolean
firstTimeInTraverse
flag indicating the first time traverse is executed
protected String
initialInputMode
The character set to use as the initial input mode, may be null
protected InputMode
interruptedIM
The input mode cause the traverse out for the text component
protected SubMenuCommand
inputMenu
This SubMenuCommand holds the set of InputModes available on the InputMode pull-out menu
protected static TextInputSession
inputSession
The TextInputMediator which handles translating key presses
protected static com.sun.midp.chameleon.layers.PTILayer
pt_popup
The PopupLayer that represents open state of this ChoiceGroup POPUP.
protected InputMode[]
inputModes
The set of InputModes available to process this text component
protected com.sun.midp.chameleon.layers.InputModeLayer
inputModeIndicator
A special "popup" layer that shows the user an indicator of what the currently selected input mode is
private boolean
pt_popupOpen
The state of the popup ChoiceGroup (false by default)
String[]
pt_matches
predictive text options
protected int[]
inputModeAnchor
A four dimensional array holding the anchor point, item height, and space below the item which corresponds to the parameters to the InputModeLayer's setAnchor() method
protected boolean
showIMPopup
This is a flag to turn on the input mode indicator popup
protected boolean
usePreferredX
true if the preferredX field in TextCursor should be updated with the latest TextCursor.x coordinate
protected int
xScrollOffset
pixel offset to the start of the text field (for example, if xScrollOffset is -60 it means means that the text in this text field is scrolled 60 pixels left of the left edge of the text field)
protected int
textWidth
Total width of the text contained in this TextField
protected int
scrollWidth
Width of the scroll area for text
protected static Timer
textScrollTimer
A Timer which will handle firing repaints of the ScrollPainter
protected TextScrollPainter
textScrollPainter
A TimerTask which will repaint scrolling text on a repeated basis
private boolean
pressedIn
flag indicating the pointer press event is happened but release is still not handled
protected Vector
timers
Pool of the active timers
protected Timer
timerService
The Timer to service TimerTasks.
Constructors Summary
TextFieldLFImpl(TextField tf)
Creates TextFieldLF for the passed in TextField.

param
tf The TextField associated with this TextFieldLF


                        
      
        super(tf);
        
        TextFieldResources.load();
        PTIResources.load();
        InputModeResources.load();
        
        this.tf = tf;
        
        cursor = new TextCursor(tf.buffer.length());
        cursor.visible = false;
        xScrollOffset = 0;
        
        if (inputSession == null) {
            inputSession = new BasicTextInputSession();
            pt_popup = new PTILayer(inputSession);
        }
        
        lSetConstraints();
        
        if (textScrollTimer == null) {
            textScrollTimer = new Timer();
        }
        
        inputModeIndicator = new InputModeLayer();
        inputModeAnchor = new int[4];
    
Methods Summary
private voidaddInputCommands()
Add input modes specific commands

        inputMenu.removeAll();
        if (inputModes != null) {
            Command[] inputCommands = new Command[inputModes.length];
            for (int i = 0; i < inputModes.length; i++) {
                inputCommands[i] = new Command(
                         inputModes[i].getCommandName(), Command.OK, i);
            }
            inputMenu.addSubCommands(inputCommands);
            // NOTE : adding the command here relies on the
            // implementation of Item.addCommand() to not add
            // the same command twice, as stated in the MIDP spec
            tf.addCommand(inputMenu);                       
        }
    
protected booleanbufferedTheSameAsDisplayed(int constraints)
Check if the string in the text buffer is the same as the string that is actually displayed

param
constraints text input constraints
return
true if the the string is the same otherwise false

        return !((constraints & TextField.PASSWORD) == TextField.PASSWORD
            || (constraints & TextField.CONSTRAINT_MASK) ==
            TextField.PHONENUMBER);
    
protected synchronized voidcancelTimerKey(int keyCode)
Cancel any running Timer.

param
keyCode key the timer is canceled for

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[cancelTimerKey] for " + keyCode);
        }
        TimerKey timer = new TimerKey(keyCode);
        int idx = timers.indexOf(timer);
        if (idx != -1) {
            ((TimerKey) timers.elementAt(idx)).stop();
        }
    
public voidclear(int num)
Clear the particular number of symbols

param
num number of symbols

        if (cursor.index <= 0) {
            return;
        }

        if (num == 0) {
            System.err.println(
                "TextFieldLFImpl Warning: asked to delete 0!");
            return;
        }
        if (cursor.index == 0) {
            System.err.println(
            "TextFieldLFImpl Warning: asked to delete when cursor index is 0!");
            return;
        }
        synchronized (Display.LCDUILock) {
            try {
                tf.delete(cursor.index - num, num);
            } catch (Throwable t) {
                t.printStackTrace();
            }
            tf.notifyStateChanged();
        }
       
    
public voidcommandAction(Command c, Displayable d)
This CommandListener is only for the selection of Commands on the Input sub-menu, which lists each of the available InputModes for this text component.

param
c command
param
d displayable

        Command[] inputCommands = inputMenu.getSubCommands();
        String label = c.getLabel();
        if (inputCommands != null && label != null) {
            for (int i = 0; i < inputCommands.length; i++) {
                if (label.equals(inputCommands[i].getLabel())) {
                    inputSession.setCurrentInputMode(inputModes[i]);
                    break;
                }
            }
        }
    
public voidcommit(java.lang.String input)
Commit the given input to this TextInputComponent's buffer. This call constitutes a change to the value of this TextInputComponent and should result in any listeners being notified.

param
input text to commit

        if (input == null || input.length() == 0) {
            return;
        }

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "TF.commit:: " + input);
        }

        synchronized (Display.LCDUILock) {
            try {
                cursor.visible = true;
                DynamicCharacterArray in = tf.buffer;

                TextCursor newCursor = new TextCursor(cursor);
                for (int i = 0; i < input.length(); i++) {
                    String str = getDisplayString(in, input.charAt(i),
                        tf.constraints,
                        newCursor, true);
                    in = new DynamicCharacterArray(str);
                }


                if (bufferedTheSameAsDisplayed(tf.constraints)) {
                    if (lValidate(in, tf.constraints)) {
                        tf.delete(0, tf.buffer.length());
                        tf.insert(in.toString(), 0);
                        setCaretPosition(newCursor.index);
                        tf.notifyStateChanged();
                    }
                } else if (tf.buffer.length() < tf.getMaxSize()) {
                    tf.insert(input, cursor.index);
                    tf.notifyStateChanged();
                }
            } catch (Exception ignore) {
            }
        }
    
private voiddisableInput()
Disable text field input

        disableTF();
        removeInputCommands();       
        inputSession.endSession();
    
private voiddisableTF()
Disable text field

        cursor.option = Text.PAINT_USE_CURSOR_INDEX;
        cursor.visible = false;
    
private voidenableInput()
Enable text field input

        enableTF();

        // ASSERT (editable && hasFocus)
        inputSession.beginSession(this);
    
private voidenableTF()
Enable text field

        cursor.option = Text.PAINT_USE_CURSOR_INDEX;
        cursor.visible = true;
    
booleanequateNLA()
Determine if this Item should have a newline after it

return
true if it should have a newline after

        if (super.equateNLA()) {
            return true;
        }        
        return ((tf.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
    
booleanequateNLB()
Determine if this Item should have a newline before it

return
true if it should have a newline before

        if (super.equateNLB()) {
            return true;
        }
        return ((tf.layout & Item.LAYOUT_2) != Item.LAYOUT_2);
    
private intgePrevCursorIndex(int constraints, com.sun.midp.lcdui.DynamicCharacterArray str, int cursor)
Get previous cursor position

param
constraints text input constraints. The semantics of the constraints value are defined in the TextField API.
param
str text
param
cursor current cursor index
return
previious cursor index

        cursor--;
        if (((constraints & TextField.CONSTRAINT_MASK) ==
             TextField.DECIMAL ||
             (constraints & TextField.CONSTRAINT_MASK) ==
             TextField.NUMERIC) &&
            cursor == 1 &&
            str.length() == 2 &&
            (str.charAt(0) == '-" ||
             str.charAt(0) == '.")) {
            cursor--;
        }
        return cursor;
    
public intgetAvailableSize()
Returns the available size (number of characters) that can be stored in this TextInputComponent.

return
available size in characters

        return tf.getMaxSize() - tf.buffer.length();
    
public java.lang.StringgetBufferString(com.sun.midp.lcdui.DynamicCharacterArray dca, int constraints, com.sun.midp.lcdui.TextCursor cursor, boolean modifyCursor)
Returns the string that would be stored. This may not be the same as the string that is actually displayed because of the options argument that affects painting.

param
dca the displayed text
param
constraints text constraints
param
cursor text cursor object to use to draw vertical bar
param
modifyCursor true if this method can modify the cursor object if necessary, false otherwise
return
the string that will be stored in buffer. This may not be what is actually drawn depending on the options. If it's impossible to get the actual string null is returned

        
        String ret = null; 
        if (!bufferedTheSameAsDisplayed(constraints)) {
            DynamicCharacterArray out = new DynamicCharacterArray(dca.length());
            
            if (!modifyCursor) {
                cursor = new TextCursor(cursor);
            }

            if ((constraints & TextField.CONSTRAINT_MASK) ==
                TextField.PHONENUMBER) {
                for (int i = 0, j = 0; i < dca.length(); i++) {
                    char next = dca.charAt(i);
                    if (next == ' ") {
                        if (cursor.index > i) cursor.index--;
                    } else {
                        out.insert(j++, next);
                    }
                }
            }
            ret = out.toString();
        } else {
            ret = dca.toString(); 
        }
        return ret;
    
public intgetConstraints()
Retrieve the constraints of this text component as defined by the LCDUI TextField API.

return
a bitmask which defines the constraints set on this text component, or 0 if none were set(?)

        synchronized (Display.LCDUILock) {
            return tf.constraints;
        }
    
public DisplaygetDisplay()
Retrieve the display for the text component

return
the display used for the text component

        return getCurrentDisplay();
    
public java.lang.StringgetDisplayString(com.sun.midp.lcdui.DynamicCharacterArray dca, char opChar, int constraints, com.sun.midp.lcdui.TextCursor cursor, boolean modifyCursor)
Returns the string that would be painted. This may not be the same as the string that is actually displayed because of the options argument that affects painting.

param
dca the text to paint
param
opChar option char
param
constraints text constraints
param
cursor text cursor object to use to draw vertical bar
param
modifyCursor true if this method can modify the cursor object if necessary, false otherwise
return
the string that will be sent to be drawn. this may not be what is actually drawn depending on the options

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[tf.getDisplayString]");
        }
        DynamicCharacterArray out = new DynamicCharacterArray(dca.length() + 1);

        int index = cursor == null ? dca.length() : cursor.index;

        if ((constraints & TextField.PASSWORD) == TextField.PASSWORD) {
            index = getStringForPassword(dca, constraints, index, opChar, out);
        } else { // not password
            out.insert(dca.toCharArray(), 0, dca.length(), 0);

            switch (constraints & TextField.CONSTRAINT_MASK) {
                case TextField.PHONENUMBER:
                    index = getStringForPhoneNumber(dca, index, opChar, out);
                    break;
                case TextField.DECIMAL:
                    index = getStringForDecimal(dca, index, opChar, out);
                    break;
                case TextField.NUMERIC:
                    index = getStringForNumeric(dca, index, opChar, out);
                    break;
                case TextField.EMAILADDR:
                case TextField.URL:
                case TextField.ANY:
                    if (opChar > 0 && dca.length() < tf.getMaxSize()) {
                        out.insert(index++, opChar);
                    }
                    break;
                default:
                    // for safety/completeness.
                    Logging.report(Logging.ERROR, LogChannels.LC_HIGHUI,
                        "TextFieldLFImpl: constraints=" + constraints);
                    if (opChar > 0 && dca.length() < tf.getMaxSize()) {
                        out.insert(index++, opChar);
                    }
                    break;
            }
        }

        if (out == null) {
            out = dca;
        }

        if (modifyCursor && cursor != null) {
            cursor.index = index;
        }

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[TF.getDisplayString] getMatchList:");
        }
        pt_matches = inputSession.getMatchList();

        return out.toString();
    
protected intgetIndexAt(int x, int y)
Get character index at the pointer position

param
x pointer x coordinate
param
y pointer y coordinate
return
the character index

        int i = -1;
        x -= contentBounds[X] +
            TextFieldSkin.PAD_H +
            xScrollOffset;
        if (x >= 0) {
            char[] data = tf.buffer.toCharArray();
            for (i = 1; i <= tf.buffer.length(); i++) {
                if (x <= ScreenSkin.FONT_INPUT_TEXT.charsWidth(data, 0, i)) {
                    break;
                }
            }
            i--;
        }
        
        return i;
    
public java.lang.StringgetInitialInputMode()
Retrieve the initial input mode of this text component as defined by the LCDUI TextField API.

return
the initial input mode for this text component or 'null' if none was set(?)

        synchronized (Display.LCDUILock) {
            return this.initialInputMode;
        }
    
protected int[]getInputModeAnchor()
This is a utility function to calculate the anchor point for the InputModeIndicator layer. This takes into account the item's location as well as the containing form's scroll location. The array is a 4 element array corresponding to the the parameters to the InputModeLayer's setAnchor() method.

return
input mode anchor (x, y, w, h)

        int[] anchor = new int[] { 0, 0, 0, 0};
        try {
            ScreenLFImpl sLF = (ScreenLFImpl)tf.owner.getLF();
            int x = getInnerBounds(X) - sLF.viewable[X] + contentBounds[X];
            int y = getInnerBounds(Y) - sLF.viewable[Y] + contentBounds[Y];
            
            // anchor x-coordinate relative to InputModeLayer
            anchor[0] = x + contentBounds[WIDTH]
                          + getCurrentDisplay().getWindow().getBodyAnchorX();
            // anchor y-coordinate relative to InputModeLayer
            anchor[1] = y + getCurrentDisplay().getWindow().getBodyAnchorY();
            // item height
            anchor[2] = contentBounds[HEIGHT];
            // space below the bottom of the item on the screen
            anchor[3] = (sLF.viewport[HEIGHT] + sLF.viewable[Y]) - 
                (bounds[Y] + bounds[HEIGHT]);
           
        } catch (Throwable t) { }
        return anchor;
    
private intgetStringForDecimal(com.sun.midp.lcdui.DynamicCharacterArray dca, int index, char opChar, com.sun.midp.lcdui.DynamicCharacterArray out)
Returns the string that would be painted for the decimal constraints.

param
dca the text to paint
param
index cursor index
param
opChar option char
param
out the string that will be sent to be drawn.
return
new cursor index

        // it can be extended by '0' if '.' is added at the beginning 
        out.setCapacity(dca.length() + 1 + 1);
        // change the number sign
        if (' " == opChar) {
            if (dca.charAt(0) == '-") {
                out.delete(0, 1);
                if (index > 0) index--;
            } else if (dca.length() < tf.getMaxSize()) {
                out.insert(0, '-");
                index++;
            }
            opChar = 0;
        } else if ('." == opChar && dca.length() < tf.getMaxSize()) {
            /**
             * insert the '.'. If it's inserted at the beginning of the number
             * '0' has to be added before the '.' Number can not contain '.'
             * twice
             */
            char[] buf = dca.toCharArray();
            int i = 0;
            for (; i < dca.length(); i++) {
                if (buf[i] == '.") break;
            }
            if (i == dca.length()) {
                if (dca.charAt(0) == '-") {
                    if (index == 0) index++;
                    if (index == 1) out.insert(index++, '0");
                } else if (index == 0) {
                    out.insert(index++, '0");
                }
            } else {
                opChar = 0;
            }
        }
        if (opChar > 0 && dca.length() < tf.getMaxSize()) {
            out.insert(index++, opChar);
        }
        return index;
    
private intgetStringForNumeric(com.sun.midp.lcdui.DynamicCharacterArray dca, int index, char opChar, com.sun.midp.lcdui.DynamicCharacterArray out)
Returns the string that would be painted for the numeric constraints.

param
dca the text to paint
param
index cursor index
param
opChar option char
param
out the string that will be sent to be drawn.
return
new cursor index

        // change the number sign
        if (' " == opChar) {
            if (dca.charAt(0) == '-") {
                out.delete(0, 1);
                if (index > 0) index--;
            } else if (dca.length() < tf.getMaxSize()) {
                out.insert(0, '-");
                index++;
            }
        } else if (opChar > 0 && dca.length() < tf.getMaxSize()) {
            out.insert(index++, opChar);
        }
        return index;
    
private intgetStringForPassword(com.sun.midp.lcdui.DynamicCharacterArray dca, int constraints, int index, char opChar, com.sun.midp.lcdui.DynamicCharacterArray out)
Returns the string that would be painted for the password modifier.

param
dca the text to paint
param
index cursor index
param
opChar option char
param
out the string that will be sent to be drawn.
param
constraints text input constraints
return
new cursor index

        for (int i = 0; i < dca.length(); i++) {
            out.append('*");
        }
        
        if (opChar > 0 && dca.length() < tf.getMaxSize()) {
            out.insert(index++, opChar);
        }
        return index;
    
private intgetStringForPhoneNumber(com.sun.midp.lcdui.DynamicCharacterArray dca, int index, char opChar, com.sun.midp.lcdui.DynamicCharacterArray out)
Returns the string that would be painted for the phone number constraints

param
dca the text to paint
param
index cursor index
param
opChar option char
param
out the string that will be sent to be drawn.
return
new cursor index

        // +3 is the most characters we will need to insert here
        out.setCapacity(dca.length() + 1 + 3);
        
        switch (dca.length()) {
        case 5:
        case 6:
        case 7:
            if (out.length() < tf.getMaxSize()) {
            out.insert(3, ' ");
            if (index > 3) index++;
            }
            break;
        case 11:
            if (out.length() + 2 < tf.getMaxSize()) {
            out.insert(1, ' ");
            if (index > 1) index++;
            out.insert(5, ' ");
            if (index > 5) index++;
            out.insert(9, ' ");
            if (index > 9) index++;
            }
            break;
        case 8:
        case 9:
        case 10:
        default:
            if (out.length() + 1 < tf.getMaxSize()) {
            out.insert(3, ' ");
            if (index > 3) index++;
            out.insert(7, ' ");
            if (index > 7) index++;
            }
            break;
        case 0:
        case 1:
        case 2:
        case 3:
        case 4:
            break;
        }
        if (opChar > 0 && out.length() + 1 < tf.getMaxSize()) {
            out.insert(index++, opChar);
        }
        return index;
    
private voidhandleClearKey(int keyCode, boolean longPress)
Handle Clear key

param
keyCode the code for the key which was pressed
param
longPress true if long key press happens otherwise false

        if (isClearKey(keyCode)) {
            if (longPress) {
                if (tf.buffer.length() > 0) {
                    tf.delete(0, tf.buffer.length());
                    tf.notifyStateChanged();
                }
            } else {
                clear(cursor.index -
                      gePrevCursorIndex(tf.constraints,
                                        tf.buffer,
                                        cursor.index));
            }
        }
    
public booleanhasPTI()
Check if PTI popup is visible

return
true if pti layer is visible, false - otherwise

        return pt_popupOpen;
    
protected voidhidePTILayer()
Hide predictive text popup dialog

        Display d = getCurrentDisplay();
        if (pt_popupOpen && d != null) {
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[showPTPopup] hiding");
            }
            d.hidePopup(pt_popup);
            pt_popupOpen = false;
            lRequestInvalidate(true, true);
        }
    
public booleanisClearKey(int keyCode)
Returns true if the keyCode is used as 'clear'

param
keyCode key code
return
true if keu code is Clear one, false otherwise

        return EventConstants.SYSTEM_KEY_CLEAR ==
            KeyConverter.getSystemKey(keyCode);        
    
public voiditemDeleted()
Notifies item that it has been recently deleted Traverse out the textFieldLF. This implicitly remove the InputMode indicator and possibly the Predictive Text Input indicator from the screen.

         uCallTraverseOut();
     
protected voidkeyClicked(int keyCode)
Emulate the key click

param
keyCode key code

        uCallKeyPressed(keyCode);
        uCallKeyReleased(keyCode);
    
booleanlCallTraverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout)
Called by the system

The default implementation of the traverse() method always returns false.

param
dir the direction of traversal
param
viewportWidth the width of the container's viewport
param
viewportHeight the height of the container's viewport
param
visRect_inout passes the visible rectangle into the method, and returns the unmodified traversal rectangle from this method
return
true if internal traversal had occurred, false if traversal should proceed out
see
#getInteractionModes
see
#traverseOut
see
#TRAVERSE_HORIZONTAL
see
#TRAVERSE_VERTICAL

        // By design, traverse should ONLY happen after the item is notified
        // to be shown, including the very first show a Form.
        // ASSERT (visible == true)
        super.lCallTraverse(dir, viewportWidth, viewportHeight, visRect_inout);

        boolean ret = false;
        Display currentDisplay = getCurrentDisplay();

        if (firstTimeInTraverse || dir == CustomItem.NONE) {

            if (firstTimeInTraverse) {
                if (editable) {
                    InputMode im = inputSession.getCurrentInputMode(); 
                    if (im != null && im.hasDisplayable()) {
                        enableTF();
                    } else {
                        // IMPL NOTE: try-catch has to be removed when the form
                        // is fixed. Form resets the focus to the 1st item after
                        // Symbol Table goes away
                        try {
                            enableInput();
                        } catch (Exception ignore) {
                        }
                    }
                    if (interruptedIM != null) {
                        inputSession.setCurrentInputMode(interruptedIM);
                        interruptedIM = null;
                    }

                } else {
                    cursor.option = Text.PAINT_USE_CURSOR_INDEX;
                    cursor.visible = false;
                    startScroll();
                }
                // Show Input Indicator regardless of editability
                // so we don't have to turn the layer on/off
                // when setConstraints() is called later, which
                // may cause deadlock between locks 'layers' and
                // LCDUILock.
                showIMPopup = true;
                firstTimeInTraverse = false;
            }
            
            lRequestPaint();
            // if (currentDisplay != null) {
            //    currentDisplay.serviceRepaints(tf.owner.getLF());
            // }
            ret = true;
            
        } else {
            
            if (moveCursor(dir)) {           
                lRequestPaint();
                // if (currentDisplay != null) {
                //    currentDisplay.serviceRepaints(tf.owner.getLF());
                // }
                ret = true;
            }            
        }

        // item has to be visible completelly
        visRect_inout[X] = 0;
        visRect_inout[Y] = 0;
        visRect_inout[WIDTH] = bounds[WIDTH];
        visRect_inout[HEIGHT] = bounds[HEIGHT];
            
        return ret;
    
voidlCallTraverseOut()
Called by the system to indicate traversal has left this Item

see
#getInteractionModes
see
#traverse
see
#TRAVERSE_HORIZONTAL
see
#TRAVERSE_VERTICAL

        super.lCallTraverseOut();
        
        firstTimeInTraverse = true;
        
        if (editable) {
            InputMode im = inputSession.getCurrentInputMode(); 
            if (im != null && im.hasDisplayable()) { 
                disableTF();
                ((ScreenLFImpl)tf.owner.getLF()).resetToTop = false;
            } else { 
                disableInput();
  
                if (im != null) { 
                    interruptedIM = im; 
                } else {
                    cursor.index = tf.buffer.length(); 
                }
            }
            // Leave the hide of indicator layer to uCallTraverseOut
            // to avoid deadlocking
        } else {
	    cursor.option = Text.PAINT_USE_CURSOR_INDEX;
            cursor.visible = false;
            cursor.index = tf.buffer.length();
        }
        xScrollOffset = 0;
        
        if (textScrollPainter != null) { 
            stopScroll();
        }
        
        lRequestPaint();
    
public voidlCommitPendingInteraction()
Called to commit any pending character from the input handler

        // IMPL NOTE: fix needed? inputHandler.endComposition(false);
    
public voidlDelete(int offset, int length)
Notifies L&amsp;F of character deletion in the corresponding TextField.

param
offset the beginning of the deleted region
param
length the number of characters deleted

        if (cursor.index >= offset) {
            int diff = cursor.index - offset;
            cursor.index -= (diff < length) ? diff : length;
            cursor.option = Text.PAINT_USE_CURSOR_INDEX;
        } 
        if (!editable) {
            resetUneditable();
        }
        if (item.owner == null) {
            return; // because owner is null, we just return.
        }
        lRequestPaint();
    
public intlGetCaretPosition()
Gets the current input position.

return
the current caret position, 0 if at the beginning

        return cursor.index;
    
voidlGetContentSize(int[] size, int availableWidth)
Sets the content size in the passed in array. Content is calculated based on the availableWidth. size[WIDTH] and size[HEIGHT] should be set by this method.

param
size The array that holds Item content size and location in Item internal bounds coordinate system.
param
availableWidth The width available for this Item

       Font f = ScreenSkin.FONT_INPUT_TEXT;
       size[HEIGHT] = f.getHeight() + (2 * TextFieldSkin.PAD_V);
       size[WIDTH] = f.charWidth('W") * tf.buffer.capacity() +
            (2 * TextFieldSkin.PAD_H);
       if (size[WIDTH] > availableWidth) {
            size[WIDTH] = availableWidth;
       }

        // update scrollWidth used in scrolling UE text
        scrollWidth = size[WIDTH] - (2 * TextFieldSkin.PAD_H) - 1;
    
public voidlInsert(char[] data, int offset, int length, int position)
Notifies L&s;F of a character insertion in the corresponding TextField.

param
data the source of the character data
param
offset the beginning of the region of characters copied
param
length the number of characters copied
param
position the position at which insertion occurred

        if (data == null) {
            return; // -au
        }
        if (position <= cursor.index) {
            cursor.index += length;
            cursor.option = Text.PAINT_USE_CURSOR_INDEX;
        }
        if (!editable) {
            resetUneditable();
        }
        if (item.owner == null) {
            return; // because owner is null, we just return.
        }
        lRequestPaint();
    
voidlPaintContent(Graphics g, int width, int height)
Paints the content area of this TextField. Graphics is translated to contents origin.

param
g The graphics where Item content should be painted
param
width The width available for the Item's content
param
height The height available for the Item's content

        // Draw the TextField background region 
        if (editable) {
            if (TextFieldSkin.IMAGE_BG != null) {
                CGraphicsUtil.draw9pcsBackground(g, 0, 0, width, height,
                    TextFieldSkin.IMAGE_BG);
            } else {
                // draw widget instead of using images
                CGraphicsUtil.drawDropShadowBox(g, 0, 0, width, height,
                    TextFieldSkin.COLOR_BORDER,
                    TextFieldSkin.COLOR_BORDER_SHD, 
                    TextFieldSkin.COLOR_BG);
            }
        } else { 
            if (TextFieldSkin.IMAGE_BG_UE != null) { 
                CGraphicsUtil.draw9pcsBackground(g, 0, 0, width, height,
                    TextFieldSkin.IMAGE_BG_UE);
            } else {
                // draw widget instead of using images
                CGraphicsUtil.drawDropShadowBox(g, 0, 0, width, height,
                    TextFieldSkin.COLOR_BORDER_UE,
                    TextFieldSkin.COLOR_BORDER_SHD_UE, 
                    TextFieldSkin.COLOR_BG_UE);
            }
        }

        // We need to translate by 1 more pixel horizontally 
        // to reserve space for cursor in the empty textfield
        g.clipRect(TextFieldSkin.PAD_H, TextFieldSkin.PAD_V,
            width - (2 * TextFieldSkin.PAD_H),
            height - (2 * TextFieldSkin.PAD_V));
        g.translate(TextFieldSkin.PAD_H + 1, 
                    TextFieldSkin.PAD_V);

        int clr;
        if (hasFocus) {
            clr = (editable ? ScreenSkin.COLOR_FG_HL : 
                   ScreenSkin.COLOR_FG_HL);
        } else {
            clr = (editable ? TextFieldSkin.COLOR_FG :
                   TextFieldSkin.COLOR_FG_UE);
        }
        
        xScrollOffset = paint(g, tf.buffer,
            inputSession.getPendingChar(), 
            tf.constraints,
            ScreenSkin.FONT_INPUT_TEXT, clr, 
            width - (2 * TextFieldSkin.PAD_H), 
            height - (2 * TextFieldSkin.PAD_V), 
            xScrollOffset, Text.NORMAL, cursor); 
        
        g.translate(-(TextFieldSkin.PAD_H + 1), 
                    -TextFieldSkin.PAD_V);
        
        if (usePreferredX) {
            cursor.preferredX = cursor.x;
        }
    
public voidlSetChars()
Notifies L&F of a content change in the corresponding TextField.

        cursor.index = tf.buffer.length(); // cursor at the end
        cursor.option = Text.PAINT_USE_CURSOR_INDEX;
        if (!editable) {
            resetUneditable();
        }
        lRequestPaint();
    
public voidlSetConstraints()
Notifies L&s;F that constraints have to be changed.

    	setConstraintsCommon(true);
        
        // The layout might change if the constraints does not match
        // the current text, causing the text to be set empty,
        // or changed to "password", causing it to change width
        // Request relayout to based on updated contentSize
        if (item.owner == null) {
            return; // because owner is null, we just return.
        }
        lRequestInvalidate(true, true);
    
public voidlSetInitialInputMode(java.lang.String characterSubset)
Notifies L&s;F that preferred initial input mode was changed.

param
characterSubset a string naming a Unicode character subset, or null

        this.initialInputMode = characterSubset;
    
public voidlSetMaxSize(int maxSize)
Notifies L&s;F of a maximum size change in the corresponding TextField.

param
maxSize - the new maximum size

        int max = tf.getMaxSize();
        if (cursor.index > max) {
            cursor.index = max;
        }
        lRequestInvalidate(true, true);
    
public booleanlUpdateContents()
Update the character buffer in TextField with pending user input. Since Java TextField always keeps TextField.buffer up-to-date, there is no pending user input. Do nothing but return false here.

return
true if there is new user input updated in the buffer.

        return false; // nothing pending
    
public booleanlValidate(com.sun.midp.lcdui.DynamicCharacterArray buffer, int constraints)
Validate a given character array against a constraints.

param
buffer a character array
param
constraints text input constraints
return
true if constraints is met by the character array

        return TextPolicy.isValidString(buffer, constraints);
    
booleanmoveCursor(int dir)
Move the text cursor in the given direction

param
dir direction to move
return
true if the cursor was moved, false otherwise

        boolean keyUsed = false;
        int newIndex;

        switch (dir) {
        case Canvas.LEFT:
            if (editable) {
                keyClicked(dir);
                if (cursor.index > 0) {
                    cursor.option = Text.PAINT_USE_CURSOR_INDEX;
                    keyUsed = true;
                    cursor.index--;
                }
            }
        break;
        
        case Canvas.RIGHT:
            if (editable) {
                keyClicked(dir);
                if (cursor.index < tf.buffer.length()) {                    
                    cursor.option = Text.PAINT_USE_CURSOR_INDEX;
                    keyUsed = true;
                    cursor.index++;
                }
            }
        break;

        case Canvas.UP:
        case Canvas.DOWN:
        default:
            break;
        }
        
        return keyUsed;
    
voidmoveInputModeIndicator()
Move input mode indicator

  
        int[] anchor = getInputModeAnchor();
        if (inputModeAnchor[0] != anchor[0] ||
            inputModeAnchor[1] != anchor[1] ||
            inputModeAnchor[2] != anchor[2] ||
            inputModeAnchor[3] != anchor[3])
        {
            inputModeAnchor = anchor;
            inputModeIndicator.setAnchor(
                                         inputModeAnchor[0],
                inputModeAnchor[1],
                inputModeAnchor[2],
                inputModeAnchor[3]);
        }
    
public voidnotifyModeChanged()
This is a notification from the input session that the selected input mode has changed. If the TextInputComponent is interested, it can query the session for the new InputMode.

        removeInputCommands();

        inputModes = inputSession.getAvailableModes();
        InputMode im = inputSession.getCurrentInputMode();       

        inputMenu = new SubMenuCommand(im.getCommandName(), Command.OK, 100);
        inputMenu.setListener(this);
       
        addInputCommands();
       
        inputModeIndicator.setDisplayMode(im.getName());
    
public intpaint(Graphics g, com.sun.midp.lcdui.DynamicCharacterArray dca, char opChar, int constraints, Font font, int fgColor, int w, int h, int offset, int options, com.sun.midp.lcdui.TextCursor cursor)
Paint the text, scrolling left or right when necessary. (A TextField may only be one line hight)

param
g the Graphics to use to paint with. If g is null then only the first four arguments are used and nothing is painted. Use this to return just the displayed string
param
dca the text to paint
param
opChar option char
param
constraints text constraints
param
font the font to use to paint the text
param
fgColor foreground color
param
w the available width for the text
param
h the available height for the text
param
offset the first line pixel offset
param
options any of Text.[NORMAL | INVERT | HYPERLINK | TRUNCATE]
param
cursor text cursor object to use to draw vertical bar
return
the current xScrollOffset value which may be changed to match the return value of Text.paintLine()


        int newXOffset = 0;
        
        g.clipRect(0, 0, w, h);

        if (opChar != 0) {
            cursor = new TextCursor(cursor);
        }
        String str = getDisplayString(dca, opChar, constraints,
                                      cursor, true);

        if (hasFocus) {
            newXOffset = Text.paintLine(g, str, font, fgColor,
                                        w, h, cursor, offset);
        } else {
            Text.drawTruncString(g, str, font, fgColor, w);
            newXOffset = 0;
        }

        // just correct cursor index if the charracter has
        // been already committed 
        if (str != null && str.length() > 0) {
            getBufferString(new DynamicCharacterArray(str),
                            constraints, cursor, true);
        }

        showPTPopup((int)0, cursor, w, h);
        return newXOffset;
    
private voidremoveInputCommands()
Remove input modes specific commands

        tf.removeCommand(inputMenu);
    
public voidrepaintScrollText()
Called repeatedly to animate a side-scroll effect for uneditable text within a TextField

        if (-xScrollOffset < (textWidth - scrollWidth)) {
            xScrollOffset -= TextFieldSkin.SCROLL_SPEED;
            lRequestPaint();
        } else {
            // already scrolled to the end of text
            stopScroll(); 
        }
    
private voidresetUneditable()
Initialize or reset variables used to auto-scroll uneditable text across this TextField

        String text = getDisplayString(
            tf.buffer, inputSession.getPendingChar(),
            tf.constraints, cursor, true);
        
        textWidth = ScreenSkin.FONT_INPUT_TEXT.stringWidth(text);
        
        xScrollOffset = 0;
    
voidsetBorder(boolean state)
Turns the border on or off. hasBorder=false used to indicate a textBox, but now that case in handled in the TextBoxLFImpl class

param
state true to turn the border on, false to turn it off

        // API requires this method to exist, so no-op
    
protected voidsetCaretPosition(int pos)
Set new cursor position

param
pos new position

        cursor.index = pos;
        if (cursor.index < 0) {
            cursor.index = 0;
        }
        if (cursor.index > tf.buffer.length()) {
            cursor.index = tf.buffer.length();
        }
    
voidsetConstraintsCommon(boolean autoScrolling)
Update states associated with input constraints.

param
autoScrolling true if auto scrolling is allowed to show large uneditable contents

	// Cleanup old states that are constraints sensitive
        if (hasFocus && visible) {
	    if (editable) {
		disableInput();
	    } else if (autoScrolling) {
		stopScroll();
	    }
	}

	// Change editability
        editable = 
            (tf.constraints & TextField.UNEDITABLE) != TextField.UNEDITABLE;
        
	// Setup new states that are constraints sensitive
        if (hasFocus && visible) {
	    if (editable) {
                enableInput();
	    } else if (autoScrolling) {
                startScroll();
            }
        }
    
protected synchronized voidsetTimerKey(int keyCode)
Set a new timer.

param
keyCode the key the timer is started for


                         
         
        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[setTimerKey] for " + keyCode);
        }
        TimerKey timer = new TimerKey(keyCode);
        if (!timers.contains(timer)) {
            try {
                timer.start();
            } catch (IllegalStateException e) {
                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                    Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                        "Exception caught in setTimer");
                }
                cancelTimerKey(keyCode);
            }
        }
    
booleanshouldSkipTraverse()
Indicate whether or not traversing should occur.

return
false always

        return false;
    
protected voidshowPTILayer()
Show predictive text popup dialog

        Display d = getCurrentDisplay();
        if (!pt_popupOpen && d != null) {
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[showPTPopup] showing");
            }
            d.showPopup(pt_popup);
            pt_popupOpen = true;
            lRequestInvalidate(true, true);
        }
    
protected voidshowPTPopup(int keyCode, com.sun.midp.lcdui.TextCursor cursor, int width, int height)
Show predictive text popup dialog

param
keyCode key code
param
cursor text cursor
param
width width
param
height height

        if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
            Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                "[ showPTPopup] " + keyCode + "," + cursor +
                    "," + width + "," + height);
        }
        if (pt_matches.length > 1) { // show layer 
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[showPTPopup]    pt_matches.length =" + pt_matches.length);
            }
            pt_popup.setList(pt_matches);
            showPTILayer();
        } else { // hide layer
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "[hidePTPopup]    pt_matches=0");
            }
            hidePTILayer();
        }
    
public voidstartScroll()
Start the scrolling of the text in textField

        if (editable || !hasFocus || textWidth <= scrollWidth) {
            return;
        }
        stopScroll();
        textScrollPainter = new TextScrollPainter();
        textScrollTimer.schedule(textScrollPainter, 0, 
                                 TextFieldSkin.SCROLL_RATE);
    
public voidstopScroll()
Stop the scrolling of the text in TextField

        if (textScrollPainter == null) {
            return;
        }
        textScrollPainter.cancel();
        textScrollPainter = null;
    
voiduCallKeyPressed(int keyCode)
Handle a key press

param
keyCode the code for the key which was pressed

        boolean theSameKey = timers.contains(new TimerKey(keyCode));

        if (!theSameKey) {
            setTimerKey(keyCode);
        }

        synchronized (Display.LCDUILock) {
            // IMPL NOTE: add back in the phone dial support after defining
            // more system keys like 'send'

            if (KeyConverter.getSystemKey(keyCode) ==
                EventConstants.SYSTEM_KEY_SEND) {
                if ((getConstraints() & TextField.CONSTRAINT_MASK)
                    == TextField.PHONENUMBER) {
                    PhoneDial.call(tf.getString());
                }
                return;
            }

            if (!editable) {
                // play sound
                AlertType.WARNING.playSound(getCurrentDisplay());
                return;
            }

            int key;
            if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                    "TF.processKey keyCode = " + keyCode +
                        " longPress = " + theSameKey);
            }
            if ((key = inputSession.processKey(keyCode, theSameKey)) ==
                InputMode.KEYCODE_NONE) {
                // This means the key wasn't handled by the InputMode
                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                    Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                        "[TF.uCallKeyPressed] returned KEYCODE_NONE");
                }
                handleClearKey(keyCode, theSameKey);
            } else if (key != InputMode.KEYCODE_INVISIBLE) {
                if (Logging.REPORT_LEVEL <= Logging.INFORMATION) {
                    Logging.report(Logging.INFORMATION, LogChannels.LC_HIGHUI,
                        "[TF.uCallKeyPressed] returned key = " + key);
                }

                cursor.visible = true;
                lRequestPaint();
            }
        } // synchronized
    
voiduCallKeyReleased(int keyCode)
Handle a key release event

param
keyCode key that was released Obsoleted: Java PhonePad input is replaced by platform input methods.

        /*
         * IMPL NOTE: abstract the press/release to constants so that
         * a port can be configured as to which one to use via the
         * constants definition file
        */

        cancelTimerKey(keyCode);
    
voiduCallKeyRepeated(int keyCode)
Handle a key repeated event

param
keyCode key that was repeated

        uCallKeyPressed(keyCode);
    
voiduCallPointerPressed(int x, int y)
Handle a pointer press event

param
x pointer x coordinate
param
y pointer y coordinate

        pressedIn = true;
        super.uCallPointerPressed(x, y);
    
voiduCallPointerReleased(int x, int y)
Handle a pointer released event

param
x pointer x coordinate
param
y pointer y coordinate

        // don't call super method because text field does not have the option 
        // to activate the command assigned to this item by the pointer

        // accept the word if the PTI is currently enabled
        if (hasPTI()) {
            inputSession.processKey(Constants.KEYCODE_SELECT, false);
        }
        
        if (pressedIn) {
            int newId = getIndexAt(x, y);
            if (newId >= 0 &&
                newId <= tf.buffer.length() &&
                newId != cursor.index) {
                cursor.index = newId;
                cursor.option = Text.PAINT_USE_CURSOR_INDEX;
                lRequestPaint();
            }

            pressedIn = false;
        }
    
public voiduCallScrollChanged(int newViewportX, int newViewportY)
Called by the system to indicate the content has been scrolled inside of the form

param
newViewportX the new width of the viewport of the screen
param
newViewportY the new height of the viewport of the screen

        synchronized (Display.LCDUILock) {
            if (hasFocus && inputModeIndicator.getDisplayMode() != null) {
                // move input mode indicator because its location depends on 
                // the item width and item location
                moveInputModeIndicator();
            }
        }
    
voiduCallSizeChanged(int w, int h)
Called by the system to indicate the size available to this Item has changed

param
w the new width of the item's content area
param
h the new height of the item's content area

        super.uCallSizeChanged(w, h);
        synchronized (Display.LCDUILock) {
            xScrollOffset = 0;
            
            if (textScrollPainter != null) { 
                stopScroll();
            }

            startScroll();
            // move input mode indicator because its location depends on 
            // the item width and item location
            if (hasFocus && inputModeIndicator.getDisplayMode() != null) {
                moveInputModeIndicator();
            }
        }
    
booleanuCallTraverse(int dir, int viewportWidth, int viewportHeight, int[] visRect_inout)
Called by the system

The default implementation of the traverse() method always returns false.

param
dir the direction of traversal
param
viewportWidth the width of the container's viewport
param
viewportHeight the height of the container's viewport
param
visRect_inout passes the visible rectangle into the method, and returns the unmodified traversal rectangle from this method
return
true if internal traversal had occurred, false if traversal should proceed out
see
#getInteractionModes
see
#traverseOut
see
#TRAVERSE_HORIZONTAL
see
#TRAVERSE_VERTICAL

        boolean ret = super.uCallTraverse(dir, viewportWidth, viewportHeight,
                                          visRect_inout);
        
        // Show indicator layer
        if (showIMPopup) {
            if (inputModeIndicator.getDisplayMode() != null) {
                getCurrentDisplay().showPopup(inputModeIndicator);
                moveInputModeIndicator();
                showIMPopup = false;
            }
        }
        
        return ret;
    
voiduCallTraverseOut()
Called by the system to indicate traversal has left this Item

see
#getInteractionModes
see
#traverse
see
#TRAVERSE_HORIZONTAL
see
#TRAVERSE_VERTICAL

        super.uCallTraverseOut();
        
        // Dismiss input mode indicator layer outside LCDUILock
        // to avoid deadlocking with Chameleon internal lock 'layers'.
        Display currentDisplay = getCurrentDisplay();
        if (currentDisplay != null) {
	    currentDisplay.hidePopup(inputModeIndicator);
            hidePTILayer();
        }