summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArtur Signell <artur.signell@itmill.com>2010-12-07 11:55:09 +0000
committerArtur Signell <artur.signell@itmill.com>2010-12-07 11:55:09 +0000
commitb76d5386b0e0ee8188f1094ec49edbef9e9edd7b (patch)
tree042d8d4347ce8c318025eeb50d7f8c8a823896fe
parent8ef4e5d2f73eb4c599f2f72a719cfa75dffe566e (diff)
downloadvaadin-framework-b76d5386b0e0ee8188f1094ec49edbef9e9edd7b.tar.gz
vaadin-framework-b76d5386b0e0ee8188f1094ec49edbef9e9edd7b.zip
#3752 - Refactor TextFields
Made PasswordField, TextArea extend AbstractTextField instead of TextField Moved commonalities "columns", "input prompt", "text change event" and "cursor position" to AbstractTextField svn changeset:16354/svn branch:6.5
-rw-r--r--src/com/vaadin/ui/AbstractTextField.java520
-rw-r--r--src/com/vaadin/ui/PasswordField.java24
-rw-r--r--src/com/vaadin/ui/TextArea.java81
-rw-r--r--src/com/vaadin/ui/TextField.java419
-rw-r--r--tests/src/com/vaadin/tests/components/textarea/TextAreaTest.java2
-rw-r--r--tests/src/com/vaadin/tests/components/textfield/TextChangeEvents.java13
-rw-r--r--tests/src/com/vaadin/tests/components/textfield/TextChangeEvents2.java2
-rw-r--r--tests/src/com/vaadin/tests/components/textfield/TextFieldTest.java6
8 files changed, 557 insertions, 510 deletions
diff --git a/src/com/vaadin/ui/AbstractTextField.java b/src/com/vaadin/ui/AbstractTextField.java
index 7fe1306ea4..cd9d99de18 100644
--- a/src/com/vaadin/ui/AbstractTextField.java
+++ b/src/com/vaadin/ui/AbstractTextField.java
@@ -1,3 +1,7 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
package com.vaadin.ui;
import java.text.Format;
@@ -5,16 +9,24 @@ import java.util.Map;
import com.vaadin.event.FieldEvents.BlurEvent;
import com.vaadin.event.FieldEvents.BlurListener;
+import com.vaadin.event.FieldEvents.BlurNotifier;
import com.vaadin.event.FieldEvents.FocusEvent;
import com.vaadin.event.FieldEvents.FocusListener;
+import com.vaadin.event.FieldEvents.FocusNotifier;
+import com.vaadin.event.FieldEvents.TextChangeEvent;
+import com.vaadin.event.FieldEvents.TextChangeListener;
+import com.vaadin.event.FieldEvents.TextChangeNotifier;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
+import com.vaadin.terminal.gwt.client.ui.VTextField;
-public abstract class AbstractTextField extends AbstractField {
+public abstract class AbstractTextField extends AbstractField implements
+ BlurNotifier, FocusNotifier, TextChangeNotifier {
/**
* Value formatter used to format the string contents.
*/
+ @Deprecated
private Format format;
/**
@@ -31,7 +43,56 @@ public abstract class AbstractTextField extends AbstractField {
*/
private int maxLength = -1;
- public AbstractTextField() {
+ /**
+ * Number of visible columns in the TextField.
+ */
+ private int columns = 0;
+
+ /**
+ * The prompt to display in an empty field. Null when disabled.
+ */
+ private String inputPrompt = null;
+
+ /**
+ * The text content when the last messages to the server was sent.
+ */
+ private String lastKnownTextContent;
+
+ /**
+ * The position of the cursor when the last message to the server was sent.
+ */
+ private int lastKnownCursorPosition;
+
+ /**
+ * Flag indicating that a text change event is pending to be triggered.
+ * Cleared by {@link #setInternalValue(Object)} and when the event is fired.
+ */
+ private boolean textChangeEventPending;
+
+ private TextChangeEventMode textChangeEventMode = TextChangeEventMode.LAZY;
+
+ private final int DEFAULT_TEXTCHANGE_TIMEOUT = 400;
+
+ private int textChangeEventTimeout = DEFAULT_TEXTCHANGE_TIMEOUT;
+
+ /**
+ * Temporarily holds the new selection position. Cleared on paint.
+ */
+ private int selectionPosition = -1;
+
+ /**
+ * Temporarily holds the new selection length.
+ */
+ private int selectionLength;
+
+ /**
+ * Flag used to determine whether we are currently handling a state change
+ * triggered by a user. Used to properly fire text change event before value
+ * change event triggered by the client side.
+ */
+ private boolean changingVariables;
+
+ protected AbstractTextField() {
super();
}
@@ -43,6 +104,16 @@ public abstract class AbstractTextField extends AbstractField {
target.addAttribute("maxLength", getMaxLength());
}
+ // Adds the number of column and rows
+ final int columns = getColumns();
+ if (columns != 0) {
+ target.addAttribute("cols", String.valueOf(columns));
+ }
+
+ if (getInputPrompt() != null) {
+ target.addAttribute("prompt", getInputPrompt());
+ }
+
// Adds the content as variable
String value = getFormattedValue();
if (value == null) {
@@ -53,6 +124,20 @@ public abstract class AbstractTextField extends AbstractField {
"Null values are not allowed if the null-representation is null");
}
target.addVariable(this, "text", value);
+
+ if (selectionPosition != -1) {
+ target.addAttribute("selpos", selectionPosition);
+ target.addAttribute("sellen", selectionLength);
+ selectionPosition = -1;
+ }
+
+ if (hasListeners(TextChangeEvent.class)) {
+ target.addAttribute(VTextField.ATTR_TEXTCHANGE_EVENTMODE,
+ getTextChangeEventMode().toString());
+ target.addAttribute(VTextField.ATTR_TEXTCHANGE_TIMEOUT,
+ getTextChangeTimeout());
+ }
+
}
/**
@@ -88,97 +173,69 @@ public abstract class AbstractTextField extends AbstractField {
@Override
public void changeVariables(Object source, Map<String, Object> variables) {
+ changingVariables = true;
- super.changeVariables(source, variables);
-
- // Sets the text
- if (variables.containsKey("text") && !isReadOnly()) {
-
- // Only do the setting if the string representation of the value
- // has been updated
- String newValue = (String) variables.get("text");
+ try {
+ super.changeVariables(source, variables);
- // server side check for max length
- if (getMaxLength() != -1 && newValue.length() > getMaxLength()) {
- newValue = newValue.substring(0, getMaxLength());
- }
- final String oldValue = getFormattedValue();
- if (newValue != null
- && (oldValue == null || isNullSettingAllowed())
- && newValue.equals(getNullRepresentation())) {
- newValue = null;
+ if (variables.containsKey(VTextField.VAR_CURSOR)) {
+ Integer object = (Integer) variables.get(VTextField.VAR_CURSOR);
+ lastKnownCursorPosition = object.intValue();
}
- if (newValue != oldValue
- && (newValue == null || !newValue.equals(oldValue))) {
- boolean wasModified = isModified();
- setValue(newValue, true);
-
- // If the modified status changes, or if we have a formatter,
- // repaint is needed after all.
- if (format != null || wasModified != isModified()) {
- requestRepaint();
- }
+
+ if (variables.containsKey(VTextField.VAR_CUR_TEXT)) {
+ /*
+ * NOTE, we might want to develop this further so that on a
+ * value change event the whole text content don't need to be
+ * sent from the client to server. Just "commit" the value from
+ * currentText to the value.
+ */
+ textChangeEventPending = true;
+ handleInputEventTextChange(variables);
}
- }
- if (variables.containsKey(FocusEvent.EVENT_ID)) {
- fireEvent(new FocusEvent(this));
- }
- if (variables.containsKey(BlurEvent.EVENT_ID)) {
- fireEvent(new BlurEvent(this));
- }
+ // Sets the text
+ if (variables.containsKey("text") && !isReadOnly()) {
- }
+ // Only do the setting if the string representation of the value
+ // has been updated
+ String newValue = (String) variables.get("text");
- /**
- * Sets the height of the {@link TextField} instance.
- *
- * <p>
- * Setting height for {@link TextField} also has a side-effect that puts
- * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
- * can also be achieved by calling {@link #setRows(int)}. The height value
- * overrides the number of rows set by {@link #setRows(int)}.
- * <p>
- * If you want to set height of single line {@link TextField}, call
- * {@link #setRows(int)} with value 0 after setting the height. Setting rows
- * to 0 resets the side-effect.
- *
- * @see com.vaadin.ui.AbstractComponent#setHeight(float, int)
- */
- @Override
- public void setHeight(float height, int unit) {
- super.setHeight(height, unit);
- if (height > 1 && this instanceof TextField) {
- /*
- * In html based terminals we most commonly want to make component
- * to be textarea if height is defined. Setting row field above 0
- * will render component as textarea.
- */
+ // server side check for max length
+ if (getMaxLength() != -1 && newValue.length() > getMaxLength()) {
+ newValue = newValue.substring(0, getMaxLength());
+ }
+ final String oldValue = getFormattedValue();
+ if (newValue != null
+ && (oldValue == null || isNullSettingAllowed())
+ && newValue.equals(getNullRepresentation())) {
+ newValue = null;
+ }
+ if (newValue != oldValue
+ && (newValue == null || !newValue.equals(oldValue))) {
+ boolean wasModified = isModified();
+ setValue(newValue, true);
+
+ // If the modified status changes, or if we have a
+ // formatter, repaint is needed after all.
+ if (format != null || wasModified != isModified()) {
+ requestRepaint();
+ }
+ }
+ }
+ firePendingTextChangeEvent();
+
+ if (variables.containsKey(FocusEvent.EVENT_ID)) {
+ fireEvent(new FocusEvent(this));
+ }
+ if (variables.containsKey(BlurEvent.EVENT_ID)) {
+ fireEvent(new BlurEvent(this));
+ }
+ } finally {
+ changingVariables = false;
- ((TextField) this).setRows(2);
}
- }
- /**
- * Sets the height of the {@link TextField} instance.
- *
- * <p>
- * Setting height for {@link TextField} also has a side-effect that puts
- * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
- * can also be achieved by calling {@link #setRows(int)}. The height value
- * overrides the number of rows set by {@link #setRows(int)}.
- * <p>
- * If you want to set height of single line {@link TextField}, call
- * {@link #setRows(int)} with value 0 after setting the height. Setting rows
- * to 0 resets the side-effect.
- *
- * @see com.vaadin.ui.AbstractComponent#setHeight(java.lang.String)
- */
- @Override
- public void setHeight(String height) {
- // will call setHeight(float, int) the actually does the magic. Method
- // is overridden just to document side-effects.
- super.setHeight(height);
}
@Override
@@ -328,6 +385,303 @@ public abstract class AbstractTextField extends AbstractField {
requestRepaint();
}
+ /**
+ * Gets the number of columns in the editor. If the number of columns is set
+ * 0, the actual number of displayed columns is determined implicitly by the
+ * adapter.
+ *
+ * @return the number of columns in the editor.
+ */
+ public int getColumns() {
+ return columns;
+ }
+
+ /**
+ * Sets the number of columns in the editor. If the number of columns is set
+ * 0, the actual number of displayed columns is determined implicitly by the
+ * adapter.
+ *
+ * @param columns
+ * the number of columns to set.
+ */
+ public void setColumns(int columns) {
+ if (columns < 0) {
+ columns = 0;
+ }
+ this.columns = columns;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the current input prompt.
+ *
+ * @see #setInputPrompt(String)
+ * @return the current input prompt, or null if not enabled
+ */
+ public String getInputPrompt() {
+ return inputPrompt;
+ }
+
+ /**
+ * Sets the input prompt - a textual prompt that is displayed when the field
+ * would otherwise be empty, to prompt the user for input.
+ *
+ * @param inputPrompt
+ */
+ public void setInputPrompt(String inputPrompt) {
+ this.inputPrompt = inputPrompt;
+ requestRepaint();
+ }
+
+ /* ** Text Change Events ** */
+
+ private void firePendingTextChangeEvent() {
+ if (textChangeEventPending) {
+ fireEvent(new TextChangeEventImpl(this));
+ textChangeEventPending = false;
+ }
+ }
+
+ @Override
+ protected void setInternalValue(Object newValue) {
+ if (changingVariables) {
+ /*
+ * Fire text change event before value change event if change is
+ * coming from the client side.
+ */
+ if (newValue == null && lastKnownTextContent != null
+ && !lastKnownTextContent.equals(getNullRepresentation())) {
+ // Value was changed from something to null representation
+ lastKnownTextContent = getNullRepresentation();
+ textChangeEventPending = true;
+ } else if (newValue != null
+ && !newValue.toString().equals(lastKnownTextContent)) {
+ // Value was changed to something else than null representation
+ lastKnownTextContent = newValue.toString();
+ textChangeEventPending = true;
+ }
+
+ if (textChangeEventPending) {
+ firePendingTextChangeEvent();
+ }
+ }
+ super.setInternalValue(newValue);
+ }
+
+ private void handleInputEventTextChange(Map<String, Object> variables) {
+ /*
+ * TODO we could vastly optimize the communication of values by using
+ * some sort of diffs instead of always sending the whole text content.
+ * Also on value change events we could use the mechanism.
+ */
+ String object = (String) variables.get(VTextField.VAR_CUR_TEXT);
+ lastKnownTextContent = object;
+ textChangeEventPending = true;
+ }
+
+ /**
+ * Sets the mode how the TextField triggers {@link TextChangeEvent}s.
+ *
+ * @param inputEventMode
+ * the new mode
+ *
+ * @see TextChangeEventMode
+ */
+ public void setTextChangeEventMode(TextChangeEventMode inputEventMode) {
+ textChangeEventMode = inputEventMode;
+ requestRepaint();
+ }
+
+ /**
+ * @return the mode used to trigger {@link TextChangeEvent}s.
+ */
+ public TextChangeEventMode getTextChangeEventMode() {
+ return textChangeEventMode;
+ }
+
+ /**
+ * Different modes how the TextField can trigger {@link TextChangeEvent}s.
+ */
+ public enum TextChangeEventMode {
+
+ /**
+ * An event is triggered on each text content change, most commonly key
+ * press events.
+ */
+ EAGER,
+ /**
+ * Each text change event in the UI causes the event to be communicated
+ * to the application after a timeout. The length of the timeout can be
+ * controlled with {@link TextField#setInputEventTimeout(int)}. Only the
+ * last input event is reported to the server side if several text
+ * change events happen during the timeout.
+ * <p>
+ * In case of a {@link ValueChangeEvent} the schedule is not kept
+ * strictly. Before a {@link ValueChangeEvent} a {@link TextChangeEvent}
+ * is triggered if the text content has changed since the previous
+ * TextChangeEvent regardless of the schedule.
+ */
+ TIMEOUT,
+ /**
+ * An event is triggered when there is a pause of text modifications.
+ * The length of the pause can be modified with
+ * {@link TextField#setInputEventTimeout(int)}. Like with the
+ * {@link #TIMEOUT} mode, an event is forced before
+ * {@link ValueChangeEvent}s, even if the user did not keep a pause
+ * while entering the text.
+ * <p>
+ * This is the default mode.
+ */
+ LAZY
+ }
+
+ public void addListener(TextChangeListener listener) {
+ addListener(TextChangeListener.EVENT_ID, TextChangeEvent.class,
+ listener, TextChangeListener.EVENT_METHOD);
+ }
+
+ public void removeListener(TextChangeListener listener) {
+ removeListener(TextChangeListener.EVENT_ID, TextChangeEvent.class,
+ listener);
+ }
+
+ /**
+ * The text change timeout modifies how often text change events are
+ * communicated to the application when {@link #getTextChangeEventMode()} is
+ * {@link TextChangeEventMode#LAZY} or {@link TextChangeEventMode#TIMEOUT}.
+ *
+ *
+ * @see #getTextChangeEventMode()
+ *
+ * @param timeout
+ * the timeout in milliseconds
+ */
+ public void setTextChangeTimeout(int timeout) {
+ textChangeEventTimeout = timeout;
+ requestRepaint();
+ }
+
+ /**
+ * Gets the timeout used to fire {@link TextChangeEvent}s when the
+ * {@link #getTextChangeEventMode()} is {@link TextChangeEventMode#LAZY} or
+ * {@link TextChangeEventMode#TIMEOUT}.
+ *
+ * @return the timeout value in milliseconds
+ */
+ public int getTextChangeTimeout() {
+ return textChangeEventTimeout;
+ }
+
+ public class TextChangeEventImpl extends TextChangeEvent {
+ private String curText;
+ private int cursorPosition;
+
+ private TextChangeEventImpl(final AbstractTextField tf) {
+ super(tf);
+ curText = tf.getCurrentTextContent();
+ cursorPosition = tf.getCursorPosition();
+ }
+
+ @Override
+ public AbstractTextField getComponent() {
+ return (AbstractTextField) super.getComponent();
+ }
+
+ @Override
+ public String getText() {
+ return curText;
+ }
+
+ @Override
+ public int getCursorPosition() {
+ return cursorPosition;
+ }
+
+ }
+
+ /**
+ * Gets the current (or the last known) text content in the field.
+ * <p>
+ * Note the text returned by this method is not necessary the same that is
+ * returned by the {@link #getValue()} method. The value is updated when the
+ * terminal fires a value change event via e.g. blurring the field or by
+ * pressing enter. The value returned by this method is updated also on
+ * {@link TextChangeEvent}s. Due to this high dependency to the terminal
+ * implementation this method is (at least at this point) not published.
+ *
+ * @return the text which is currently displayed in the field.
+ */
+ private String getCurrentTextContent() {
+ if (lastKnownTextContent != null) {
+ return lastKnownTextContent;
+ } else {
+ Object text = getValue();
+ if (text == null) {
+ return getNullRepresentation();
+ }
+ return text.toString();
+ }
+ }
+
+ /**
+ * Selects all text in the field.
+ *
+ * @since 6.4
+ */
+ public void selectAll() {
+ String text = getValue() == null ? "" : getValue().toString();
+ setSelectionRange(0, text.length());
+ }
+
+ /**
+ * Sets the range of text to be selected.
+ *
+ * As a side effect the field will become focused.
+ *
+ * @since 6.4
+ *
+ * @param pos
+ * the position of the first character to be selected
+ * @param length
+ * the number of characters to be selected
+ */
+ public void setSelectionRange(int pos, int length) {
+ selectionPosition = pos;
+ selectionLength = length;
+ focus();
+ requestRepaint();
+ }
+
+ /**
+ * Sets the cursor position in the field. As a side effect the field will
+ * become focused.
+ *
+ * @since 6.4
+ *
+ * @param pos
+ * the position for the cursor
+ * */
+ public void setCursorPosition(int pos) {
+ setSelectionRange(pos, 0);
+ lastKnownCursorPosition = pos;
+ }
+
+ /**
+ * Returns the last known cursor position of the field.
+ *
+ * <p>
+ * Note that due to the client server nature or the GWT terminal, Vaadin
+ * cannot provide the exact value of the cursor position in most situations.
+ * The value is updated only when the client side terminal communicates to
+ * TextField, like on {@link ValueChangeEvent}s and {@link TextChangeEvent}
+ * s. This may change later if a deep push integration is built to Vaadin.
+ *
+ * @return the cursor position
+ */
+ public int getCursorPosition() {
+ return lastKnownCursorPosition;
+ }
+
public void addListener(FocusListener listener) {
addListener(FocusEvent.EVENT_ID, FocusEvent.class, listener,
FocusListener.focusMethod);
diff --git a/src/com/vaadin/ui/PasswordField.java b/src/com/vaadin/ui/PasswordField.java
index 0c9da78cd5..609108c62f 100644
--- a/src/com/vaadin/ui/PasswordField.java
+++ b/src/com/vaadin/ui/PasswordField.java
@@ -1,3 +1,6 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
package com.vaadin.ui;
import com.vaadin.data.Property;
@@ -5,27 +8,26 @@ import com.vaadin.terminal.gwt.client.ui.VPasswordField;
/**
* A field that is used to enter secret text information like passwords. The
- * clear text is not displayed in the screen.
+ * entered text is not displayed on the screen.
*/
@ClientWidget(VPasswordField.class)
-@SuppressWarnings("serial")
-public class PasswordField extends TextField {
+public class PasswordField extends AbstractTextField {
/**
* Constructs an empty PasswordField.
*/
public PasswordField() {
- super();
+ setValue("");
}
/**
* Constructs a PasswordField with given property data source.
*
* @param dataSource
- * the property dato source for the field
+ * the property data source for the field
*/
public PasswordField(Property dataSource) {
- super(dataSource);
+ setPropertyDataSource(dataSource);
}
/**
@@ -37,7 +39,8 @@ public class PasswordField extends TextField {
* the property data source for the field
*/
public PasswordField(String caption, Property dataSource) {
- super(caption, dataSource);
+ this(dataSource);
+ setCaption(caption);
}
/**
@@ -49,7 +52,8 @@ public class PasswordField extends TextField {
* the value for the field
*/
public PasswordField(String caption, String value) {
- super(caption, value);
+ setValue(value);
+ setCaption(caption);
}
/**
@@ -59,7 +63,7 @@ public class PasswordField extends TextField {
* the caption for the field
*/
public PasswordField(String caption) {
- super(caption);
+ this();
+ setCaption(caption);
}
-
}
diff --git a/src/com/vaadin/ui/TextArea.java b/src/com/vaadin/ui/TextArea.java
index 9665a7a98c..83cdf8f050 100644
--- a/src/com/vaadin/ui/TextArea.java
+++ b/src/com/vaadin/ui/TextArea.java
@@ -1,21 +1,34 @@
+/*
+@ITMillApache2LicenseForJavaFiles@
+ */
+
package com.vaadin.ui;
import com.vaadin.data.Property;
import com.vaadin.terminal.gwt.client.ui.VTextArea;
/**
- * A text field that supports multiline editing.
+ * A text field that supports multi line editing.
*/
@ClientWidget(VTextArea.class)
-public class TextArea extends TextField {
+public class TextArea extends AbstractTextField {
private static final int DEFAULT_ROWS = 5;
/**
+ * Number of visible rows in the text area.
+ */
+ private int rows = DEFAULT_ROWS;
+
+ /**
+ * Tells if word-wrapping should be used in the text area.
+ */
+ private boolean wordwrap = true;
+
+ /**
* Constructs an empty TextArea.
*/
public TextArea() {
- setRows(DEFAULT_ROWS);
}
/**
@@ -25,8 +38,8 @@ public class TextArea extends TextField {
* the caption for the field.
*/
public TextArea(String caption) {
- super(caption);
- setRows(DEFAULT_ROWS);
+ this();
+ setCaption(caption);
}
/**
@@ -36,8 +49,8 @@ public class TextArea extends TextField {
* the data source for the field
*/
public TextArea(Property dataSource) {
- super(dataSource);
- setRows(DEFAULT_ROWS);
+ this();
+ setPropertyDataSource(dataSource);
}
/**
@@ -46,11 +59,11 @@ public class TextArea extends TextField {
* @param caption
* the caption for the field
* @param dataSource
- * the dato source for the field
+ * the data source for the field
*/
public TextArea(String caption, Property dataSource) {
- super(caption, dataSource);
- setRows(DEFAULT_ROWS);
+ this(dataSource);
+ setCaption(caption);
}
/**
@@ -62,58 +75,60 @@ public class TextArea extends TextField {
* the value for the field
*/
public TextArea(String caption, String value) {
- super(caption, value);
- setRows(DEFAULT_ROWS);
+ this(caption);
+ setValue(value);
+
}
/**
- * Sets the number of rows in the editor.
+ * Sets the number of rows in the text area.
*
* @param rows
- * the number of rows for this editor.
+ * the number of rows for this text area.
*/
- @Override
public void setRows(int rows) {
- // TODO implement here once the API from TextField is removed
- super.setRows(rows);
+ if (rows < 0) {
+ rows = 0;
+ }
+ if (this.rows != rows) {
+ this.rows = rows;
+ requestRepaint();
+ }
}
/**
- * Gets the number of rows in the editor. If the number of rows is set to 0,
- * the actual number of displayed rows is determined implicitly by the
+ * Gets the number of rows in the text area. If the number of rows is set to
+ * 0, the actual number of displayed rows is determined implicitly by the
* adapter.
*
* @return number of explicitly set rows.
*/
- @Override
public int getRows() {
- // TODO implement here once the API from TextField is removed
- return super.getRows();
+ return rows;
}
/**
- * Sets the editor's word-wrap mode on or off.
+ * Sets the text area's word-wrap mode on or off.
*
* @param wordwrap
- * the boolean value specifying if the editor should be in
- * word-wrap mode after the call or not.
+ * the boolean value specifying if the text area should be in
+ * word-wrap mode.
*/
- @Override
public void setWordwrap(boolean wordwrap) {
- // TODO implement here once the API from TextField is removed
- super.setWordwrap(wordwrap);
+ if (this.wordwrap != wordwrap) {
+ this.wordwrap = wordwrap;
+ requestRepaint();
+ }
}
/**
- * Tests if the editor is in word-wrap mode.
+ * Tests if the text area is in word-wrap mode.
*
- * @return <code>true</code> if the component is in the word-wrap mode,
+ * @return <code>true</code> if the component is in word-wrap mode,
* <code>false</code> if not.
*/
- @Override
public boolean isWordwrap() {
- // TODO implement here once the API from TextField is removed
- return super.isWordwrap();
+ return wordwrap;
}
}
diff --git a/src/com/vaadin/ui/TextField.java b/src/com/vaadin/ui/TextField.java
index 2a3b20a117..67d9e005c8 100644
--- a/src/com/vaadin/ui/TextField.java
+++ b/src/com/vaadin/ui/TextField.java
@@ -4,12 +4,7 @@
package com.vaadin.ui;
-import java.util.Map;
-
import com.vaadin.data.Property;
-import com.vaadin.event.FieldEvents;
-import com.vaadin.event.FieldEvents.TextChangeEvent;
-import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.gwt.client.ui.VTextField;
@@ -37,61 +32,29 @@ import com.vaadin.ui.ClientWidget.LoadStyle;
*/
@SuppressWarnings("serial")
@ClientWidget(value = VTextField.class, loadStyle = LoadStyle.EAGER)
-public class TextField extends AbstractTextField implements
- FieldEvents.BlurNotifier, FieldEvents.FocusNotifier,
- FieldEvents.TextChangeNotifier {
+public class TextField extends AbstractTextField {
/**
* Tells if input is used to enter sensitive information that is not echoed
* to display. Typically passwords.
*/
+ @Deprecated
private boolean secret = false;
/**
* Number of visible rows in a multiline TextField. Value 0 implies a
* single-line text-editor.
*/
+ @Deprecated
private int rows = 0;
/**
* Tells if word-wrapping should be used in multiline mode.
*/
+ @Deprecated
private boolean wordwrap = true;
/**
- * Number of visible columns in the TextField.
- */
- private int columns = 0;
-
- private String inputPrompt = null;
-
- private int selectionPosition = -1;
- private int selectionLength;
-
- private int lastKnownCursorPosition;
-
- private String lastKnownTextContent;
-
- /**
- * Flag indicating that a text change event is pending to be triggered.
- * Cleared by {@link #setInternalValue(Object)} and when the event is fired.
- */
- private boolean textChangeEventPending;
-
- /**
- * Flag used to determine wheter we are currently handling a state change
- * triggered by a user. Used to properly fire text change event before value
- * change event triggered by the client side.
- */
- private boolean changingVariables;
-
- private TextChangeEventMode textChangeEventMode = TextChangeEventMode.LAZY;
-
- private final int DEFAULT_TEXTCHANGE_TIMEOUT = 400;
-
- private int textChangeEventTimeout = DEFAULT_TEXTCHANGE_TIMEOUT;
-
- /**
* Constructs an empty <code>TextField</code> with no caption.
*/
public TextField() {
@@ -152,13 +115,13 @@ public class TextField extends AbstractTextField implements
}
/**
- * Gets the secret property on and off. If a field is used to enter
- * secretinformation the information is not echoed to display.
+ * Gets the secret property. If a field is used to enter secret information
+ * the information is not echoed to display.
*
* @return <code>true</code> if the field is used to enter secret
* information, <code>false</code> otherwise.
*
- * @deprecated in 6.5 use {@link PasswordField} instead
+ * @deprecated Starting from 6.5 use {@link PasswordField} instead
*/
@Deprecated
public boolean isSecret() {
@@ -166,13 +129,13 @@ public class TextField extends AbstractTextField implements
}
/**
- * Sets the secret property on and off. If a field is used to enter
- * secretinformation the information is not echoed to display.
+ * Sets the secret property on and off. If a field is used to enter secret
+ * information the information is not echoed to display.
*
* @param secret
* the value specifying if the field is used to enter secret
* information.
- * @deprecated in 6.5 use {@link PasswordField} instead
+ * @deprecated Starting from 6.5 use {@link PasswordField} instead
*/
@Deprecated
public void setSecret(boolean secret) {
@@ -187,11 +150,7 @@ public class TextField extends AbstractTextField implements
if (isSecret()) {
target.addAttribute("secret", true);
}
- // Adds the number of column and rows
- final int columns = getColumns();
- if (columns != 0) {
- target.addAttribute("cols", String.valueOf(columns));
- }
+
final int rows = getRows();
if (rows != 0) {
target.addAttribute("rows", String.valueOf(rows));
@@ -203,22 +162,6 @@ public class TextField extends AbstractTextField implements
}
}
- if (getInputPrompt() != null) {
- target.addAttribute("prompt", getInputPrompt());
- }
-
- if (selectionPosition != -1) {
- target.addAttribute("selpos", selectionPosition);
- target.addAttribute("sellen", selectionLength);
- selectionPosition = -1;
- }
- if (hasListeners(TextChangeEvent.class)) {
- target.addAttribute(VTextField.ATTR_TEXTCHANGE_EVENTMODE,
- getTextChangeEventMode().toString());
- target.addAttribute(VTextField.ATTR_TEXTCHANGE_TIMEOUT,
- getTextChangeTimeout());
- }
-
super.paintContent(target);
}
@@ -294,326 +237,58 @@ public class TextField extends AbstractTextField implements
}
/**
- * Gets the number of columns in the editor. If the number of columns is set
- * 0, the actual number of displayed columns is determined implicitly by the
- * adapter.
- *
- * @return the number of columns in the editor.
- */
- public int getColumns() {
- return columns;
- }
-
- /**
- * Sets the number of columns in the editor. If the number of columns is set
- * 0, the actual number of displayed columns is determined implicitly by the
- * adapter.
- *
- * @param columns
- * the number of columns to set.
- */
- public void setColumns(int columns) {
- if (columns < 0) {
- columns = 0;
- }
- this.columns = columns;
- requestRepaint();
- }
-
- /**
- * Gets the current input prompt.
- *
- * @see #setInputPrompt(String)
- * @return the current input prompt, or null if not enabled
- */
- public String getInputPrompt() {
- return inputPrompt;
- }
-
- /**
- * Sets the input prompt - a textual prompt that is displayed when the field
- * would otherwise be empty, to prompt the user for input.
- *
- * @param inputPrompt
- */
- public void setInputPrompt(String inputPrompt) {
- this.inputPrompt = inputPrompt;
- requestRepaint();
- }
-
- /**
- * Selects all text in the field.
- *
- * @since 6.4
- */
- public void selectAll() {
- String text = getValue() == null ? "" : getValue().toString();
- setSelectionRange(0, text.length());
- }
-
- /**
- * Sets the range of text to be selected.
- *
- * As a side effect the field will become focused.
- *
- * @since 6.4
- *
- * @param pos
- * the position of the first character to be selected
- * @param length
- * the number of characters to be selected
- */
- public void setSelectionRange(int pos, int length) {
- selectionPosition = pos;
- selectionLength = length;
- focus();
- requestRepaint();
- }
-
- /**
- * Sets the cursor position in the field. As a side effect the field will
- * become focused.
- *
- * @since 6.4
- *
- * @param pos
- * the position for the cursor
- * */
- public void setCursorPosition(int pos) {
- setSelectionRange(pos, 0);
- lastKnownCursorPosition = pos;
- }
-
- /**
- * Returns the last known cursor position of the field.
+ * Sets the height of the {@link TextField} instance.
*
* <p>
- * Note that due to the client server nature or the GWT terminal, Vaadin
- * cannot provide the exact value of the cursor position in most situations.
- * The value is updated only when the client side terminal communicates to
- * TextField, like on {@link ValueChangeEvent}s and {@link TextChangeEvent}
- * s. This may change later if a deep push integration is built to Vaadin.
- *
- * @return the cursor position
- */
- public int getCursorPosition() {
- return lastKnownCursorPosition;
- }
-
- /**
- * Gets the current (or the last known) text content in the field.
+ * Setting height for {@link TextField} also has a side-effect that puts
+ * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
+ * can also be achieved by calling {@link #setRows(int)}. The height value
+ * overrides the number of rows set by {@link #setRows(int)}.
* <p>
- * Note the text returned by this method is not necessary the same what is
- * returned by the {@link #getValue()} method. The value is updated when the
- * terminal fires a value change event via e.g. blurring the field or by
- * pressing enter. The value returned by this method is updated also on
- * {@link TextChangeEvent}s. Due to this high dependency to the terminal
- * implementation this method is (at least at this point) not published.
+ * If you want to set height of single line {@link TextField}, call
+ * {@link #setRows(int)} with value 0 after setting the height. Setting rows
+ * to 0 resets the side-effect.
+ * <p>
+ * Starting from 6.5 you should use {@link TextArea} instead of
+ * {@link TextField} for multiline text input.
+ *
*
- * @return the text which is currently displayed in the field.
+ * @see com.vaadin.ui.AbstractComponent#setHeight(float, int)
*/
- private String getCurrentTextContent() {
- if (lastKnownTextContent != null) {
- return lastKnownTextContent;
- } else {
- Object text = getValue();
- if (text == null) {
- return getNullRepresentation();
- }
- return text.toString();
- }
- }
-
- @Override
- public void changeVariables(Object source, Map<String, Object> variables) {
- if (variables.containsKey(VTextField.VAR_CURSOR)) {
- Integer object = (Integer) variables.get(VTextField.VAR_CURSOR);
- lastKnownCursorPosition = object.intValue();
- }
- if (variables.containsKey(VTextField.VAR_CUR_TEXT)) {
- /*
- * NOTE, we might want to develop this further so that on a value
- * change event the whole text content don't need to be sent from
- * the client to server. Just "commit" the value from currentText to
- * the value.
- */
- textChangeEventPending = true;
- handleInputEventTextChange(variables);
- }
-
- changingVariables = true;
- try {
- super.changeVariables(source, variables);
- } finally {
- changingVariables = false;
- }
- firePendingTextChangeEvent();
- }
-
- private void firePendingTextChangeEvent() {
- if (textChangeEventPending) {
- fireEvent(new TextChangeEventImpl(this));
- textChangeEventPending = false;
- }
- }
-
@Override
- protected void setInternalValue(Object newValue) {
- if (changingVariables) {
+ public void setHeight(float height, int unit) {
+ super.setHeight(height, unit);
+ if (height > 1 && getClass() == TextField.class) {
/*
- * Fire text change event before value change event if change is
- * coming from the client side.
+ * In html based terminals we most commonly want to make component
+ * to be textarea if height is defined. Setting row field above 0
+ * will render component as textarea.
*/
- if (newValue == null && lastKnownTextContent != null
- && !lastKnownTextContent.equals(getNullRepresentation())) {
- // Value was changed from something to null representation
- lastKnownTextContent = getNullRepresentation();
- textChangeEventPending = true;
- } else if (newValue != null
- && !newValue.toString().equals(lastKnownTextContent)) {
- // Value was changed to something else than null representation
- lastKnownTextContent = newValue.toString();
- textChangeEventPending = true;
- }
- if (textChangeEventPending) {
- firePendingTextChangeEvent();
- }
+ setRows(2);
}
- super.setInternalValue(newValue);
}
- private void handleInputEventTextChange(Map<String, Object> variables) {
- /*
- * TODO we could vastly optimize the communication of values by using
- * some sort of diffs instead of always sending the whole text content.
- * Also on value change events we could use the mechanism.
- */
- String object = (String) variables.get(VTextField.VAR_CUR_TEXT);
- lastKnownTextContent = object;
- textChangeEventPending = true;
- }
-
- /* ** Text Change Events ** */
-
/**
- * Sets the mode how the TextField triggers {@link TextChangeEvent}s.
+ * Sets the height of the {@link TextField} instance.
*
- * @param inputEventMode
- * the new mode
- *
- * @see TextChangeEventMode
- */
- public void setTextChangeEventMode(TextChangeEventMode inputEventMode) {
- textChangeEventMode = inputEventMode;
- requestRepaint();
- }
-
- /**
- * @return the mode used to trigger {@link TextChangeEvent}s.
- */
- public TextChangeEventMode getTextChangeEventMode() {
- return textChangeEventMode;
- }
-
- /**
- * Different modes how the TextField can trigger {@link TextChangeEvent}s.
- */
- public enum TextChangeEventMode {
-
- /**
- * An event is triggered on each text content change, most commonly key
- * press events.
- */
- EAGER,
- /**
- * Each text change event in the UI causes the event to be communicated
- * to the application after a timeout. The length of the timeout can be
- * controlled with {@link TextField#setInputEventTimeout(int)}. Only the
- * last input event is reported to the server side if several text
- * change events happen during the timeout.
- * <p>
- * In case of a {@link ValueChangeEvent} the schedule is not kept
- * strictly. Before a {@link ValueChangeEvent} a {@link TextChangeEvent}
- * is triggered if the text content has changed since the previous
- * TextChangeEvent regardless of the schedule.
- */
- TIMEOUT,
- /**
- * An event is triggered when there is a pause of text modifications.
- * The length of the pause can be modified with
- * {@link TextField#setInputEventTimeout(int)}. Like with the
- * {@link #TIMEOUT} mode, an event is forced before
- * {@link ValueChangeEvent}s, even if the user did not keep a pause
- * while entering the text.
- * <p>
- * This is the default mode.
- */
- LAZY
- }
-
- public void addListener(TextChangeListener listener) {
- addListener(TextChangeListener.EVENT_ID, TextChangeEvent.class,
- listener, TextChangeListener.EVENT_METHOD);
- }
-
- public void removeListener(TextChangeListener listener) {
- removeListener(TextChangeListener.EVENT_ID, TextChangeEvent.class,
- listener);
- }
-
- /**
- * The text change timeout modifies how often text change events are
- * communicated to the application when {@link #getTextChangeEventMode()} is
- * {@link TextChangeEventMode#LAZY} or {@link TextChangeEventMode#TIMEOUT}.
- *
- *
- * @see #getTextChangeEventMode()
- *
- * @param timeout
- * the timeout in milliseconds
- */
- public void setTextChangeTimeout(int timeout) {
- textChangeEventTimeout = timeout;
- requestRepaint();
- }
-
- /**
- * Gets the timeout used to fire {@link TextChangeEvent}s when the
- * {@link #getTextChangeEventMode()} is {@link TextChangeEventMode#LAZY} or
- * {@link TextChangeEventMode#TIMEOUT}.
+ * <p>
+ * Setting height for {@link TextField} also has a side-effect that puts
+ * {@link TextField} into multiline mode (aka "textarea"). Multiline mode
+ * can also be achieved by calling {@link #setRows(int)}. The height value
+ * overrides the number of rows set by {@link #setRows(int)}.
+ * <p>
+ * If you want to set height of single line {@link TextField}, call
+ * {@link #setRows(int)} with value 0 after setting the height. Setting rows
+ * to 0 resets the side-effect.
*
- * @return the timeout value in milliseconds
+ * @see com.vaadin.ui.AbstractComponent#setHeight(java.lang.String)
*/
- public int getTextChangeTimeout() {
- return textChangeEventTimeout;
- }
-
- public class TextChangeEventImpl extends TextChangeEvent {
- private String curText;
- private int cursorPosition;
-
- private TextChangeEventImpl(final TextField tf) {
- super(tf);
- curText = tf.getCurrentTextContent();
- cursorPosition = tf.getCursorPosition();
- }
-
- @Override
- public TextField getComponent() {
- return (TextField) super.getComponent();
- }
-
- @Override
- public String getText() {
- return curText;
- }
-
- @Override
- public int getCursorPosition() {
- return cursorPosition;
- }
-
+ @Override
+ public void setHeight(String height) {
+ // will call setHeight(float, int) the actually does the magic. Method
+ // is overridden just to document side-effects.
+ super.setHeight(height);
}
}
diff --git a/tests/src/com/vaadin/tests/components/textarea/TextAreaTest.java b/tests/src/com/vaadin/tests/components/textarea/TextAreaTest.java
index 34ed567b78..1977067a19 100644
--- a/tests/src/com/vaadin/tests/components/textarea/TextAreaTest.java
+++ b/tests/src/com/vaadin/tests/components/textarea/TextAreaTest.java
@@ -7,8 +7,8 @@ import java.util.List;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.tests.components.abstractfield.AbstractTextFieldTest;
+import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.TextArea;
-import com.vaadin.ui.TextField.TextChangeEventMode;
public class TextAreaTest extends AbstractTextFieldTest<TextArea> implements
TextChangeListener {
diff --git a/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents.java b/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents.java
index 4317000812..f754beb792 100644
--- a/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents.java
+++ b/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents.java
@@ -5,9 +5,9 @@ import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.tests.components.TestBase;
import com.vaadin.tests.util.Log;
import com.vaadin.tests.util.TestUtils;
+import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.TextArea;
import com.vaadin.ui.TextField;
-import com.vaadin.ui.TextField.TextChangeEventMode;
public class TextChangeEvents extends TestBase {
Log l = new Log(10);
@@ -22,9 +22,8 @@ public class TextChangeEvents extends TestBase {
public void textChange(TextChangeEvent event) {
l.log("Text change event for "
+ event.getComponent().getCaption()
- + ", text content currently:'"
- + event.getText() + "' Cursor at index:"
- + event.getCursorPosition());
+ + ", text content currently:'" + event.getText()
+ + "' Cursor at index:" + event.getCursorPosition());
}
};
@@ -47,7 +46,7 @@ public class TextChangeEvents extends TestBase {
ta.addListener(inputEventListener);
getLayout().addComponent(ta);
- VaadinDeveloeprNameField vd = new VaadinDeveloeprNameField();
+ VaadinDeveloperNameField vd = new VaadinDeveloperNameField();
vd.addListener(inputEventListener);
getLayout().addComponent(vd);
@@ -73,13 +72,13 @@ public class TextChangeEvents extends TestBase {
* 2010-10
*
*/
- private class VaadinDeveloeprNameField extends TextField implements
+ private class VaadinDeveloperNameField extends TextField implements
TextChangeListener {
private String[] names = new String[] { "Matti Tahvonen",
"Marc Englund", "Joonas Lehtinen", "Jouni Koivuviita",
"Marko Grönroos", "Artur Signell" };
- public VaadinDeveloeprNameField() {
+ public VaadinDeveloperNameField() {
setCaption("Start typing 'old' Vaadin developers.");
addListener((TextChangeListener) this);
setStyleName("nomatch");
diff --git a/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents2.java b/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents2.java
index 523d8f4057..b40ebb2434 100644
--- a/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents2.java
+++ b/tests/src/com/vaadin/tests/components/textfield/TextChangeEvents2.java
@@ -9,10 +9,10 @@ import com.vaadin.event.FieldEvents.FocusListener;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.tests.components.TestBase;
+import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.TextField;
-import com.vaadin.ui.TextField.TextChangeEventMode;
public class TextChangeEvents2 extends TestBase {
@Override
diff --git a/tests/src/com/vaadin/tests/components/textfield/TextFieldTest.java b/tests/src/com/vaadin/tests/components/textfield/TextFieldTest.java
index 1b1041f053..5937993e83 100644
--- a/tests/src/com/vaadin/tests/components/textfield/TextFieldTest.java
+++ b/tests/src/com/vaadin/tests/components/textfield/TextFieldTest.java
@@ -7,11 +7,11 @@ import java.util.List;
import com.vaadin.event.FieldEvents.TextChangeEvent;
import com.vaadin.event.FieldEvents.TextChangeListener;
import com.vaadin.tests.components.abstractfield.AbstractTextFieldTest;
+import com.vaadin.ui.AbstractTextField.TextChangeEventMode;
import com.vaadin.ui.TextField;
-import com.vaadin.ui.TextField.TextChangeEventMode;
-public class TextFieldTest extends AbstractTextFieldTest<TextField>
- implements TextChangeListener {
+public class TextFieldTest extends AbstractTextFieldTest<TextField> implements
+ TextChangeListener {
private Command<TextField, Boolean> secretCommand = new Command<TextField, Boolean>() {
@SuppressWarnings("deprecation")