001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package java.awt;
019:
020: import java.awt.event.ActionEvent;
021: import java.awt.event.ActionListener;
022: import java.awt.event.KeyAdapter;
023: import java.awt.event.KeyEvent;
024: import java.util.EventListener;
025: import javax.accessibility.AccessibleContext;
026: import javax.accessibility.AccessibleState;
027: import javax.accessibility.AccessibleStateSet;
028: import javax.swing.BoundedRangeModel;
029: import javax.swing.DefaultBoundedRangeModel;
030: import javax.swing.event.ChangeEvent;
031: import javax.swing.event.ChangeListener;
032: import javax.swing.text.View;
033:
034: import org.apache.harmony.awt.internal.nls.Messages;
035: import org.apache.harmony.awt.text.AWTTextAction;
036: import org.apache.harmony.awt.text.ActionNames;
037: import org.apache.harmony.awt.text.ActionSet;
038: import org.apache.harmony.awt.text.PropertyNames;
039: import org.apache.harmony.awt.text.TextFactory;
040: import org.apache.harmony.awt.text.TextFieldKit;
041:
042: public class TextField extends TextComponent {
043: protected class AccessibleAWTTextField extends
044: AccessibleAWTTextComponent {
045: private static final long serialVersionUID = 6219164359235943158L;
046:
047: @Override
048: public AccessibleStateSet getAccessibleStateSet() {
049: AccessibleStateSet set = super .getAccessibleStateSet();
050: set.add(AccessibleState.SINGLE_LINE);
051: return set;
052: }
053: }
054:
055: /**
056: * Implementation of text field specific text operations
057: */
058: final class TextFieldKitImpl implements TextFieldKit {
059: /**
060: * used in horizontal text scrolling
061: */
062: BoundedRangeModel boundedRangeModel;
063:
064: public int getHorizontalAlignment() {
065: return 10; // LEADING
066: }
067:
068: /**
069: * Gets current bounded range model.
070: * Creates default bounded range model if necessary
071: * and adds listener to update current horizontal scroll
072: * position.
073: */
074: public BoundedRangeModel getHorizontalVisibility() {
075: if (boundedRangeModel == null) {
076: int prefWidth = (int) rootViewContext.getView()
077: .getPreferredSpan(View.X_AXIS);
078: int value = getMaxScrollOffset();
079: int max = Math.max(prefWidth, value);
080: boundedRangeModel = new DefaultBoundedRangeModel(value,
081: max - value, 0, max);
082: boundedRangeModel
083: .addChangeListener(new ChangeListener() {
084: public void stateChanged(ChangeEvent e) {
085: scrollPosition.x = -boundedRangeModel
086: .getValue();
087: }
088: });
089: }
090: return boundedRangeModel;
091: }
092:
093: public boolean echoCharIsSet() {
094: return TextField.this .echoChar != 0;
095: }
096:
097: public char getEchoChar() {
098: return TextField.this .getEchoChar();
099: }
100:
101: public Insets getInsets() {
102: return TextField.this .getNativeInsets();
103: }
104: }
105:
106: private static final long serialVersionUID = -2966288784432217853L;
107:
108: private final AWTListenerList<ActionListener> actionListeners = new AWTListenerList<ActionListener>(
109: this );
110:
111: private int columns;
112:
113: private char echoChar;
114:
115: public TextField(String text) throws HeadlessException {
116: this (text, (text != null ? text.length() : 0));
117: toolkit.lockAWT();
118: try {
119: } finally {
120: toolkit.unlockAWT();
121: }
122: }
123:
124: public TextField(int columns) throws HeadlessException {
125: this (new String(), columns);
126: toolkit.lockAWT();
127: try {
128: } finally {
129: toolkit.unlockAWT();
130: }
131: }
132:
133: public TextField() throws HeadlessException {
134: this (new String(), 0);
135: toolkit.lockAWT();
136: try {
137: } finally {
138: toolkit.unlockAWT();
139: }
140: }
141:
142: public TextField(String text, int columns) throws HeadlessException {
143: super ();
144: toolkit.lockAWT();
145: try {
146: Toolkit.checkHeadless();
147: setTextFieldKit(new TextFieldKitImpl());
148: this .columns = Math.max(0, columns);
149: addAWTKeyListener(new KeyAdapter() {
150: @Override
151: public void keyPressed(KeyEvent e) {
152: if ((e.getKeyCode() == KeyEvent.VK_ENTER)
153: && !e.isAltDown() && !e.isControlDown()) {
154: generateActionEvent(e.getWhen(), e
155: .getModifiers());
156: }
157: }
158: });
159: } finally {
160: toolkit.unlockAWT();
161: }
162: setText(text);
163: }
164:
165: @Override
166: public void addNotify() {
167: document.putProperty(PropertyNames.FILTER_NEW_LINES,
168: Boolean.TRUE);
169: setText(getText()); // remove all new lines in already existing text
170: toolkit.lockAWT();
171: try {
172: super .addNotify();
173: } finally {
174: toolkit.unlockAWT();
175: }
176: }
177:
178: @Override
179: public AccessibleContext getAccessibleContext() {
180: toolkit.lockAWT();
181: try {
182: return super .getAccessibleContext();
183: } finally {
184: toolkit.unlockAWT();
185: }
186: }
187:
188: public int getColumns() {
189: toolkit.lockAWT();
190: try {
191: return columns;
192: } finally {
193: toolkit.unlockAWT();
194: }
195: }
196:
197: @Override
198: public Dimension getMinimumSize() {
199: toolkit.lockAWT();
200: try {
201: return minimumSize();
202: } finally {
203: toolkit.unlockAWT();
204: }
205: }
206:
207: public Dimension getMinimumSize(int cols) {
208: toolkit.lockAWT();
209: try {
210: return minimumSize(cols);
211: } finally {
212: toolkit.unlockAWT();
213: }
214: }
215:
216: @Override
217: public Dimension getPreferredSize() {
218: toolkit.lockAWT();
219: try {
220: return preferredSize();
221: } finally {
222: toolkit.unlockAWT();
223: }
224: }
225:
226: public Dimension getPreferredSize(int columns) {
227: toolkit.lockAWT();
228: try {
229: return preferredSize(columns);
230: } finally {
231: toolkit.unlockAWT();
232: }
233: }
234:
235: /**
236: * @deprecated
237: */
238: @SuppressWarnings("deprecation")
239: @Deprecated
240: public Dimension minimumSize(int columns) {
241: toolkit.lockAWT();
242: try {
243: Dimension minSize = calcSize(columns);
244: if (minSize == null) {
245: return super .minimumSize();
246: }
247: return minSize;
248: } finally {
249: toolkit.unlockAWT();
250: }
251: }
252:
253: /**
254: * Calculates minimum size required for <code>cols</code> columns
255: */
256: private Dimension calcSize(int cols) {
257: FontMetrics fm = getFontMetrics(getFont());
258: if ((fm == null) || !isDisplayable()) {
259: return null;
260: }
261: return new Dimension(fm.charWidth('_') * cols + 6, fm
262: .getHeight() + 6);
263: }
264:
265: /**
266: * @deprecated
267: */
268: @SuppressWarnings("deprecation")
269: @Deprecated
270: @Override
271: public Dimension minimumSize() {
272: toolkit.lockAWT();
273: try {
274: if ((columns > 0)) {
275: return minimumSize(columns);
276: }
277: return super .minimumSize();
278: } finally {
279: toolkit.unlockAWT();
280: }
281: }
282:
283: @Override
284: protected String paramString() {
285: /* The format is based on 1.5 release behavior
286: * which can be revealed by the following code:
287: *
288: * TextField tf = new TextField();
289: * tf.setEchoChar('q');
290: * System.out.println(tf);
291: */
292: toolkit.lockAWT();
293: try {
294: String paramStr = super .paramString();
295: if (echoCharIsSet()) {
296: paramStr += ",echo=" + getEchoChar(); //$NON-NLS-1$
297: }
298: return paramStr;
299: } finally {
300: toolkit.unlockAWT();
301: }
302: }
303:
304: /**
305: * @deprecated
306: */
307: @SuppressWarnings("deprecation")
308: @Deprecated
309: public Dimension preferredSize(int columns) {
310: toolkit.lockAWT();
311: try {
312: Dimension prefSize = calcSize(columns);
313: if (prefSize == null) {
314: return super .preferredSize();
315: }
316: return prefSize;
317: } finally {
318: toolkit.unlockAWT();
319: }
320: }
321:
322: /**
323: * @deprecated
324: */
325: @SuppressWarnings("deprecation")
326: @Deprecated
327: @Override
328: public Dimension preferredSize() {
329: toolkit.lockAWT();
330: try {
331: if (columns > 0) {
332: return preferredSize(columns);
333: }
334: return super .preferredSize();
335: } finally {
336: toolkit.unlockAWT();
337: }
338: }
339:
340: public void setColumns(int columns) {
341: toolkit.lockAWT();
342: try {
343: if (columns < 0) {
344: // awt.102=columns less than zero.
345: throw new IllegalArgumentException(Messages
346: .getString("awt.102")); //$NON-NLS-1$
347: }
348: this .columns = columns;
349: } finally {
350: toolkit.unlockAWT();
351: }
352: }
353:
354: @Override
355: public void setText(String text) {
356: super .setText(text); // no AWT lock here!
357: }
358:
359: public boolean echoCharIsSet() {
360: toolkit.lockAWT();
361: try {
362: return (echoChar != 0);
363: } finally {
364: toolkit.unlockAWT();
365: }
366: }
367:
368: public char getEchoChar() {
369: toolkit.lockAWT();
370: try {
371: return echoChar;
372: } finally {
373: toolkit.unlockAWT();
374: }
375: }
376:
377: public void setEchoChar(char ch) {
378: toolkit.lockAWT();
379: try {
380: if (echoChar == ch) {
381: return;
382: }
383: echoChar = ch;
384: } finally {
385: toolkit.unlockAWT();
386: }
387: repaint();
388: }
389:
390: @Deprecated
391: public void setEchoCharacter(char ch) {
392: setEchoChar(ch);
393: }
394:
395: @SuppressWarnings("unchecked")
396: @Override
397: public <T extends EventListener> T[] getListeners(
398: Class<T> listenerType) {
399: if (ActionListener.class.isAssignableFrom(listenerType)) {
400: return (T[]) getActionListeners();
401: }
402: return super .getListeners(listenerType);
403: }
404:
405: public void addActionListener(ActionListener l) {
406: actionListeners.addUserListener(l);
407: }
408:
409: public void removeActionListener(ActionListener l) {
410: actionListeners.removeUserListener(l);
411: }
412:
413: public ActionListener[] getActionListeners() {
414: return actionListeners.getUserListeners(new ActionListener[0]);
415: }
416:
417: @Override
418: protected void processEvent(AWTEvent e) {
419: if (toolkit.eventTypeLookup.getEventMask(e) == AWTEvent.ACTION_EVENT_MASK) {
420: processActionEvent((ActionEvent) e);
421: } else {
422: super .processEvent(e);
423: }
424: }
425:
426: protected void processActionEvent(ActionEvent e) {
427: for (ActionListener listener : actionListeners
428: .getUserListeners()) {
429: switch (e.getID()) {
430: case ActionEvent.ACTION_PERFORMED:
431: listener.actionPerformed(e);
432: break;
433: }
434: }
435: }
436:
437: @Override
438: boolean isPrepainter() {
439: return true;
440: }
441:
442: /**
443: * Creates password view instead of default plain view.
444: * Necessary to be able to set echo character.
445: */
446: @Override
447: View createView() {
448: TextFactory factory = TextFactory.getTextFactory();
449: View v = factory.createPasswordView(document
450: .getDefaultRootElement());
451: return v;
452: }
453:
454: @Override
455: Dimension getDefaultMinimumSize() {
456: return calcSize(getText().length());
457: }
458:
459: @Override
460: Dimension getDefaultPreferredSize() {
461: if (getFont() == null) {
462: return null;
463: }
464: return getDefaultMinimumSize();
465: }
466:
467: private void generateActionEvent(long when, int modifiers) {
468: postEvent(new ActionEvent(this , ActionEvent.ACTION_PERFORMED,
469: getText(), when, modifiers));
470: }
471:
472: /**
473: * Horizontally scrolls text to make specified rectangle
474: * visible. Uses bounded range model value for
475: * scrolling. Repaints TextField.
476: */
477: @Override
478: void scrollRectToVisible(Rectangle r) {
479: int x = r.x;
480: Insets insets = getTextFieldKit().getInsets();
481: BoundedRangeModel brm = getTextFieldKit()
482: .getHorizontalVisibility();
483: int oldValue = brm.getValue();
484: int width = getModelRect().width;
485: if (x > width - insets.right) {
486: int newVal = oldValue + (x - width + insets.right) + 2;
487: brm.setValue(newVal);
488: repaint();
489: }
490: if (x < insets.left) {
491: brm.setValue(oldValue - (insets.left - x) - 2);
492: repaint();
493: }
494: }
495:
496: /**
497: * Returns just the same rectangle as getClient().
498: * Bounded range model takes care of actual text size.
499: */
500: @Override
501: Rectangle getModelRect() {
502: return getClient();
503: }
504:
505: /**
506: * Calculates maximum horizontal scroll value as
507: * difference between actual text size and text field component
508: * client area size.
509: */
510: final int getMaxScrollOffset() {
511: Insets ins = getNativeInsets();
512: int prefWidth = (int) rootViewContext.getView()
513: .getPreferredSpan(View.X_AXIS)
514: + ins.left + ins.right;
515: int width = getWidth();
516: int diff = prefWidth - width;
517: return (diff >= 0) ? diff + 1 : 0;
518: }
519:
520: @Override
521: AccessibleContext createAccessibleContext() {
522: return new AccessibleAWTTextField();
523: }
524:
525: @Override
526: String autoName() {
527: return ("textfield" + toolkit.autoNumber.nextTextField++); //$NON-NLS-1$
528: }
529:
530: /**
531: * Handles text actions.
532: * Ignores new line insertion into text.
533: */
534: @Override
535: void performTextAction(AWTTextAction action) {
536: if (action != ActionSet.actionMap
537: .get(ActionNames.insertBreakAction)) {
538: super.performTextAction(action);
539: }
540: }
541: }
|