diff -r e8e63152f320 -r 2a9601315dfc javauis/lcdui_qt/src/javax/microedition/lcdui/TextFieldLayouter.java --- /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) { + } + + } + +}