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: * @author Evgeniya G. Maenkova
019: * @version $Revision$
020: */package javax.swing;
021:
022: import java.awt.ComponentOrientation;
023: import java.awt.Container;
024: import java.awt.Dimension;
025: import java.awt.Font;
026: import java.awt.FontMetrics;
027: import java.awt.Insets;
028: import java.awt.Rectangle;
029: import java.awt.event.ActionEvent;
030: import java.awt.event.ActionListener;
031: import java.beans.PropertyChangeEvent;
032: import java.beans.PropertyChangeListener;
033:
034: import javax.accessibility.AccessibleContext;
035: import javax.accessibility.AccessibleState;
036: import javax.accessibility.AccessibleStateSet;
037: import javax.swing.event.ChangeEvent;
038: import javax.swing.event.ChangeListener;
039: import javax.swing.plaf.TextUI;
040: import javax.swing.text.BadLocationException;
041: import javax.swing.text.Document;
042: import javax.swing.text.JTextComponent;
043: import javax.swing.text.PlainDocument;
044: import javax.swing.text.TextAction;
045: import javax.swing.text.View;
046:
047: import org.apache.harmony.awt.ComponentInternals;
048: import org.apache.harmony.awt.text.PropertyNames;
049: import org.apache.harmony.awt.text.TextFieldKit;
050:
051: import org.apache.harmony.x.swing.internal.nls.Messages;
052:
053: /**
054: * Note: <code>serialVersionUID</code> fields in this class and its inner
055: * classes are added as a performance optimization but not as a guarantee of
056: * correct deserialization of the classes.
057: */
058: public class JTextField extends JTextComponent implements
059: SwingConstants {
060:
061: protected class AccessibleJTextField extends
062: JTextComponent.AccessibleJTextComponent {
063:
064: private static final long serialVersionUID = -3980593114771538955L;
065:
066: protected AccessibleJTextField() {
067: super ();
068: }
069:
070: @Override
071: public AccessibleStateSet getAccessibleStateSet() {
072: AccessibleStateSet ass = super .getAccessibleStateSet();
073: ass.add(AccessibleState.SINGLE_LINE);
074: return ass;
075: }
076: }
077:
078: public static final String notifyAction = "notify-field-accept";
079:
080: /**
081: * This field is added as a performance optimization but not as
082: * a guarantee of correct deserialization of the class.
083: */
084: private static final long serialVersionUID = 6111025777502333651L;
085:
086: private int columns;
087:
088: private int columnWidth;
089:
090: private static final String uiClassID = "TextFieldUI";
091:
092: private static final TextAction AcceptAction = new NotifyAction(
093: notifyAction);
094:
095: private transient String actionCommand;
096:
097: private transient int horizontalAlignment;
098:
099: private transient ActionEvent actionEvent;
100:
101: private transient Action action;
102:
103: private transient Action oldAction;
104:
105: private transient PropertyChangeListener listener;
106:
107: private transient int scrollOffset;
108:
109: private transient BoundedRangeModel boundedRangeModel;
110:
111: transient boolean scrollOffsetWasSet = false;
112:
113: final class ActionPropertyChangeListener implements
114: PropertyChangeListener {
115: public void propertyChange(final PropertyChangeEvent event) {
116: String name = event.getPropertyName();
117: Object newValue = event.getNewValue();
118: if (name == "enabled") {
119: setEnabled(((Boolean) newValue).booleanValue());
120: }
121: if (name == "ShortDescription") {
122: setToolTipText((String) newValue);
123: }
124: }
125: }
126:
127: static class NotifyAction extends TextAction {
128: private static final long serialVersionUID = 7892443630033381907L;
129:
130: public NotifyAction(final String name) {
131: super (name);
132: }
133:
134: public void actionPerformed(final ActionEvent a) {
135: final JTextComponent focused = getFocusedComponent();
136: if (!(focused instanceof JTextField)) {
137: return;
138: }
139:
140: ((JTextField) focused).postActionEvent();
141: }
142:
143: @Override
144: public boolean isEnabled() {
145: final JTextComponent focused = getFocusedComponent();
146: if (!(focused instanceof JTextField)) {
147: return false;
148: }
149:
150: JTextField textField = (JTextField) focused;
151: return textField.getActionListeners().length > 0;
152: }
153: }
154:
155: class TextFieldKitImpl implements TextFieldKit {
156: public int getHorizontalAlignment() {
157: return JTextField.this .getHorizontalAlignment();
158: }
159:
160: public BoundedRangeModel getHorizontalVisibility() {
161: return JTextField.this .getHorizontalVisibility();
162: }
163:
164: public boolean echoCharIsSet() {
165: return false;
166: }
167:
168: public char getEchoChar() {
169: return '\0';
170: }
171:
172: public Insets getInsets() {
173: return JTextField.this .getInsets();
174: }
175:
176: public ComponentOrientation getComponentOrientation() {
177: return JTextField.this .getComponentOrientation();
178: }
179: }
180:
181: final class ModelChangeListener implements ChangeListener {
182: public void stateChanged(final ChangeEvent e) {
183: scrollOffset = boundedRangeModel.getValue();
184: }
185: }
186:
187: public JTextField() {
188: this (null, null, 0);
189: }
190:
191: public JTextField(final int c) {
192: this (null, null, c);
193: }
194:
195: public JTextField(final String text) {
196: this (null, text, 0);
197: }
198:
199: public JTextField(final String text, final int c) {
200: this (null, text, c);
201: }
202:
203: public JTextField(final Document doc, final String text, final int c) {
204: super ();
205: if (c < 0) {
206: throw new IllegalArgumentException(Messages
207: .getString("swing.45")); //$NON-NLS-1$
208: }
209: Document document = doc;
210: if (doc == null) {
211: document = createDefaultModel();
212: }
213:
214: setDocument(document);
215: if (text != null) {
216: try {
217: document.remove(0, document.getLength());
218: document.insertString(0, text, null);
219: } catch (final BadLocationException e) {
220: }
221: }
222:
223: columns = c;
224: evaluate(getFont());
225: actionCommand = null;
226: horizontalAlignment = LEADING;
227: action = null;
228: oldAction = null;
229: installTextKit();
230: }
231:
232: void installTextKit() {
233: ComponentInternals.getComponentInternals().setTextFieldKit(
234: this , new TextFieldKitImpl());
235: }
236:
237: public void addActionListener(final ActionListener actionListener) {
238: listenerList.add(ActionListener.class, actionListener);
239: }
240:
241: private String alignmentToString(final int alignment) {
242: switch (alignment) {
243: case LEFT:
244: return "LEFT";
245: case CENTER:
246: return "CENTER";
247: case RIGHT:
248: return "RIGHT";
249: case LEADING:
250: return "LEADING";
251: case TRAILING:
252: return "TRAILING";
253: default:
254: return null;
255: }
256: }
257:
258: protected void configurePropertiesFromAction(final Action a) {
259: if (a == null) {
260: setEnabled(true);
261: setToolTipText(null);
262: return;
263: }
264: setEnabled(a.isEnabled());
265: String toolTipText = (String) a
266: .getValue(Action.SHORT_DESCRIPTION);
267: setToolTipText(toolTipText);
268: }
269:
270: protected PropertyChangeListener createActionPropertyChangeListener(
271: final Action a) {
272: return new ActionPropertyChangeListener();
273: }
274:
275: final BoundedRangeModel createBoundedRangeModel() {
276: int prefWidth = (int) getUI().getRootView(this )
277: .getPreferredSpan(View.X_AXIS);
278: int value = getMaxScrollOffset();
279: int max = Math.max(prefWidth, value);
280: return new DefaultBoundedRangeModel(value, max - value, 0, max);
281: }
282:
283: protected Document createDefaultModel() {
284: return new PlainDocument();
285: }
286:
287: private void evaluate(final Font f) {
288: if (f != null) {
289: FontMetrics fm = getFontMetrics(f);
290: columnWidth = fm.charWidth('m');
291: } else {
292: columnWidth = 0;
293: }
294: }
295:
296: protected void fireActionPerformed() {
297: String command = actionCommand == null ? getText()
298: : actionCommand;
299: actionEvent = new ActionEvent(this ,
300: ActionEvent.ACTION_PERFORMED, command);
301: ActionListener[] listeners = getActionListeners();
302: for (int i = 0; i < listeners.length; i++) {
303: listeners[i].actionPerformed(actionEvent);
304: }
305:
306: }
307:
308: @Override
309: public AccessibleContext getAccessibleContext() {
310: if (accessibleContext == null) {
311: accessibleContext = new AccessibleJTextField();
312: }
313: return accessibleContext;
314: }
315:
316: public Action getAction() {
317: return action;
318: }
319:
320: public ActionListener[] getActionListeners() {
321: return listenerList.getListeners(ActionListener.class);
322: }
323:
324: @Override
325: public Action[] getActions() {
326: Action[] editorKitActions = ((TextUI) ui).getEditorKit(this )
327: .getActions();
328: int length = editorKitActions.length;
329: Action[] actions = new Action[length + 1];
330: System.arraycopy(editorKitActions, 0, actions, 0, length);
331: actions[length] = AcceptAction;
332: return actions;
333: }
334:
335: public int getColumns() {
336: return columns;
337: }
338:
339: protected int getColumnWidth() {
340: return columnWidth;
341: }
342:
343: public int getHorizontalAlignment() {
344: return horizontalAlignment;
345: }
346:
347: public BoundedRangeModel getHorizontalVisibility() {
348: if (boundedRangeModel == null) {
349: boundedRangeModel = createBoundedRangeModel();
350: boundedRangeModel
351: .addChangeListener(new ModelChangeListener());
352: }
353: return boundedRangeModel;
354: }
355:
356: final int getMaxScrollOffset() {
357: int prefWidth = getPreferredSize().width;
358: int width = getWidth();
359: int diff = prefWidth - width;
360: return (diff >= 0) ? diff + 1 : 0;
361: }
362:
363: @Override
364: public Dimension getPreferredSize() {
365: int widthColumns = columns * columnWidth;
366: Dimension dim = super .getPreferredSize();
367: int width = (columns == 0) ? dim.width : widthColumns;
368: return new Dimension(width, dim.height);
369: }
370:
371: public int getScrollOffset() {
372: return scrollOffset;
373: }
374:
375: @Override
376: public String getUIClassID() {
377: return uiClassID;
378: }
379:
380: @Override
381: public boolean isValidateRoot() {
382: Container parent = getParent();
383: return parent == null || !(parent instanceof JViewport);
384: }
385:
386: /*
387: * The format of the string is based on 1.5 release behavior
388: * which can be revealed using the following code:
389: *
390: * Object obj = new JTextField();
391: * System.out.println(obj.toString());
392: */
393: @Override
394: protected String paramString() {
395: return super .paramString() + "," + "columns=" + getColumns()
396: + "," + "columnWidth=" + getColumnWidth() + ","
397: + "command=" + actionCommand + ","
398: + "horizontalAlignment="
399: + alignmentToString(getHorizontalAlignment());
400: }
401:
402: public void postActionEvent() {
403: fireActionPerformed();
404: }
405:
406: public void removeActionListener(final ActionListener actionListener) {
407: listenerList.remove(ActionListener.class, actionListener);
408: }
409:
410: @Override
411: public void scrollRectToVisible(final Rectangle r) {
412: int x = r.x;
413: Insets insets = getInsets();
414: BoundedRangeModel brm = getHorizontalVisibility();
415: int oldValue = brm.getValue();
416: int width = getVisibleRect().width;
417:
418: if (x > width - insets.right) {
419: brm.setValue(oldValue + (x - width + insets.right) + 2);
420: repaint();
421: }
422: if (x < insets.left) {
423: brm.setValue(oldValue - (insets.left - x) - 2);
424: repaint();
425: }
426: }
427:
428: public void setAction(final Action a) {
429: oldAction = action;
430: action = a;
431: configurePropertiesFromAction(a);
432: if (oldAction != null) {
433: oldAction.removePropertyChangeListener(listener);
434: }
435: if (a != null) {
436: listener = createActionPropertyChangeListener(a);
437: a.addPropertyChangeListener(listener);
438: }
439:
440: ActionListener[] listeners = getActionListeners();
441: boolean isNew = true;
442: int length = listeners.length;
443:
444: removeActionListener(oldAction);
445: if (a == null) {
446: return;
447: }
448: for (int i = 0; i < length; i++) {
449: if (listeners[i] == a) {
450: isNew = false;
451: break;
452: }
453: }
454: if (isNew) {
455: addActionListener(a);
456: }
457: }
458:
459: public void setActionCommand(final String command) {
460: actionCommand = command;
461:
462: }
463:
464: public void setColumns(final int c) {
465: if (c < 0) {
466: throw new IllegalArgumentException(Messages
467: .getString("swing.45")); //$NON-NLS-1$
468: }
469: columns = c;
470: invalidate();
471:
472: }
473:
474: @Override
475: public void setDocument(final Document doc) {
476: super .setDocument(doc);
477: if (doc != null) {
478: doc.putProperty(PropertyNames.FILTER_NEW_LINES,
479: Boolean.TRUE);
480: }
481: }
482:
483: @Override
484: public void setFont(final Font f) {
485: super .setFont(f);
486: evaluate(f);
487: revalidate();
488: }
489:
490: public void setHorizontalAlignment(final int alignment) {
491: if (alignment != LEFT && alignment != RIGHT
492: && alignment != CENTER && alignment != LEADING
493: && alignment != TRAILING) {
494: throw new IllegalArgumentException("horizontalAlignment"); //$NON-NLS-1$
495: }
496: int old = horizontalAlignment;
497: horizontalAlignment = alignment;
498: LookAndFeel.markPropertyNotInstallable(this ,
499: "horizontalAlignment");
500: firePropertyChange("horizontalAlignment", old,
501: horizontalAlignment);
502: }
503:
504: public void setScrollOffset(final int scrOffset) {
505: scrollOffsetWasSet = true;
506: LookAndFeel.markPropertyNotInstallable(this , "scrollOffset");
507: scrollOffset = Math.min(Math.max(0, scrOffset),
508: getMaxScrollOffset());
509: getHorizontalVisibility().setValue(scrollOffset);
510: }
511:
512: }
|