001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.user.client.ui;
017:
018: import com.google.gwt.core.client.GWT;
019: import com.google.gwt.user.client.DOM;
020: import com.google.gwt.user.client.Element;
021: import com.google.gwt.user.client.Event;
022: import com.google.gwt.user.client.ui.impl.TextBoxImpl;
023:
024: /**
025: * Abstract base class for all text entry widgets.
026: */
027: public class TextBoxBase extends FocusWidget implements
028: SourcesKeyboardEvents, SourcesChangeEvents, SourcesClickEvents,
029: HasText, HasName {
030:
031: /**
032: * Text alignment constant, used in
033: * {@link TextBoxBase#setTextAlignment(TextBoxBase.TextAlignConstant)}.
034: */
035: public static class TextAlignConstant {
036: private String textAlignString;
037:
038: private TextAlignConstant(String textAlignString) {
039: this .textAlignString = textAlignString;
040: }
041:
042: private String getTextAlignString() {
043: return textAlignString;
044: }
045: }
046:
047: /**
048: * Center the text.
049: */
050: public static final TextAlignConstant ALIGN_CENTER = new TextAlignConstant(
051: "center");
052:
053: /**
054: * Justify the text.
055: */
056: public static final TextAlignConstant ALIGN_JUSTIFY = new TextAlignConstant(
057: "justify");
058:
059: /**
060: * Align the text to the left edge.
061: */
062: public static final TextAlignConstant ALIGN_LEFT = new TextAlignConstant(
063: "left");
064:
065: /**
066: * Align the text to the right.
067: */
068: public static final TextAlignConstant ALIGN_RIGHT = new TextAlignConstant(
069: "right");
070:
071: private static TextBoxImpl impl = GWT.create(TextBoxImpl.class);
072:
073: private ChangeListenerCollection changeListeners;
074: private ClickListenerCollection clickListeners;
075: private Event currentEvent;
076: private KeyboardListenerCollection keyboardListeners;
077:
078: /**
079: * Creates a text box that wraps the given browser element handle. This is
080: * only used by subclasses.
081: *
082: * @param elem the browser element to wrap
083: */
084: protected TextBoxBase(Element elem) {
085: super (elem);
086: sinkEvents(Event.ONCHANGE);
087: }
088:
089: public void addChangeListener(ChangeListener listener) {
090: if (changeListeners == null) {
091: changeListeners = new ChangeListenerCollection();
092: }
093: changeListeners.add(listener);
094: }
095:
096: @Override
097: public void addClickListener(ClickListener listener) {
098: if (clickListeners == null) {
099: clickListeners = new ClickListenerCollection();
100: }
101: clickListeners.add(listener);
102: }
103:
104: @Override
105: public void addKeyboardListener(KeyboardListener listener) {
106: if (keyboardListeners == null) {
107: keyboardListeners = new KeyboardListenerCollection();
108: }
109: keyboardListeners.add(listener);
110: }
111:
112: /**
113: * If a keyboard event is currently being handled on this text box, calling
114: * this method will suppress it. This allows listeners to easily filter
115: * keyboard input.
116: */
117: public void cancelKey() {
118: if (currentEvent != null) {
119: DOM.eventPreventDefault(currentEvent);
120: }
121: }
122:
123: /**
124: * Gets the current position of the cursor (this also serves as the beginning
125: * of the text selection).
126: *
127: * @return the cursor's position
128: */
129: public int getCursorPos() {
130: return impl.getCursorPos(getElement());
131: }
132:
133: public String getName() {
134: return DOM.getElementProperty(getElement(), "name");
135: }
136:
137: /**
138: * Gets the text currently selected within this text box.
139: *
140: * @return the selected text, or an empty string if none is selected
141: */
142: public String getSelectedText() {
143: int start = getCursorPos(), length = getSelectionLength();
144: return getText().substring(start, start + length);
145: }
146:
147: /**
148: * Gets the length of the current text selection.
149: *
150: * @return the text selection length
151: */
152: public int getSelectionLength() {
153: return impl.getSelectionLength(getElement());
154: }
155:
156: public String getText() {
157: return DOM.getElementProperty(getElement(), "value");
158: }
159:
160: /**
161: * Determines whether or not the widget is read-only.
162: *
163: * @return <code>true</code> if the widget is currently read-only,
164: * <code>false</code> if the widget is currently editable
165: */
166: public boolean isReadOnly() {
167: return DOM.getElementPropertyBoolean(getElement(), "readOnly");
168: }
169:
170: @Override
171: public void onBrowserEvent(Event event) {
172: // Call the superclass' implementation first (because FocusWidget fires
173: // some events itself).
174: super .onBrowserEvent(event);
175:
176: int type = DOM.eventGetType(event);
177: if ((keyboardListeners != null)
178: && (type & Event.KEYEVENTS) != 0) {
179: // Fire the keyboard event. Hang on to the current event object so that
180: // cancelKey() and setKey() can be implemented.
181: currentEvent = event;
182: keyboardListeners.fireKeyboardEvent(this , event);
183: currentEvent = null;
184: } else if (type == Event.ONCLICK) {
185: // Fire the click event.
186: if (clickListeners != null) {
187: clickListeners.fireClick(this );
188: }
189: } else if (type == Event.ONCHANGE) {
190: // Fire the change event.
191: if (changeListeners != null) {
192: changeListeners.fireChange(this );
193: }
194: }
195: }
196:
197: public void removeChangeListener(ChangeListener listener) {
198: if (changeListeners != null) {
199: changeListeners.remove(listener);
200: }
201: }
202:
203: @Override
204: public void removeClickListener(ClickListener listener) {
205: if (clickListeners != null) {
206: clickListeners.remove(listener);
207: }
208: }
209:
210: @Override
211: public void removeKeyboardListener(KeyboardListener listener) {
212: if (keyboardListeners != null) {
213: keyboardListeners.remove(listener);
214: }
215: }
216:
217: /**
218: * Selects all of the text in the box.
219: */
220: public void selectAll() {
221: int length = getText().length();
222: if (length > 0) {
223: setSelectionRange(0, length);
224: }
225: }
226:
227: /**
228: * Sets the cursor position.
229: *
230: * @param pos the new cursor position
231: */
232: public void setCursorPos(int pos) {
233: setSelectionRange(pos, 0);
234: }
235:
236: /**
237: * If a keyboard event is currently being handled by the text box, this method
238: * replaces the unicode character or key code associated with it. This allows
239: * listeners to easily filter keyboard input.
240: *
241: * @param key the new key value
242: */
243: public void setKey(char key) {
244: if (currentEvent != null) {
245: DOM.eventSetKeyCode(currentEvent, key);
246: }
247: }
248:
249: public void setName(String name) {
250: DOM.setElementProperty(getElement(), "name", name);
251: }
252:
253: /**
254: * Turns read-only mode on or off.
255: *
256: * @param readOnly if <code>true</code>, the widget becomes read-only; if
257: * <code>false</code> the widget becomes editable
258: */
259: public void setReadOnly(boolean readOnly) {
260: DOM.setElementPropertyBoolean(getElement(), "readOnly",
261: readOnly);
262: String readOnlyStyle = "readonly";
263: if (readOnly) {
264: addStyleDependentName(readOnlyStyle);
265: } else {
266: removeStyleDependentName(readOnlyStyle);
267: }
268: }
269:
270: /**
271: * Sets the range of text to be selected.
272: *
273: * @param pos the position of the first character to be selected
274: * @param length the number of characters to be selected
275: */
276: public void setSelectionRange(int pos, int length) {
277: if (length < 0) {
278: throw new IndexOutOfBoundsException(
279: "Length must be a positive integer. Length: "
280: + length);
281: }
282: if ((pos < 0) || (length + pos > getText().length())) {
283: throw new IndexOutOfBoundsException("From Index: " + pos
284: + " To Index: " + (pos + length)
285: + " Text Length: " + getText().length());
286: }
287: impl.setSelectionRange(getElement(), pos, length);
288: }
289:
290: public void setText(String text) {
291: DOM.setElementProperty(getElement(), "value",
292: text != null ? text : "");
293: }
294:
295: /**
296: * Sets the alignment of the text in the text box.
297: *
298: * @param align the text alignment (as specified by {@link #ALIGN_CENTER},
299: * {@link #ALIGN_JUSTIFY}, {@link #ALIGN_LEFT}, and
300: * {@link #ALIGN_RIGHT})
301: */
302: public void setTextAlignment(TextAlignConstant align) {
303: DOM.setStyleAttribute(getElement(), "textAlign", align
304: .getTextAlignString());
305: }
306:
307: protected TextBoxImpl getImpl() {
308: return impl;
309: }
310: }
|