001: /* *************************************************************************
002:
003: Millstone(TM)
004: Open Sourced User Interface Library for
005: Internet Development with Java
006:
007: Millstone is a registered trademark of IT Mill Ltd
008: Copyright (C) 2000-2005 IT Mill Ltd
009:
010: *************************************************************************
011:
012: This library is free software; you can redistribute it and/or
013: modify it under the terms of the GNU Lesser General Public
014: license version 2.1 as published by the Free Software Foundation.
015:
016: This library is distributed in the hope that it will be useful,
017: but WITHOUT ANY WARRANTY; without even the implied warranty of
018: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
019: Lesser General Public License for more details.
020:
021: You should have received a copy of the GNU Lesser General Public
022: License along with this library; if not, write to the Free Software
023: Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
024:
025: *************************************************************************
026:
027: For more information, contact:
028:
029: IT Mill Ltd phone: +358 2 4802 7180
030: Ruukinkatu 2-4 fax: +358 2 4802 7181
031: 20540, Turku email: info@itmill.com
032: Finland company www: www.itmill.com
033:
034: Primary source for MillStone information and releases: www.millstone.org
035:
036: ********************************************************************** */
037:
038: package org.millstone.base.ui;
039:
040: import java.text.Format;
041: import java.util.Map;
042:
043: import org.millstone.base.data.Property;
044: import org.millstone.base.terminal.PaintException;
045: import org.millstone.base.terminal.PaintTarget;
046:
047: /** <p>A text editor component that can be bound to any bindable Property.
048: * The text editor supports both multiline and single line modes, default
049: * is one-line mode.</p>
050: *
051: * <p>Since <code>TextField</code> extends <code>AbstractField</code> it
052: * implements the {@link org.millstone.base.data.Buffered} interface. A
053: * <code>TextField</code> is in write-through mode by default, so
054: * {@link org.millstone.base.ui.AbstractField#setWriteThrough(boolean)}
055: * must be called to enable buffering.</p>
056: *
057: * @author IT Mill Ltd.
058: * @version 3.1.1
059: * @since 3.0
060: */
061: public class TextField extends AbstractField {
062:
063: /* Private members ************************************************* */
064:
065: /** Value formatter used to format the string contents*/
066: private Format format;
067:
068: /** Number of visible columns in the TextField. */
069: private int columns = 0;
070:
071: /** Number of visible rows in a multiline TextField. Value 0 implies a
072: * single-line text-editor.
073: */
074: private int rows = 0;
075:
076: /** Tells if word-wrapping should be used in multiline mode. */
077: private boolean wordwrap = true;
078:
079: /** Tells if input is used to enter sensitive information that is
080: * not echoed to display. Typically passwords.
081: */
082: private boolean secret = false;
083:
084: /** Null representation. */
085: private String nullRepresentation = "null";
086:
087: /** Is setting to null from non-null value allowed by setting with
088: * null representation */
089: private boolean nullSettingAllowed = false;
090:
091: /* Constructors **************************************************** */
092:
093: /** Constructs an empty <code>TextField</code> with no caption. */
094: public TextField() {
095: setValue("");
096: }
097:
098: /** Constructs an empty <code>TextField</code> with given caption. */
099: public TextField(String caption) {
100: setValue("");
101: setCaption(caption);
102: }
103:
104: /** Constructs a new <code>TextField</code> that's bound to the
105: * specified <code>Property</code> and has no caption.
106: *
107: * @param dataSource the Property to be edited with this editor
108: */
109: public TextField(Property dataSource) {
110: setPropertyDataSource(dataSource);
111: }
112:
113: /** Constructs a new <code>TextField</code> that's bound to the
114: * specified <code>Property</code> and has the given caption
115: * <code>String</code>.
116: *
117: * @param caption caption <code>String</code> for the editor
118: * @param dataSource the Property to be edited with this editor
119: */
120: public TextField(String caption, Property dataSource) {
121: this (dataSource);
122: setCaption(caption);
123: }
124:
125: /** Constructs a new <code>TextField</code> with the given caption and
126: * initial text contents. The editor constructed this way will not be
127: * bound to a Property unless
128: * {@link org.millstone.base.data.Property.Viewer#setPropertyDataSource(Property)}
129: * is called to bind it.
130: *
131: * @param caption caption <code>String</code> for the editor
132: * @param text initial text content of the editor
133: */
134: public TextField(String caption, String value) {
135: setValue(value);
136: setCaption(caption);
137: }
138:
139: /* Component basic features ********************************************* */
140:
141: /* Paint this component.
142: * Don't add a JavaDoc comment here, we use the default documentation
143: * from implemented interface.
144: */
145: public void paintContent(PaintTarget target) throws PaintException {
146: super .paintContent(target);
147:
148: // Set secret attribute
149: if (this .isSecret())
150: target.addAttribute("secret", true);
151:
152: // Add the number of column and rows
153: int c = getColumns();
154: int r = getRows();
155: if (c != 0)
156: target.addAttribute("cols", String.valueOf(c));
157: if (r != 0) {
158: target.addAttribute("rows", String.valueOf(r));
159: target.addAttribute("multiline", true);
160: if (!wordwrap)
161: target.addAttribute("wordwrap", false);
162: }
163:
164: // Add content as variable
165: String value = getFormattedValue();
166: if (value == null)
167: value = getNullRepresentation();
168: if (value == null)
169: throw new IllegalStateException(
170: "Null values are not allowed if the null-representation is null");
171: target.addVariable(this , "text", value);
172: }
173:
174: /** Get the formatted dtring value.
175: * Sets the field value by using the assigned Format.
176: * @param value to be formatted
177: * @return Formatted value
178: * @see #setFormat(Format)
179: * @see Format
180: */
181: protected String getFormattedValue() {
182: Object value = getValue();
183: if (this .format != null && value != null)
184: try {
185: return this .format.format(value);
186: } catch (IllegalArgumentException ignored) {
187: // Ignored exception
188: }
189: if (value != null)
190: return value.toString();
191: return null;
192: }
193:
194: /* Gets the components UIDL tag string.
195: * Don't add a JavaDoc comment here, we use the default documentation
196: * from implemented interface.
197: */
198: public String getTag() {
199: return "textfield";
200: }
201:
202: /* Invoked when a variable of the component changes.
203: * Don't add a JavaDoc comment here, we use the default documentation
204: * from implemented interface.
205: */
206: public void changeVariables(Object source, Map variables) {
207:
208: // Set the text
209: if (variables.containsKey("text") && !isReadOnly()) {
210:
211: // Only do the setting if the string representation of the value
212: // has been updated
213: String newValue = (String) variables.get("text");
214: String oldValue = getFormattedValue();
215: if (newValue != null
216: && (oldValue == null || isNullSettingAllowed())
217: && newValue.equals(getNullRepresentation()))
218: newValue = null;
219: if (newValue != oldValue
220: && (newValue == null || !newValue.equals(oldValue)))
221: setValue(newValue);
222: }
223:
224: }
225:
226: /* Text field configuration ********************************************* */
227:
228: /** Gets the number of columns in the editor. If the number of columns
229: * is set 0, the actual number of displayed columns is determined
230: * implicitly by the adapter.
231: *
232: * @param the number of columns for this editor
233: */
234: public int getColumns() {
235: return this .columns;
236: }
237:
238: /** Sets the number of columns in the editor. If the number of columns
239: * is set 0, the actual number of displayed columns is determined
240: * implicitly by the adapter.
241: *
242: * @return number of explicitly set columns
243: */
244: public void setColumns(int columns) {
245: if (columns < 0)
246: columns = 0;
247: this .columns = columns;
248: requestRepaint();
249: }
250:
251: /** Gets the number of rows in the editor. If the number of rows is set
252: * to 0, the actual number of displayed rows is determined implicitly by
253: * the adapter.
254: *
255: * @return number of explicitly set rows
256: */
257: public int getRows() {
258: return this .rows;
259: }
260:
261: /** Sets the number of rows in the editor. If the number of rows is set
262: * to 0, the actual number of displayed rows is determined implicitly by
263: * the adapter.
264: *
265: * @param the number of rows for this editor
266: */
267: public void setRows(int rows) {
268: if (rows < 0)
269: rows = 0;
270: this .rows = rows;
271: requestRepaint();
272: }
273:
274: /** Tests if the editor is in word-wrap mode.
275: *
276: * @return <code>true</code> if the component is in the word-wrap mode,
277: * <code>false</code> if not
278: */
279: public boolean isWordwrap() {
280: return this .wordwrap;
281: }
282:
283: /** Sets the editor's word-wrap mode on or off.
284: *
285: * @param wordwrap boolean value specifying if the editor should be in
286: * word-wrap mode after the call or not.
287: */
288: public void setWordwrap(boolean wordwrap) {
289: this .wordwrap = wordwrap;
290: }
291:
292: /* Property features **************************************************** */
293:
294: /* Gets the edited property's type.
295: * Don't add a JavaDoc comment here, we use the default documentation
296: * from implemented interface.
297: */
298: public Class getType() {
299: return String.class;
300: }
301:
302: /** Get the secret property on and off.
303: * If a field is used to enter secretinformation
304: * the information is not echoed to display.
305: * @return true if the field is used to enter secret information, false otherwise.
306: */
307: public boolean isSecret() {
308: return secret;
309: }
310:
311: /** Set the secret property on and off.
312: * If a field is used to enter secretinformation
313: * the information is not echoed to display.
314: * @param secret value specifying if the field is used to enter secret information.
315: */
316: public void setSecret(boolean secret) {
317: this .secret = secret;
318: }
319:
320: /** Get the null-string representation.
321: *
322: * <p>The null-valued strings are represented on the user interface by replacing the
323: * null value with this string. If the null representation is set null (not 'null' string),
324: * painting null value throws exception.</p>
325: *
326: * <p>The default value is string 'null'</p>
327: *
328: * @see TextField#isNullSettingAllowed()
329: * @return String Textual representation for null strings.
330: */
331: public String getNullRepresentation() {
332: return nullRepresentation;
333: }
334:
335: /** Is setting nulls with null-string representation allowed.
336: *
337: * <p>If this property is true, writing null-representation string to text
338: * field allways sets the field value to real null. If this property is
339: * false, null setting is not made, but the null values are maintained.
340: * Maintenance of null-values is made by only converting the textfield
341: * contents to real null, if the text field matches the null-string
342: * representation and the current value of the field is null.</p>
343: *
344: * <p>By default this setting is false</p>
345: *
346: * @return boolean Should the null-string represenation be allways
347: * converted to null-values.
348: * @see TextField#getNullRepresentation()
349: */
350: public boolean isNullSettingAllowed() {
351: return nullSettingAllowed;
352: }
353:
354: /** Sets the null-string representation.
355: *
356: * <p>The null-valued strings are represented on the user interface by replacing the
357: * null value with this string. If the null representation is set null (not 'null' string),
358: * painting null value throws exception.</p>
359: *
360: * <p>The default value is string 'null'</p>
361: *
362: * @see TextField#setNullSettingAllowed(boolean)
363: * @param nullRepresentation Textual representation for null strings.
364: */
365: public void setNullRepresentation(String nullRepresentation) {
366: this .nullRepresentation = nullRepresentation;
367: }
368:
369: /** Set the null conversion mode.
370: *
371: * <p>If this property is true, writing null-representation string to text
372: * field allways sets the field value to real null. If this property is
373: * false, null setting is not made, but the null values are maintained.
374: * Maintenance of null-values is made by only converting the textfield
375: * contents to real null, if the text field matches the null-string
376: * representation and the current value of the field is null.</p>
377: *
378: * <p>By default this setting is false</p>
379: *
380: * @param nullSettingAllowed Should the null-string represenation be allways
381: * converted to null-values.
382: * @see TextField#getNullRepresentation()
383: */
384: public void setNullSettingAllowed(boolean nullSettingAllowed) {
385: this .nullSettingAllowed = nullSettingAllowed;
386: }
387:
388: /** Get the value formatter of TextField.
389: *
390: *
391: * @return The Format used to format the value.
392: */
393: public Format getFormat() {
394: return format;
395: }
396:
397: /** Get the value formatter of TextField.
398: *
399: * @param The Format used to format the value. Null disables the formatting.
400: */
401: public void setFormat(Format format) {
402: this.format = format;
403: }
404:
405: }
|