001: /*
002: * Copyright 2003-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.X11;
027:
028: import java.awt.*;
029: import java.awt.peer.*;
030: import java.awt.event.*;
031: import java.awt.event.ActionEvent;
032: import java.awt.event.ActionListener;
033: import java.awt.event.TextEvent;
034: import javax.swing.text.*;
035: import javax.swing.event.DocumentListener;
036: import javax.swing.event.DocumentEvent;
037: import javax.swing.plaf.ComponentUI;
038: import javax.swing.InputMap;
039: import javax.swing.JPasswordField;
040: import javax.swing.SwingUtilities;
041: import javax.swing.TransferHandler;
042:
043: import java.awt.event.MouseEvent;
044: import java.awt.event.FocusEvent;
045: import java.awt.event.KeyEvent;
046:
047: import javax.swing.plaf.UIResource;
048: import javax.swing.UIDefaults;
049: import javax.swing.JTextField;
050: import javax.swing.JComponent;
051: import javax.swing.border.Border;
052: import com.sun.java.swing.plaf.motif.*;
053: import java.awt.im.InputMethodRequests;
054:
055: import java.util.logging.*;
056: import sun.awt.CausedFocusEvent;
057: import sun.awt.ComponentAccessor;
058:
059: public class XTextFieldPeer extends XComponentPeer implements
060: TextFieldPeer {
061: private static final Logger log = Logger
062: .getLogger("sun.awt.X11.XTextField");
063:
064: String text;
065: XAWTTextField xtext;
066:
067: boolean firstChangeSkipped;
068:
069: public XTextFieldPeer(TextField target) {
070: super (target);
071: int start, end;
072: firstChangeSkipped = false;
073: text = target.getText();
074: xtext = new XAWTTextField(text, this , target.getParent());
075: xtext.getDocument().addDocumentListener(xtext);
076: xtext.setCursor(target.getCursor());
077: target.enableInputMethods(true);
078: xtext.enableInputMethods(true);
079: XToolkit.specialPeerMap.put(xtext, this );
080:
081: TextField txt = (TextField) target;
082: initTextField();
083: setText(txt.getText());
084: if (txt.echoCharIsSet()) {
085: setEchoChar(txt.getEchoChar());
086: } else
087: setEchoChar((char) 0);
088:
089: start = txt.getSelectionStart();
090: end = txt.getSelectionEnd();
091:
092: if (end > start) {
093: select(start, end);
094: }
095: // Fix for 5100200
096: // Restoring Motif behaviour
097: // Since the end position of the selected text can be greater then the length of the text,
098: // so we should set caret to max position of the text
099: int caretPosition = Math.min(end, text.length());
100: setCaretPosition(caretPosition);
101:
102: setEditable(txt.isEditable());
103:
104: // After this line we should not change the component's text
105: firstChangeSkipped = true;
106: }
107:
108: public void dispose() {
109: XToolkit.specialPeerMap.remove(xtext);
110: xtext.removeNotify();
111: super .dispose();
112: }
113:
114: void initTextField() {
115: setVisible(target.isVisible());
116:
117: setBounds(x, y, width, height, SET_BOUNDS);
118:
119: foreground = ComponentAccessor.getForeground(target);
120: if (foreground == null)
121: foreground = SystemColor.textText;
122:
123: setForeground(foreground);
124:
125: background = ComponentAccessor.getBackground(target);
126: if (background == null) {
127: if (((TextField) target).isEditable())
128: background = SystemColor.text;
129: else
130: background = SystemColor.control;
131: }
132: setBackground(background);
133:
134: if (!target.isBackgroundSet()) {
135: // This is a way to set the background color of the TextArea
136: // without calling setBackground - go through reflection
137: ComponentAccessor.setBackground(target, background);
138: }
139: if (!target.isForegroundSet()) {
140: target.setForeground(SystemColor.textText);
141: }
142:
143: setFont(font);
144: }
145:
146: /**
147: * @see java.awt.peer.TextComponentPeer
148: */
149: public void setEditable(boolean editable) {
150: if (xtext != null) {
151: xtext.setEditable(editable);
152: xtext.repaint();
153: }
154: }
155:
156: /**
157: * @see java.awt.peer.ComponentPeer
158: */
159: public void setEnabled(boolean enabled) {
160: super .setEnabled(enabled);
161: if (xtext != null) {
162: xtext.setEnabled(enabled);
163: xtext.repaint();
164: }
165: }
166:
167: /**
168: * @see java.awt.peer.TextComponentPeer
169: */
170:
171: public InputMethodRequests getInputMethodRequests() {
172: if (xtext != null)
173: return xtext.getInputMethodRequests();
174: else
175: return null;
176:
177: }
178:
179: void handleJavaInputMethodEvent(InputMethodEvent e) {
180: if (xtext != null)
181: xtext.processInputMethodEventImpl(e);
182: }
183:
184: /**
185: * @see java.awt.peer.TextFieldPeer
186: */
187: public void setEchoChar(char c) {
188: if (xtext != null) {
189: xtext.setEchoChar(c);
190: xtext.putClientProperty("JPasswordField.cutCopyAllowed",
191: xtext.echoCharIsSet() ? Boolean.FALSE
192: : Boolean.TRUE);
193: }
194: }
195:
196: /**
197: * @see java.awt.peer.TextComponentPeer
198: */
199: public int getSelectionStart() {
200: return xtext.getSelectionStart();
201: }
202:
203: /**
204: * @see java.awt.peer.TextComponentPeer
205: */
206: public int getSelectionEnd() {
207: return xtext.getSelectionEnd();
208: }
209:
210: /**
211: * @see java.awt.peer.TextComponentPeer
212: */
213: public String getText() {
214: return xtext.getText();
215: }
216:
217: /**
218: * @see java.awt.peer.TextComponentPeer
219: */
220: public void setText(String txt) {
221: setXAWTTextField(txt);
222: repaint();
223: }
224:
225: protected boolean setXAWTTextField(String txt) {
226: text = txt;
227: if (xtext != null) {
228: // JTextField.setText() posts two different events (remove & insert).
229: // Since we make no differences between text events,
230: // the document listener has to be disabled while
231: // JTextField.setText() is called.
232: xtext.getDocument().removeDocumentListener(xtext);
233: xtext.setText(txt);
234: if (firstChangeSkipped) {
235: postEvent(new TextEvent(target,
236: TextEvent.TEXT_VALUE_CHANGED));
237: }
238: xtext.getDocument().addDocumentListener(xtext);
239: xtext.setCaretPosition(0);
240: }
241: return true;
242: }
243:
244: /**
245: * to be implemented.
246: * @see java.awt.peer.TextComponentPeer
247: */
248: public void setCaretPosition(int position) {
249: if (xtext != null)
250: xtext.setCaretPosition(position);
251: }
252:
253: /**
254: * DEPRECATED
255: * @see java.awt.peer.TextFieldPeer
256: */
257: public void setEchoCharacter(char c) {
258: setEchoChar(c);
259: }
260:
261: void repaintText() {
262: xtext.repaintNow();
263: }
264:
265: public void setBackground(Color c) {
266: if (log.isLoggable(Level.FINE))
267: log.fine("target=" + target + ", old=" + background
268: + ", new=" + c);
269: background = c;
270: if (xtext != null) {
271: xtext.setBackground(c);
272: xtext.setSelectedTextColor(c);
273: }
274: repaintText();
275: }
276:
277: public void setForeground(Color c) {
278: foreground = c;
279: if (xtext != null) {
280: xtext.setForeground(foreground);
281: xtext.setSelectionColor(foreground);
282: xtext.setCaretColor(foreground);
283: }
284: repaintText();
285: }
286:
287: public void setFont(Font f) {
288: synchronized (getStateLock()) {
289: font = f;
290: if (xtext != null) {
291: xtext.setFont(font);
292: }
293: }
294: xtext.validate();
295: }
296:
297: /**
298: * DEPRECATED
299: * @see java.awt.peer.TextFieldPeer
300: */
301: public Dimension preferredSize(int cols) {
302: return getPreferredSize(cols);
303: }
304:
305: /**
306: * Deselects the the highlighted text.
307: */
308: public void deselect() {
309: int selStart = xtext.getSelectionStart();
310: int selEnd = xtext.getSelectionEnd();
311: if (selStart != selEnd) {
312: xtext.select(selStart, selStart);
313: }
314: }
315:
316: /**
317: * to be implemented.
318: * @see java.awt.peer.TextComponentPeer
319: */
320: public int getCaretPosition() {
321: return xtext.getCaretPosition();
322: }
323:
324: /**
325: * @see java.awt.peer.TextComponentPeer
326: */
327: public void select(int s, int e) {
328: xtext.select(s, e);
329: // Fixed 5100806
330: // We must take care that Swing components repainted correctly
331: xtext.repaint();
332: }
333:
334: public Dimension getMinimumSize() {
335: return xtext.getMinimumSize();
336: }
337:
338: public Dimension getPreferredSize() {
339: return xtext.getPreferredSize();
340: }
341:
342: public Dimension getPreferredSize(int cols) {
343: return getMinimumSize(cols);
344: }
345:
346: private static final int PADDING = 16;
347:
348: public Dimension getMinimumSize(int cols) {
349: Font f = xtext.getFont();
350: FontMetrics fm = xtext.getFontMetrics(f);
351: return new Dimension(fm.charWidth('0') * cols + 10, fm
352: .getMaxDescent()
353: + fm.getMaxAscent() + PADDING);
354:
355: }
356:
357: public boolean isFocusable() {
358: return true;
359: }
360:
361: // NOTE: This method is called by privileged threads.
362: // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
363: public void action(final long when, final int modifiers) {
364: postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED,
365: text, when, modifiers));
366: }
367:
368: protected void disposeImpl() {
369: }
370:
371: public void repaint() {
372: if (xtext != null)
373: xtext.repaint();
374: }
375:
376: public void paint(Graphics g) {
377: if (xtext != null)
378: xtext.paint(g);
379: }
380:
381: public void print(Graphics g) {
382: if (xtext != null) {
383: xtext.print(g);
384: }
385: }
386:
387: public void focusLost(FocusEvent e) {
388: super .focusLost(e);
389: xtext.forwardFocusLost(e);
390: }
391:
392: public void focusGained(FocusEvent e) {
393: super .focusGained(e);
394: xtext.forwardFocusGained(e);
395: }
396:
397: void handleJavaKeyEvent(KeyEvent e) {
398: ComponentAccessor.processEvent(xtext, e);
399: }
400:
401: public void handleJavaMouseEvent(MouseEvent mouseEvent) {
402: super .handleJavaMouseEvent(mouseEvent);
403: if (xtext != null) {
404: mouseEvent.setSource(xtext);
405: int id = mouseEvent.getID();
406: if (id == MouseEvent.MOUSE_DRAGGED
407: || id == MouseEvent.MOUSE_MOVED)
408: xtext.processMouseMotionEventImpl(mouseEvent);
409: else
410: xtext.processMouseEventImpl(mouseEvent);
411: }
412: }
413:
414: /**
415: * DEPRECATED
416: */
417: public Dimension minimumSize() {
418: return getMinimumSize();
419: }
420:
421: /**
422: * DEPRECATED
423: */
424: public Dimension minimumSize(int cols) {
425: return getMinimumSize(cols);
426: }
427:
428: public void setVisible(boolean b) {
429: super .setVisible(b);
430: if (xtext != null)
431: xtext.setVisible(b);
432: }
433:
434: public void setBounds(int x, int y, int width, int height, int op) {
435: super .setBounds(x, y, width, height, op);
436: if (xtext != null) {
437: /*
438: * Fixed 6277332, 6198290:
439: * the coordinates is coming (to peer): relatively to closest HW parent
440: * the coordinates is setting (to textField): relatively to closest ANY parent
441: * the parent of peer is target.getParent()
442: * the parent of textField is the same
443: * see 6277332, 6198290 for more information
444: */
445: int childX = x;
446: int childY = y;
447: Component parent = target.getParent();
448: // we up to heavyweight parent in order to be sure
449: // that the coordinates of the text pane is relatively to closest parent
450: while (parent.isLightweight()) {
451: childX -= parent.getX();
452: childY -= parent.getY();
453: parent = parent.getParent();
454: }
455: xtext.setBounds(childX, childY, width, height);
456: xtext.validate();
457: }
458: }
459:
460: //
461: // Accessibility support
462: //
463:
464: // stub functions: to be fully implemented in a future release
465: public int getIndexAtPoint(int x, int y) {
466: return -1;
467: }
468:
469: public Rectangle getCharacterBounds(int i) {
470: return null;
471: }
472:
473: public long filterEvents(long mask) {
474: return 0;
475: }
476:
477: /* To be fully implemented in a future release
478:
479: int oldSelectionStart;
480: int oldSelectionEnd;
481:
482: public native int getIndexAtPoint(int x, int y);
483: public native Rectangle getCharacterBounds(int i);
484: public native long filterEvents(long mask);
485:
486: /**
487: * Handle a change in the text selection endpoints
488: * (Note: could be simply a change in the caret location)
489: *
490: public void selectionValuesChanged(int start, int end) {
491: return; // Need to write implemetation of this.
492: }
493: */
494:
495: class AWTTextFieldUI extends MotifPasswordFieldUI {
496:
497: /**
498: * Creates a UI for a JTextField.
499: *
500: * @param c the text field
501: * @return the UI
502: */
503: JTextField jtf;
504:
505: protected String getPropertyPrefix() {
506: JTextComponent comp = getComponent();
507: if (comp instanceof JPasswordField
508: && ((JPasswordField) comp).echoCharIsSet()) {
509: return "PasswordField";
510: } else {
511: return "TextField";
512: }
513: }
514:
515: public void installUI(JComponent c) {
516: super .installUI(c);
517:
518: jtf = (JTextField) c;
519:
520: JTextField editor = jtf;
521:
522: UIDefaults uidefaults = XToolkit.getUIDefaults();
523:
524: String prefix = getPropertyPrefix();
525: Font f = editor.getFont();
526: if ((f == null) || (f instanceof UIResource)) {
527: editor.setFont(uidefaults.getFont(prefix + ".font"));
528: }
529:
530: Color bg = editor.getBackground();
531: if ((bg == null) || (bg instanceof UIResource)) {
532: editor.setBackground(uidefaults.getColor(prefix
533: + ".background"));
534: }
535:
536: Color fg = editor.getForeground();
537: if ((fg == null) || (fg instanceof UIResource)) {
538: editor.setForeground(uidefaults.getColor(prefix
539: + ".foreground"));
540: }
541:
542: Color color = editor.getCaretColor();
543: if ((color == null) || (color instanceof UIResource)) {
544: editor.setCaretColor(uidefaults.getColor(prefix
545: + ".caretForeground"));
546: }
547:
548: Color s = editor.getSelectionColor();
549: if ((s == null) || (s instanceof UIResource)) {
550: editor.setSelectionColor(uidefaults.getColor(prefix
551: + ".selectionBackground"));
552: }
553:
554: Color sfg = editor.getSelectedTextColor();
555: if ((sfg == null) || (sfg instanceof UIResource)) {
556: editor.setSelectedTextColor(uidefaults.getColor(prefix
557: + ".selectionForeground"));
558: }
559:
560: Color dfg = editor.getDisabledTextColor();
561: if ((dfg == null) || (dfg instanceof UIResource)) {
562: editor.setDisabledTextColor(uidefaults.getColor(prefix
563: + ".inactiveForeground"));
564: }
565:
566: Border b = editor.getBorder();
567: if ((b == null) || (b instanceof UIResource)) {
568: editor.setBorder(uidefaults.getBorder(prefix
569: + ".border"));
570: }
571:
572: Insets margin = editor.getMargin();
573: if (margin == null || margin instanceof UIResource) {
574: editor.setMargin(uidefaults.getInsets(prefix
575: + ".margin"));
576: }
577: }
578:
579: protected void installKeyboardActions() {
580: super .installKeyboardActions();
581:
582: JTextComponent comp = getComponent();
583:
584: UIDefaults uidefaults = XToolkit.getUIDefaults();
585:
586: String prefix = getPropertyPrefix();
587:
588: InputMap map = (InputMap) uidefaults.get(prefix
589: + ".focusInputMap");
590:
591: if (map != null) {
592: SwingUtilities.replaceUIInputMap(comp,
593: JComponent.WHEN_FOCUSED, map);
594: }
595: }
596:
597: protected Caret createCaret() {
598: return new XAWTCaret();
599: }
600: }
601:
602: class XAWTCaret extends DefaultCaret {
603: public void focusGained(FocusEvent e) {
604: super .focusGained(e);
605: getComponent().repaint();
606: }
607:
608: public void focusLost(FocusEvent e) {
609: super .focusLost(e);
610: getComponent().repaint();
611: }
612:
613: // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit
614: // Restoring Motif behaviour
615: // If the text is unhighlighted then we should sets the selection range to zero
616: public void setSelectionVisible(boolean vis) {
617: if (vis) {
618: super .setSelectionVisible(vis);
619: } else {
620: // In order to de-select the selection
621: setDot(getDot());
622: }
623: }
624: }
625:
626: class XAWTTextField extends JPasswordField implements
627: ActionListener, DocumentListener {
628:
629: boolean isFocused = false;
630:
631: XComponentPeer peer;
632:
633: public XAWTTextField(String text, XComponentPeer peer,
634: Container parent) {
635: super (text);
636: this .peer = peer;
637: setDoubleBuffered(true);
638: setFocusable(false);
639: ComponentAccessor.setParent(this , parent);
640: setBackground(peer.getPeerBackground());
641: setForeground(peer.getPeerForeground());
642: setFont(peer.getPeerFont());
643: setCaretPosition(0);
644: addActionListener(this );
645: addNotify();
646:
647: }
648:
649: public void actionPerformed(ActionEvent actionEvent) {
650: peer.postEvent(new ActionEvent(peer.target,
651: ActionEvent.ACTION_PERFORMED, getText(),
652: actionEvent.getWhen(), actionEvent.getModifiers()));
653:
654: }
655:
656: public void insertUpdate(DocumentEvent e) {
657: if (peer != null) {
658: peer.postEvent(new TextEvent(peer.target,
659: TextEvent.TEXT_VALUE_CHANGED));
660: }
661: }
662:
663: public void removeUpdate(DocumentEvent e) {
664: if (peer != null) {
665: peer.postEvent(new TextEvent(peer.target,
666: TextEvent.TEXT_VALUE_CHANGED));
667: }
668: }
669:
670: public void changedUpdate(DocumentEvent e) {
671: if (peer != null) {
672: peer.postEvent(new TextEvent(peer.target,
673: TextEvent.TEXT_VALUE_CHANGED));
674: }
675: }
676:
677: public ComponentPeer getPeer() {
678: return (ComponentPeer) peer;
679: }
680:
681: public void repaintNow() {
682: paintImmediately(getBounds());
683: }
684:
685: public Graphics getGraphics() {
686: return peer.getGraphics();
687: }
688:
689: public void updateUI() {
690: ComponentUI ui = new AWTTextFieldUI();
691: setUI(ui);
692: }
693:
694: void forwardFocusGained(FocusEvent e) {
695: isFocused = true;
696: FocusEvent fe = CausedFocusEvent.retarget(e, this );
697: super .processFocusEvent(fe);
698:
699: }
700:
701: void forwardFocusLost(FocusEvent e) {
702: isFocused = false;
703: FocusEvent fe = CausedFocusEvent.retarget(e, this );
704: super .processFocusEvent(fe);
705:
706: }
707:
708: public boolean hasFocus() {
709: return isFocused;
710: }
711:
712: public void processInputMethodEventImpl(InputMethodEvent e) {
713: processInputMethodEvent(e);
714: }
715:
716: public void processMouseEventImpl(MouseEvent e) {
717: processMouseEvent(e);
718: }
719:
720: public void processMouseMotionEventImpl(MouseEvent e) {
721: processMouseMotionEvent(e);
722: }
723:
724: // Fix for 4915454 - override the default implementation to avoid
725: // loading SystemFlavorMap and associated classes.
726: public void setTransferHandler(TransferHandler newHandler) {
727: TransferHandler oldHandler = (TransferHandler) getClientProperty(XTextTransferHelper
728: .getTransferHandlerKey());
729: putClientProperty(XTextTransferHelper
730: .getTransferHandlerKey(), newHandler);
731:
732: firePropertyChange("transferHandler", oldHandler,
733: newHandler);
734: }
735:
736: public void setEchoChar(char c) {
737: super .setEchoChar(c);
738: ((AWTTextFieldUI) ui).installKeyboardActions();
739: }
740: }
741: }
|