/*
* 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) {
}
}
}