001: /*
002: * This file is part of the Echo Web Application Framework (hereinafter "Echo").
003: * Copyright (C) 2002-2005 NextApp, Inc.
004: *
005: * Version: MPL 1.1/GPL 2.0/LGPL 2.1
006: *
007: * The contents of this file are subject to the Mozilla Public License Version
008: * 1.1 (the "License"); you may not use this file except in compliance with
009: * the License. You may obtain a copy of the License at
010: * http://www.mozilla.org/MPL/
011: *
012: * Software distributed under the License is distributed on an "AS IS" basis,
013: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
014: * for the specific language governing rights and limitations under the
015: * License.
016: *
017: * Alternatively, the contents of this file may be used under the terms of
018: * either the GNU General Public License Version 2 or later (the "GPL"), or
019: * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
020: * in which case the provisions of the GPL or the LGPL are applicable instead
021: * of those above. If you wish to allow use of your version of this file only
022: * under the terms of either the GPL or the LGPL, and not to allow others to
023: * use your version of this file under the terms of the MPL, indicate your
024: * decision by deleting the provisions above and replace them with the notice
025: * and other provisions required by the GPL or the LGPL. If you do not delete
026: * the provisions above, a recipient may use your version of this file under
027: * the terms of any one of the MPL, the GPL or the LGPL.
028: */
029:
030: package nextapp.echo2.app.text;
031:
032: import java.util.EventListener;
033:
034: import nextapp.echo2.app.Alignment;
035: import nextapp.echo2.app.Color;
036: import nextapp.echo2.app.FillImage;
037: import nextapp.echo2.app.Border;
038: import nextapp.echo2.app.Component;
039: import nextapp.echo2.app.Extent;
040: import nextapp.echo2.app.Font;
041: import nextapp.echo2.app.Insets;
042: import nextapp.echo2.app.event.ActionEvent;
043: import nextapp.echo2.app.event.ActionListener;
044: import nextapp.echo2.app.event.DocumentEvent;
045: import nextapp.echo2.app.event.DocumentListener;
046:
047: /**
048: * Abstract base class for text-entry components.
049: */
050: public abstract class TextComponent extends Component {
051:
052: public static final String INPUT_ACTION = "action";
053:
054: public static final String PROPERTY_ACTION_COMMAND = "actionCommand";
055: public static final String PROPERTY_ALIGNMENT = "alignment";
056: public static final String PROPERTY_BACKGROUND_IMAGE = "backgroundImage";
057: public static final String PROPERTY_BORDER = "border";
058: public static final String PROPERTY_DISABLED_BACKGROUND = "disabledBackground";
059: public static final String PROPERTY_DISABLED_BACKGROUND_IMAGE = "disabledBackgroundImage";
060: public static final String PROPERTY_DISABLED_BORDER = "disabledBorder";
061: public static final String PROPERTY_DISABLED_FONT = "disabledFont";
062: public static final String PROPERTY_DISABLED_FOREGROUND = "disabledForeground";
063: public static final String PROPERTY_HEIGHT = "height";
064: public static final String PROPERTY_HORIZONTAL_SCROLL = "horizontalScroll";
065: public static final String PROPERTY_INSETS = "insets";
066: public static final String PROPERTY_MAXIMUM_LENGTH = "maximumLength";
067: public static final String PROPERTY_TOOL_TIP_TEXT = "toolTipText";
068: public static final String PROPERTY_VERTICAL_SCROLL = "verticalScroll";
069: public static final String PROPERTY_WIDTH = "width";
070:
071: public static final String ACTION_LISTENERS_CHANGED_PROPERTY = "actionListeners";
072: public static final String DOCUMENT_CHANGED_PROPERTY = "document";
073: public static final String TEXT_CHANGED_PROPERTY = "text";
074:
075: private Document document;
076:
077: /**
078: * Local listener to monitor changes to document.
079: */
080: private DocumentListener documentListener = new DocumentListener() {
081:
082: /**
083: * @see nextapp.echo2.app.event.DocumentListener#documentUpdate(nextapp.echo2.app.event.DocumentEvent)
084: */
085: public void documentUpdate(DocumentEvent e) {
086: firePropertyChange(TEXT_CHANGED_PROPERTY, null,
087: ((Document) e.getSource()).getText());
088: }
089: };
090:
091: /**
092: * Creates a new <code>TextComponent</code> with the specified
093: * <code>Document</code> as its model.
094: *
095: * @param document the desired model
096: */
097: public TextComponent(Document document) {
098: super ();
099: setDocument(document);
100: }
101:
102: /**
103: * Adds an <code>ActionListener</code> to the <code>TextField</code>.
104: * The <code>ActionListener</code> will be invoked when the user
105: * presses the ENTER key in the field.
106: *
107: * @param l the <code>ActionListener</code> to add
108: */
109: public void addActionListener(ActionListener l) {
110: getEventListenerList().addListener(ActionListener.class, l);
111: // Notification of action listener changes is provided due to
112: // existence of hasActionListeners() method.
113: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, null, l);
114: }
115:
116: /**
117: * Fires an action event to all listeners.
118: */
119: private void fireActionEvent() {
120: if (!hasEventListenerList()) {
121: return;
122: }
123: EventListener[] listeners = getEventListenerList()
124: .getListeners(ActionListener.class);
125: ActionEvent e = null;
126: for (int i = 0; i < listeners.length; ++i) {
127: if (e == null) {
128: e = new ActionEvent(
129: this ,
130: (String) getRenderProperty(PROPERTY_ACTION_COMMAND));
131: }
132: ((ActionListener) listeners[i]).actionPerformed(e);
133: }
134: }
135:
136: /**
137: * Returns the action command which will be provided in
138: * <code>ActionEvent</code>s fired by this <code>TextField</code>.
139: *
140: * @return the action command
141: */
142: public String getActionCommand() {
143: return (String) getProperty(PROPERTY_ACTION_COMMAND);
144: }
145:
146: /**
147: * Returns the alignment of the text component.
148: *
149: * @return the alignment
150: */
151: public Alignment getAlignment() {
152: return (Alignment) getProperty(PROPERTY_ALIGNMENT);
153: }
154:
155: /**
156: * Returns the default background image of the text component.
157: *
158: * @return the background image
159: */
160: public FillImage getBackgroundImage() {
161: return (FillImage) getProperty(PROPERTY_BACKGROUND_IMAGE);
162: }
163:
164: /**
165: * Returns the border of the text component.
166: *
167: * @return the border
168: */
169: public Border getBorder() {
170: return (Border) getProperty(PROPERTY_BORDER);
171: }
172:
173: /**
174: * Returns the background color displayed when the text component is
175: * disabled.
176: *
177: * @return the color
178: */
179: public Color getDisabledBackground() {
180: return (Color) getProperty(PROPERTY_DISABLED_BACKGROUND);
181: }
182:
183: /**
184: * Returns the background image displayed when the text component is
185: * disabled.
186: *
187: * @return the background image
188: */
189: public FillImage getDisabledBackgroundImage() {
190: return (FillImage) getProperty(PROPERTY_DISABLED_BACKGROUND_IMAGE);
191: }
192:
193: /**
194: * Returns the border displayed when the text component is
195: * disabled.
196: *
197: * @return the border
198: */
199: public Border getDisabledBorder() {
200: return (Border) getProperty(PROPERTY_DISABLED_BORDER);
201: }
202:
203: /**
204: * Returns the font displayed when the text component is
205: * disabled.
206: *
207: * @return the font
208: */
209: public Font getDisabledFont() {
210: return (Font) getProperty(PROPERTY_DISABLED_FONT);
211: }
212:
213: /**
214: * Returns the foreground color displayed when the text component is
215: * disabled.
216: *
217: * @return the color
218: */
219: public Color getDisabledForeground() {
220: return (Color) getProperty(PROPERTY_DISABLED_FOREGROUND);
221: }
222:
223: /**
224: * Returns the model associated with this <code>TextComponent</code>.
225: *
226: * @return the model
227: */
228: public Document getDocument() {
229: return document;
230: }
231:
232: /**
233: * Returns the height of the text component.
234: * This property only supports <code>Extent</code>s with
235: * fixed (i.e., not percent) units.
236: *
237: * @return the height
238: */
239: public Extent getHeight() {
240: return (Extent) getProperty(PROPERTY_HEIGHT);
241: }
242:
243: /**
244: * Returns the horizontal scroll bar position.
245: *
246: * @return the scroll bar position
247: */
248: public Extent getHorizontalScroll() {
249: return (Extent) getProperty(PROPERTY_HORIZONTAL_SCROLL);
250: }
251:
252: /**
253: * Returns the insets of the text component.
254: *
255: * @return the insets
256: */
257: public Insets getInsets() {
258: return (Insets) getProperty(PROPERTY_INSETS);
259: }
260:
261: /**
262: * Returns the maximum length (in characters) of the text which may be
263: * entered into the component.
264: *
265: * @return the maximum length, or -1 if no value is specified
266: */
267: public int getMaximumLength() {
268: Integer value = (Integer) getProperty(PROPERTY_MAXIMUM_LENGTH);
269: return value == null ? -1 : value.intValue();
270: }
271:
272: /**
273: * Returns the text contained in the <code>Document</code> model of
274: * this text component.
275: *
276: * @return the text contained in the document
277: */
278: public String getText() {
279: return document.getText();
280: }
281:
282: /**
283: * Returns the tool tip text (displayed when the mouse cursor is hovered
284: * over the component).
285: *
286: * @return the tool tip text
287: */
288: public String getToolTipText() {
289: return (String) getProperty(PROPERTY_TOOL_TIP_TEXT);
290: }
291:
292: /**
293: * Returns the vertical scroll bar position.
294: *
295: * @return the scroll bar position
296: */
297: public Extent getVerticalScroll() {
298: return (Extent) getProperty(PROPERTY_VERTICAL_SCROLL);
299: }
300:
301: /**
302: * Returns the width of the text component.
303: * This property supports <code>Extent</code>s with
304: * either fixed or percentage-based units.
305: *
306: * @return the width
307: */
308: public Extent getWidth() {
309: return (Extent) getProperty(PROPERTY_WIDTH);
310: }
311:
312: /**
313: * Determines the any <code>ActionListener</code>s are registered.
314: *
315: * @return true if any action listeners are registered
316: */
317: public boolean hasActionListeners() {
318: return hasEventListenerList()
319: && getEventListenerList().getListenerCount(
320: ActionListener.class) != 0;
321: }
322:
323: /**
324: * This component does not support children.
325: *
326: * @see nextapp.echo2.app.Component#isValidChild(nextapp.echo2.app.Component)
327: */
328: public boolean isValidChild(Component component) {
329: return false;
330: }
331:
332: /**
333: * @see nextapp.echo2.app.Component#processInput(java.lang.String, java.lang.Object)
334: */
335: public void processInput(String inputName, Object inputValue) {
336: super .processInput(inputName, inputValue);
337:
338: if (TEXT_CHANGED_PROPERTY.equals(inputName)) {
339: setText((String) inputValue);
340: } else if (PROPERTY_HORIZONTAL_SCROLL.equals(inputName)) {
341: setHorizontalScroll((Extent) inputValue);
342: } else if (PROPERTY_VERTICAL_SCROLL.equals(inputName)) {
343: setVerticalScroll((Extent) inputValue);
344: } else if (INPUT_ACTION.equals(inputName)) {
345: fireActionEvent();
346: }
347: }
348:
349: /**
350: * Removes an <code>ActionListener</code> from the <code>TextField</code>.
351: *
352: * @param l the <code>ActionListener</code> to remove
353: */
354: public void removeActionListener(ActionListener l) {
355: if (!hasEventListenerList()) {
356: return;
357: }
358: getEventListenerList().removeListener(ActionListener.class, l);
359: // Notification of action listener changes is provided due to
360: // existence of hasActionListeners() method.
361: firePropertyChange(ACTION_LISTENERS_CHANGED_PROPERTY, l, null);
362: }
363:
364: /**
365: * Sets the action command which will be provided in
366: * <code>ActionEvent</code>s fired by this <code>TextField</code>.
367: *
368: * @param newValue the new action command
369: */
370: public void setActionCommand(String newValue) {
371: setProperty(PROPERTY_ACTION_COMMAND, newValue);
372: }
373:
374: /**
375: * Sets the alignment of the text component.
376: *
377: * @param newValue the new alignment
378: */
379: public void setAlignment(Alignment newValue) {
380: setProperty(PROPERTY_ALIGNMENT, newValue);
381: }
382:
383: /**
384: * Sets the default background image of the text component.
385: *
386: * @param newValue the new background image
387: */
388: public void setBackgroundImage(FillImage newValue) {
389: setProperty(PROPERTY_BACKGROUND_IMAGE, newValue);
390: }
391:
392: /**
393: * Sets the border of the text component.
394: *
395: * @param newValue the new border
396: */
397: public void setBorder(Border newValue) {
398: setProperty(PROPERTY_BORDER, newValue);
399: }
400:
401: /**
402: * Sets the background color displayed when the component is disabled.
403: *
404: * @param newValue the new <code>Color</code>
405: */
406: public void setDisabledBackground(Color newValue) {
407: setProperty(PROPERTY_DISABLED_BACKGROUND, newValue);
408: }
409:
410: /**
411: * Sets the background image displayed when the component is disabled.
412: *
413: * @param newValue the new background image
414: */
415: public void setDisabledBackgroundImage(FillImage newValue) {
416: setProperty(PROPERTY_DISABLED_BACKGROUND_IMAGE, newValue);
417: }
418:
419: /**
420: * Sets the border displayed when the component is disabled.
421: *
422: * @param newValue the new border
423: */
424: public void setDisabledBorder(Border newValue) {
425: setProperty(PROPERTY_DISABLED_BORDER, newValue);
426: }
427:
428: /**
429: * Sets the font displayed when the component is disabled.
430: *
431: * @param newValue the new <code>Font</code>
432: */
433: public void setDisabledFont(Font newValue) {
434: setProperty(PROPERTY_DISABLED_FONT, newValue);
435: }
436:
437: /**
438: * Sets the foreground color displayed when the component is disabled.
439: *
440: * @param newValue the new <code>Color</code>
441: */
442: public void setDisabledForeground(Color newValue) {
443: setProperty(PROPERTY_DISABLED_FOREGROUND, newValue);
444: }
445:
446: /**
447: * Sets the model associated with this <code>TextComponent</code>.
448: *
449: * @param newValue the new model (may not be null)
450: */
451: public void setDocument(Document newValue) {
452: if (newValue == null) {
453: throw new IllegalArgumentException(
454: "Document may not be null.");
455: }
456: Document oldValue = getDocument();
457: if (oldValue != null) {
458: oldValue.removeDocumentListener(documentListener);
459: }
460: newValue.addDocumentListener(documentListener);
461: document = newValue;
462: }
463:
464: /**
465: * Sets the height of the text component.
466: * This property only supports <code>Extent</code>s with
467: * fixed (i.e., not percent) units.
468: *
469: * @param newValue the new height
470: */
471: public void setHeight(Extent newValue) {
472: setProperty(PROPERTY_HEIGHT, newValue);
473: }
474:
475: /**
476: * Sets the horizontal scroll bar position.
477: * The provided <code>Extent</code> value must be in pixel units.
478: *
479: * @param newValue the new scroll bar position
480: */
481: public void setHorizontalScroll(Extent newValue) {
482: setProperty(PROPERTY_HORIZONTAL_SCROLL, newValue);
483: }
484:
485: /**
486: * Sets the insets of the text component.
487: *
488: * @param newValue the new insets
489: */
490: public void setInsets(Insets newValue) {
491: setProperty(PROPERTY_INSETS, newValue);
492: }
493:
494: /**
495: * Sets the maximum length (in characters) of the text which may be
496: * entered into the component.
497: *
498: * @param newValue the new maximum length, or -1 if to specify an
499: * unlimited length
500: */
501: public void setMaximumLength(int newValue) {
502: if (newValue < 0) {
503: setProperty(PROPERTY_MAXIMUM_LENGTH, null);
504: } else {
505: setProperty(PROPERTY_MAXIMUM_LENGTH, new Integer(newValue));
506: }
507: }
508:
509: /**
510: * Sets the text of document model of this text component.
511: *
512: * @param newValue the new text
513: */
514: public void setText(String newValue) {
515: Integer maxLength = (Integer) getProperty(PROPERTY_MAXIMUM_LENGTH);
516: if (newValue != null && maxLength != null
517: && maxLength.intValue() > 0
518: && newValue.length() > maxLength.intValue()) {
519: getDocument().setText(
520: newValue.substring(0, maxLength.intValue()));
521: } else {
522: getDocument().setText(newValue);
523: }
524: }
525:
526: /**
527: * Sets the tool tip text (displayed when the mouse cursor is hovered
528: * over the component).
529: *
530: * @param newValue the new tool tip text
531: */
532: public void setToolTipText(String newValue) {
533: setProperty(PROPERTY_TOOL_TIP_TEXT, newValue);
534: }
535:
536: /**
537: * Sets the vertical scroll bar position.
538: * The provided <code>Extent</code> value must be in pixel units.
539: *
540: * @param newValue the new scroll bar position
541: */
542: public void setVerticalScroll(Extent newValue) {
543: setProperty(PROPERTY_VERTICAL_SCROLL, newValue);
544: }
545:
546: /**
547: * Sets the width of the text component.
548: * This property supports <code>Extent</code>s with
549: * either fixed or percentage-based units.
550: *
551: * @param newValue the new width
552: */
553: public void setWidth(Extent newValue) {
554: setProperty(PROPERTY_WIDTH, newValue);
555: }
556: }
|