javauis/lcdui_qt/src/javax/microedition/lcdui/TextFieldLayouter.java
changeset 21 2a9601315dfc
child 23 98ccebc37403
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javauis/lcdui_qt/src/javax/microedition/lcdui/TextFieldLayouter.java	Mon May 03 12:27:20 2010 +0300
@@ -0,0 +1,505 @@
+/*
+* Copyright (c) 2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description: 
+*
+*/
+package javax.microedition.lcdui;
+
+import org.eclipse.ercp.swt.mobile.ConstrainedText;
+import org.eclipse.ercp.swt.mobile.TextExtension;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.*;
+import org.eclipse.swt.graphics.Point;
+import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Control;
+
+/**
+ * Responsible for correct layout of TextField in a Form.
+ */
+class TextFieldLayouter extends ItemLayouter {
+
+    /**
+     * Key name for modify listener.
+     */
+    private static final String MODIFY_LISTENER = "modify";
+
+    /**
+     * Key name for key listener.
+     */
+    private static final String KEY_LISTENER = "key";
+
+    /**
+     * Key name for mouse listener.
+     */
+    private static final String MOUSE_LISTENER = "mouse";
+
+
+    /**
+     * Percentage of the whole screen.
+     */
+    private static final int TOTAL_PERCENTAGE = 100;
+
+
+    // private static Control[] staticControls = new Control[6];
+
+    private static TextExtension any;
+    private static ConstrainedText numeric;
+    private static ConstrainedText phonenr;
+    private static ConstrainedText decimal;
+    private static TextExtension   email;
+    private static TextExtension   url;
+    private static boolean isCorrectText;
+
+    /**
+     * Constructor.
+     *
+     * @param dflp DefaultFormLayoutPolicy`
+     */
+    TextFieldLayouter(DefaultFormLayoutPolicy dflp) {
+        super(dflp);
+    }
+
+    /**
+     * Get static eSWT control (ConstraintText or TextExtension).
+     *
+     * @param constraint
+     */
+    static Control eswtGetStaticTextControl(int constraint) {
+        Control ret = null;
+
+        /*
+        int maskedConstraint = constraint & TextField.CONSTRAINT_MASK;
+
+        if (staticControls[maskedConstraint] == null) {
+            staticControls[maskedConstraint] = TextWrapper.eswtConstructText(
+                    eswtGetStaticShell(), SWT.MULTI | SWT.WRAP, constraint);
+            ret = staticControls[maskedConstraint];
+        }
+        */
+
+        if (constraint == TextField.NUMERIC) {
+            if (numeric == null) {
+                numeric = new ConstrainedText(eswtGetStaticShell(), SWT.SINGLE,
+                        ConstrainedText.NUMERIC);
+            }
+            ret = numeric;
+        }
+        else if (constraint == TextField.DECIMAL) {
+            if (decimal == null) {
+                decimal = new ConstrainedText(eswtGetStaticShell(), SWT.SINGLE,
+                        ConstrainedText.DECIMAL);
+            }
+            ret = decimal;
+        }
+        else if (constraint == TextField.PHONENUMBER) {
+            if (phonenr == null) {
+                phonenr = new ConstrainedText(eswtGetStaticShell(), SWT.SINGLE,
+                        ConstrainedText.PHONENUMBER);
+            }
+            ret = phonenr;
+        }
+        else {
+            // TODO: eSWT support required - text validation on EMAIL and URL constraints
+            // default
+            if (any == null) {
+                any = new TextExtension(eswtGetStaticShell(), SWT.MULTI | SWT.WRAP);
+            }
+            ret = any;
+        }
+
+        return ret;
+    }
+
+    /**
+     * Check that text satisfies specified constraints.
+     *
+     * @param constraint TextField.NUMERIC etc.
+     * @return true if text is correct for specified constraint.
+     */
+    static boolean checkText(final int constraint, final String text) {
+        isCorrectText = true;
+        ESWTUIThreadRunner.syncExec(new Runnable() {
+            public void run() {
+                try {
+                    TextWrapper.eswtSetContent(
+                            eswtGetStaticTextControl(constraint), text);
+                }
+                catch (IllegalArgumentException e) {
+                    isCorrectText = false;
+                }
+            }
+        });
+        return isCorrectText;
+    }
+
+    /**
+     * eSWT specific calls to implement getControl.
+     *
+     * @param parent for the control.
+     * @param item TextField item.
+     */
+    Control eswtGetControl(Composite parent, Item item) {
+        TextField textfield = (TextField) item;
+
+        Control te = TextWrapper.eswtConstructText(parent,
+                SWT.WRAP | SWT.MULTI, textfield.getConstraints());
+        TextWrapper.eswtSetMaxSize(te, textfield.getMaxSize());
+        TextWrapper.eswtSetContent(te, textfield.getString());
+        TextWrapper.eswtSetSelection(te,
+                textfield.getCaretPosition(), textfield.getCaretPosition());
+
+        if (textfield.getInitialInputMode() != null) {
+            eswtUpdateItem(textfield, te, TextField.UPDATE_INITIAL_INPUT_MODE,
+                    null);
+        }
+        return te;
+    }
+
+    /**
+     * Returns true if this eSWT control is suitable to be used for updating.
+     *
+     * @param item Item.
+     * @param control eSWT control.
+     *
+     * @return true if this control is suitable for update
+     */
+    boolean eswtIsSpecificControl(Item item, Control control) {
+        return (control instanceof TextExtension
+                || control instanceof ConstrainedText);
+    }
+
+    /**
+     * Updates the values of TextField.
+     *
+     * @param item Item.
+     * @param control eSWT control.
+     * @param reason reason to update.
+     */
+    void eswtUpdateItem(Item item, Control control, int reason, Object param) {
+        TextField textfield = (TextField) item;
+        if (reason == Item.UPDATE_CONTENT) {
+            TextWrapper.eswtSetContent(control, textfield.getString());
+        }
+        else if (reason == TextField.UPDATE_INITIAL_INPUT_MODE) {
+            TextWrapper.eswtSetInputMode(control,
+                    textfield.getInitialInputMode(),
+                    textfield.getConstraints());
+        }
+    }
+
+    /**
+     * Update size of TextField.
+     *
+     * @param item TextField.
+     * @param control Control which represents TextField.
+     * @param width which control must occupy.
+     */
+    void eswtResizeControl(Item item, Control control, int width, int height) {
+        super.eswtResizeControl(item, control, width, height);
+        if (control instanceof TextExtension) {
+            TextExtension te = (TextExtension) control;
+            ((TextField) item).internalSetLinesCount(te.getLineCount());
+        }
+    }
+
+    /**
+     * Returns true if that key was consumed by TextField.
+     *
+     * @param item TextField.
+     * @param key keyCode.
+     */
+    boolean eswtOfferKeyPressed(Item item, int key) {
+        TextField tf = (TextField) item;
+        if (item.hasLayout(Item.LAYOUT_SHRINK)) {
+            if ((key == SWT.ARROW_LEFT
+                    && tf.getCaretPosition() == 0)
+                || (key == SWT.ARROW_RIGHT
+                    && tf.getCaretPosition() == tf.size())) {
+                return false;
+            }
+        }
+        if (((key == SWT.ARROW_UP)
+                    && (tf.getCaretPosition() == 0))
+            || ((key == SWT.ARROW_DOWN)
+                    && (tf.getCaretPosition() == tf.size()))) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * Responsible for reacting on focusGained event, and according to direction
+     * from which that event comes sets the caret of the TextField.
+     *
+     * @param item TextField.
+     * @param dir direction from which focus came, in case if it was set with
+     *            setCurrentItem() default direction is used (-1).
+     */
+    void eswtFocusGained(Item item, int dir) {
+        super.eswtFocusGained(item, dir);
+        TextField tf = (TextField) item;
+        // direction = dir;
+        resetCaretPosition(tf, dir);
+        Control control = eswtGetFirstSpecificControl(item);
+        TextWrapper.eswtSetSelection(control,
+                tf.getCaretPosition(), tf.getCaretPosition());
+    }
+
+    /**
+     * Returns the minimum area needed to display a TextField.
+     *
+     * @param textField TextField object
+     * @return Minimum area needed to display TextField.
+     */
+    static Point calculateMinimumBounds(final TextField textField) {
+        final Point minSize = new Point(0, 0);
+        ESWTUIThreadRunner.syncExec(new Runnable() {
+            public void run() {
+                TextExtension tempExt = (TextExtension) eswtGetStaticTextControl(TextField.ANY);
+                tempExt.setText(ItemLayouter.MIN_TEXT);
+                tempExt.pack();
+                minSize.x = tempExt.getSize().x;
+                minSize.y = tempExt.getSize().y + Config.TEXTFIELD_MARGIN;
+                applyMinMargins(textField, minSize);
+            }
+        });
+        return minSize;
+    }
+
+    /**
+     * Returns the preferred area needed to display an Item.
+     *
+     * @param item Item.
+     * @return Preferred area needed to display Item. x is width and y is
+     *         height.
+     */
+    static Point calculatePreferredBounds(Item item) {
+        final TextField textfield = (TextField) item;
+        final Point prefSize = new Point(0, 0);
+        ESWTUIThreadRunner.syncExec(new Runnable() {
+            public void run() {
+                TextExtension te = (TextExtension) eswtGetStaticTextControl(TextField.ANY);
+                te.setText(textfield.getString());
+
+                int maxHeight = (formHeigh
+                        * Config.TEXTFIELD_MAX_SCREEN_PERCENTAGE / TOTAL_PERCENTAGE)
+                        - Config.TEXTFIELD_MARGIN;
+                textfield.internalSetMaxVisibleLines(maxHeight
+                        / te.getLineHeight());
+
+                prefSize.x = getMaximumItemWidth(textfield);
+                prefSize.y = Config.TEXTFIELD_MARGIN + Math.min(
+                        te.computeSize(prefSize.x, SWT.DEFAULT).y, maxHeight);
+                // prefSize.y = Math.min(calc.y, maxHeight) + MARGIN;
+                applyPrefMargins(textfield, prefSize);
+            }
+        });
+        return prefSize;
+    }
+
+    /**
+     * Update caret position based on direction.
+     *
+     * @param textfield TextField for which to update caret position.
+     * @param dir direction of scrolling.
+     */
+    private void resetCaretPosition(TextField textfield, int dir) {
+        switch (dir) {
+            case SWT.ARROW_DOWN:
+                textfield.internalSetCaretPosition(0);
+                break;
+            case SWT.ARROW_RIGHT:
+                textfield.internalSetCaretPosition(0);
+                break;
+            case SWT.ARROW_UP:
+                textfield.internalSetCaretPosition(textfield.size());
+                break;
+            case SWT.ARROW_LEFT:
+                textfield.internalSetCaretPosition(textfield.size());
+                break;
+            default:
+                break;
+        }
+    }
+
+    /**
+     * Add TextField listeners when form is activated.
+     *
+     * @param item TextField.
+     * @param control Control which represents TextField.
+     */
+    void eswtAddSpecificListeners(Item item, Control control) {
+        super.eswtAddSpecificListeners(item, control);
+        TextField textfield = (TextField) item;
+        ModifyListener listener = new TextFieldModifyListener(textfield);
+        TextWrapper.eswtAddModListener(control, listener);
+        control.setData(MODIFY_LISTENER, listener);
+        KeyListener listener2 = new TextFieldKeyListener(textfield);
+        control.addKeyListener(listener2);
+        control.setData(KEY_LISTENER, listener2);
+        MouseListener listener4 = new AllMouseListener(textfield);
+        control.addMouseListener(listener4);
+        control.setData(MOUSE_LISTENER, listener4);
+    }
+
+    /**
+     * Remove listeners from a TextField if the form goes to background.
+     *
+     * @param item TextField.
+     * @param control Control which represents TextField.
+     */
+    void eswtRemoveSpecificListeners(Item item, Control control) {
+        super.eswtRemoveSpecificListeners(item, control);
+        ModifyListener l1 = (ModifyListener) control.getData(MODIFY_LISTENER);
+        if (l1 != null) {
+            TextWrapper.eswtRemoveModListener(control, l1);
+            control.setData(MODIFY_LISTENER, null);
+        }
+        KeyListener l2 = (KeyListener) control.getData(KEY_LISTENER);
+        if (l2 != null) {
+            control.removeKeyListener(l2);
+            control.setData(KEY_LISTENER, null);
+        }
+        MouseListener l4 = (MouseListener) control.getData(MOUSE_LISTENER);
+        if (l4 != null) {
+            control.removeMouseListener(l4);
+            control.setData(MOUSE_LISTENER, null);
+        }
+    }
+
+    /**
+     * Class that receives ModifyEvents from TextExtension and updates values of
+     * TextField.
+     */
+    class TextFieldModifyListener implements ModifyListener {
+
+        private TextField textfield;
+
+        TextFieldModifyListener(TextField textField) {
+            this.textfield = textField;
+        }
+
+        private void handleLinesChange(TextExtension te) {
+            int lines = te.getLineCount();
+            int visibleLines = te.getSize().y / te.getLineHeight();
+            if (lines != textfield.internalGetLinesCount()) {
+                textfield.internalSetLinesCount(lines);
+                Control control = eswtGetFirstControl(textfield);
+                if (control.getSize().y + te.getLineHeight()
+                        + Config.TEXTFIELD_MARGIN <= dfi.getFormHeight()) {
+                    textfield.updateParent(Item.UPDATE_HEIGHT_CHANGED);
+                }
+                if (textfield.internalGetLinesCount() > lines) {
+                    if ((te.getTopIndex() + visibleLines) > lines) {
+                        te.setTopIndex(Math.max(0, lines - visibleLines));
+                    }
+                    if (visibleLines > lines) {
+                        textfield.updateParent(Item.UPDATE_HEIGHT_CHANGED);
+                    }
+                }
+
+                te.setTopIndex(Math.max(te.getCaretLineNumber() + 1
+                        - textfield.internalGetMaxVisibleLines(), 0));
+            }
+        }
+
+        public void modifyText(ModifyEvent modifyEvent) {
+            Control te = (Control) modifyEvent.widget;
+            if (textfield.internalSetString(TextWrapper.eswtGetContent(te))) {
+                Logger.method(textfield, "modify", modifyEvent);
+                textfield.internalSetCaretPosition(
+                        TextWrapper.eswtGetCaretPosition(te));
+                if (te instanceof TextExtension) {
+                    handleLinesChange((TextExtension) te);
+                }
+                textfield.notifyStateChanged();
+            }
+        }
+    }
+
+    /**
+     * Class that receives KeyEvents from TextExtension and updates
+     * caret position for TextField.
+     */
+    class TextFieldKeyListener implements KeyListener {
+
+        private TextField textfield;
+
+        TextFieldKeyListener(TextField textField) {
+            this.textfield = textField;
+        }
+
+        public void keyPressed(KeyEvent keyEvent) {
+            Control te =  (Control) keyEvent.widget;
+            int caretPos = TextWrapper.eswtGetCaretPosition(te);
+            int caretLine = TextWrapper.eswtGetCaretLine(te);
+
+            if (keyEvent.keyCode == SWT.ARROW_UP && caretLine == 0) {
+                caretPos = 0;
+                TextWrapper.eswtSetSelection(te, caretPos, caretPos);
+            }
+            else if (keyEvent.keyCode == SWT.ARROW_DOWN
+                    && (caretLine == (TextWrapper.eswtGetLineCount(te) - 1))) {
+                caretPos = textfield.size();
+                TextWrapper.eswtSetSelection(te, caretPos, caretPos);
+            }
+
+            textfield.internalSetCaretPosition(caretPos);
+        }
+
+        public void keyReleased(KeyEvent keyEvent) {
+            // this is needed if focus was changed with touch.
+            // so ne scrolling was done in DFI.
+            if (!dfi.isItemFullyVisible(textfield)) {
+                dfi.eswtScrollToItem(textfield);
+            }
+            textfield.internalSetCaretPosition(
+                    TextWrapper.eswtGetCaretPosition((Control) keyEvent.widget));
+        }
+
+    }
+
+    class AllMouseListener implements MouseListener, MouseMoveListener {
+
+        private TextField textfield;
+        private boolean isEnabled;
+
+        AllMouseListener(TextField tf) {
+            textfield = tf;
+        }
+
+        public void enable(boolean enabled) {
+            isEnabled = enabled;
+        }
+
+        public void mouseUp(MouseEvent me) {
+            if (isEnabled) {
+                //
+            }
+        }
+
+        public void mouseDown(MouseEvent me) {
+            textfield.internalSetCaretPosition(
+                    TextWrapper.eswtGetCaretPosition((Control) me.widget));
+        }
+
+        public void mouseMove(MouseEvent me) {
+        }
+
+        public void mouseDoubleClick(MouseEvent me) {
+        }
+
+    }
+
+}