1 /*
2  * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package sun.awt.X11;
27 
28 import java.awt.*;
29 import java.awt.peer.*;
30 import java.awt.event.*;
31 import java.awt.event.ActionEvent;
32 import java.awt.event.ActionListener;
33 import java.awt.event.TextEvent;
34 import javax.swing.text.*;
35 import javax.swing.event.DocumentListener;
36 import javax.swing.event.DocumentEvent;
37 import javax.swing.plaf.ComponentUI;
38 import javax.swing.InputMap;
39 import javax.swing.JPasswordField;
40 import javax.swing.SwingUtilities;
41 import javax.swing.TransferHandler;
42 
43 import java.awt.event.MouseEvent;
44 import java.awt.event.FocusEvent;
45 import java.awt.event.KeyEvent;
46 
47 import javax.swing.plaf.UIResource;
48 import javax.swing.UIDefaults;
49 import javax.swing.JTextField;
50 import javax.swing.JComponent;
51 import javax.swing.border.Border;
52 import com.sun.java.swing.plaf.motif.*;
53 import java.awt.im.InputMethodRequests;
54 
55 import sun.util.logging.PlatformLogger;
56 
57 import sun.awt.CausedFocusEvent;
58 import sun.awt.AWTAccessor;
59 
60 final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer {
61     private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XTextField");
62 
63     private String text;
64     private final XAWTTextField xtext;
65     private final boolean firstChangeSkipped;
66 
XTextFieldPeer(TextField target)67     XTextFieldPeer(TextField target) {
68         super(target);
69         text = target.getText();
70         xtext = new XAWTTextField(text,this, target.getParent());
71         xtext.getDocument().addDocumentListener(xtext);
72         xtext.setCursor(target.getCursor());
73         XToolkit.specialPeerMap.put(xtext,this);
74 
75         initTextField();
76         setText(target.getText());
77         if (target.echoCharIsSet()) {
78             setEchoChar(target.getEchoChar());
79         }
80         else setEchoChar((char)0);
81 
82         int start = target.getSelectionStart();
83         int end = target.getSelectionEnd();
84         // Fix for 5100200
85         // Restoring Motif behaviour
86         // Since the end position of the selected text can be greater then the length of the text,
87         // so we should set caret to max position of the text
88         setCaretPosition(Math.min(end, text.length()));
89         if (end > start) {
90             // Should be called after setText() and setCaretPosition()
91             select(start, end);
92         }
93 
94         setEditable(target.isEditable());
95 
96         // After this line we should not change the component's text
97         firstChangeSkipped = true;
98     }
99 
100     @Override
dispose()101     public void dispose() {
102         XToolkit.specialPeerMap.remove(xtext);
103         // visible caret has a timer thread which must be stopped
104         xtext.getCaret().setVisible(false);
105         xtext.removeNotify();
106         super.dispose();
107     }
108 
initTextField()109     void initTextField() {
110         setVisible(target.isVisible());
111 
112         setBounds(x, y, width, height, SET_BOUNDS);
113 
114         AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor();
115         foreground = compAccessor.getForeground(target);
116         if (foreground == null)
117             foreground = SystemColor.textText;
118 
119         setForeground(foreground);
120 
121         background = compAccessor.getBackground(target);
122         if (background == null) {
123             if (((TextField)target).isEditable()) background = SystemColor.text;
124             else background = SystemColor.control;
125         }
126         setBackground(background);
127 
128         if (!target.isBackgroundSet()) {
129             // This is a way to set the background color of the TextArea
130             // without calling setBackground - go through accessor
131             compAccessor.setBackground(target, background);
132         }
133         if (!target.isForegroundSet()) {
134             target.setForeground(SystemColor.textText);
135         }
136 
137         setFont(font);
138     }
139 
140     /**
141      * @see java.awt.peer.TextComponentPeer
142      */
143     @Override
setEditable(boolean editable)144     public void setEditable(boolean editable) {
145         if (xtext != null) {
146             xtext.setEditable(editable);
147             xtext.repaint();
148         }
149     }
150 
151     /**
152      * @see java.awt.peer.ComponentPeer
153      */
154     @Override
setEnabled(boolean enabled)155     public void setEnabled(boolean enabled) {
156         super.setEnabled(enabled);
157         if (xtext != null) {
158             xtext.setEnabled(enabled);
159             xtext.repaint();
160         }
161     }
162 
163     /**
164      * @see java.awt.peer.TextComponentPeer
165      */
166     @Override
getInputMethodRequests()167     public InputMethodRequests getInputMethodRequests() {
168         if (xtext != null) return xtext.getInputMethodRequests();
169         else  return null;
170 
171     }
172 
173     @Override
handleJavaInputMethodEvent(InputMethodEvent e)174     void handleJavaInputMethodEvent(InputMethodEvent e) {
175         if (xtext != null)
176             xtext.processInputMethodEventImpl(e);
177     }
178 
179     /**
180      * @see java.awt.peer.TextFieldPeer
181      */
182     @Override
setEchoChar(char c)183     public void setEchoChar(char c) {
184         if (xtext != null) {
185             xtext.setEchoChar(c);
186             xtext.putClientProperty("JPasswordField.cutCopyAllowed",
187                     xtext.echoCharIsSet() ? Boolean.FALSE : Boolean.TRUE);
188         }
189     }
190 
191     /**
192      * @see java.awt.peer.TextComponentPeer
193      */
194     @Override
getSelectionStart()195     public int getSelectionStart() {
196         return xtext.getSelectionStart();
197     }
198 
199     /**
200      * @see java.awt.peer.TextComponentPeer
201      */
202     @Override
getSelectionEnd()203     public int getSelectionEnd() {
204         return xtext.getSelectionEnd();
205     }
206 
207     /**
208      * @see java.awt.peer.TextComponentPeer
209      */
210     @Override
getText()211     public String getText() {
212         return xtext.getText();
213     }
214 
215     /**
216      * @see java.awt.peer.TextComponentPeer
217      */
218     @Override
setText(String text)219     public void setText(String text) {
220         setXAWTTextField(text);
221         repaint();
222     }
223 
setXAWTTextField(String txt)224     private void setXAWTTextField(String txt) {
225         text = txt;
226         if (xtext != null)  {
227             // JTextField.setText() posts two different events (remove & insert).
228             // Since we make no differences between text events,
229             // the document listener has to be disabled while
230             // JTextField.setText() is called.
231             xtext.getDocument().removeDocumentListener(xtext);
232             xtext.setText(txt);
233             if (firstChangeSkipped) {
234                 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED));
235             }
236             xtext.getDocument().addDocumentListener(xtext);
237             xtext.setCaretPosition(0);
238         }
239     }
240 
241     /**
242      * to be implemented.
243      * @see java.awt.peer.TextComponentPeer
244      */
245     @Override
setCaretPosition(int position)246     public void setCaretPosition(int position) {
247         if (xtext != null) xtext.setCaretPosition(position);
248     }
249 
repaintText()250     void repaintText() {
251         xtext.repaintNow();
252     }
253 
254     @Override
setBackground(Color c)255     public void setBackground(Color c) {
256         if (log.isLoggable(PlatformLogger.Level.FINE)) {
257             log.fine("target="+ target + ", old=" + background + ", new=" + c);
258         }
259         background = c;
260         if (xtext != null) {
261             xtext.setBackground(c);
262             xtext.setSelectedTextColor(c);
263         }
264         repaintText();
265     }
266 
267     @Override
setForeground(Color c)268     public void setForeground(Color c) {
269         foreground = c;
270         if (xtext != null) {
271             xtext.setForeground(foreground);
272             xtext.setSelectionColor(foreground);
273             xtext.setCaretColor(foreground);
274         }
275         repaintText();
276     }
277 
278     @Override
setFont(Font f)279     public void setFont(Font f) {
280         synchronized (getStateLock()) {
281             font = f;
282             if (xtext != null) {
283                 xtext.setFont(font);
284             }
285         }
286         xtext.validate();
287     }
288 
289     /**
290      * Deselects the the highlighted text.
291      */
deselect()292     public void deselect() {
293         int selStart=xtext.getSelectionStart();
294         int selEnd=xtext.getSelectionEnd();
295         if (selStart != selEnd) {
296             xtext.select(selStart,selStart);
297         }
298     }
299 
300     /**
301      * to be implemented.
302      * @see java.awt.peer.TextComponentPeer
303      */
304     @Override
getCaretPosition()305     public int getCaretPosition() {
306         return xtext.getCaretPosition();
307     }
308 
309     /**
310      * @see java.awt.peer.TextComponentPeer
311      */
312     @Override
select(int s, int e)313     public void select(int s, int e) {
314         xtext.select(s,e);
315         // Fixed 5100806
316         // We must take care that Swing components repainted correctly
317         xtext.repaint();
318     }
319 
320     @Override
getMinimumSize()321     public Dimension getMinimumSize() {
322         return xtext.getMinimumSize();
323     }
324 
325     @Override
getPreferredSize()326     public Dimension getPreferredSize() {
327         return xtext.getPreferredSize();
328     }
329 
330     @Override
getPreferredSize(int cols)331     public Dimension getPreferredSize(int cols) {
332         return getMinimumSize(cols);
333     }
334 
335     private static final int PADDING = 16;
336 
337     @Override
getMinimumSize(int cols)338     public Dimension getMinimumSize(int cols) {
339         Font f = xtext.getFont();
340         FontMetrics fm = xtext.getFontMetrics(f);
341         return new Dimension(fm.charWidth('0') * cols + 10,
342                              fm.getMaxDescent() + fm.getMaxAscent() + PADDING);
343     }
344 
345     @Override
isFocusable()346     public boolean isFocusable() {
347         return true;
348     }
349 
350     // NOTE: This method is called by privileged threads.
351     //       DO NOT INVOKE CLIENT CODE ON THIS THREAD!
action(final long when, final int modifiers)352     public void action(final long when, final int modifiers) {
353         postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED,
354                                   text, when,
355                                   modifiers));
356     }
357 
disposeImpl()358     protected void disposeImpl() {
359     }
360 
361     @Override
repaint()362     public void repaint() {
363         if (xtext  != null) xtext.repaint();
364     }
365     @Override
paintPeer(final Graphics g)366     void paintPeer(final Graphics g) {
367         if (xtext  != null) xtext.paint(g);
368     }
369 
370     @Override
print(Graphics g)371     public void print(Graphics g) {
372         if (xtext != null) {
373             xtext.print(g);
374         }
375     }
376 
377     @Override
focusLost(FocusEvent e)378     public void focusLost(FocusEvent e) {
379         super.focusLost(e);
380         xtext.forwardFocusLost(e);
381     }
382 
383     @Override
focusGained(FocusEvent e)384     public void focusGained(FocusEvent e) {
385         super.focusGained(e);
386         xtext.forwardFocusGained(e);
387     }
388 
389     @Override
handleJavaKeyEvent(KeyEvent e)390     void handleJavaKeyEvent(KeyEvent e) {
391         AWTAccessor.getComponentAccessor().processEvent(xtext,e);
392     }
393 
394 
395     @Override
handleJavaMouseEvent( MouseEvent mouseEvent )396     public void handleJavaMouseEvent( MouseEvent mouseEvent ) {
397         super.handleJavaMouseEvent(mouseEvent);
398         if (xtext != null)  {
399             mouseEvent.setSource(xtext);
400             int id = mouseEvent.getID();
401             if (id == MouseEvent.MOUSE_DRAGGED || id == MouseEvent.MOUSE_MOVED)
402                 xtext.processMouseMotionEventImpl(mouseEvent);
403             else
404                 xtext.processMouseEventImpl(mouseEvent);
405         }
406     }
407 
408     /**
409      * DEPRECATED
410      */
411     @Override
minimumSize()412     public Dimension minimumSize() {
413         return getMinimumSize();
414     }
415 
416     @Override
setVisible(boolean b)417     public void setVisible(boolean b) {
418         super.setVisible(b);
419         if (xtext != null) xtext.setVisible(b);
420     }
421 
422     @Override
setBounds(int x, int y, int width, int height, int op)423     public void setBounds(int x, int y, int width, int height, int op) {
424         super.setBounds(x, y, width, height, op);
425         if (xtext != null) {
426             /*
427              * Fixed 6277332, 6198290:
428              * the coordinates is coming (to peer): relatively to closest HW parent
429              * the coordinates is setting (to textField): relatively to closest ANY parent
430              * the parent of peer is target.getParent()
431              * the parent of textField is the same
432              * see 6277332, 6198290 for more information
433              */
434             int childX = x;
435             int childY = y;
436             Component parent = target.getParent();
437             // we up to heavyweight parent in order to be sure
438             // that the coordinates of the text pane is relatively to closest parent
439             while (parent.isLightweight()){
440                 childX -= parent.getX();
441                 childY -= parent.getY();
442                 parent = parent.getParent();
443             }
444             xtext.setBounds(childX,childY,width,height);
445             xtext.validate();
446         }
447     }
448 
449     final class AWTTextFieldUI extends MotifPasswordFieldUI {
450 
451         private JTextField jtf;
452 
453         @Override
getPropertyPrefix()454         protected String getPropertyPrefix() {
455             JTextComponent comp = getComponent();
456             if (comp instanceof JPasswordField && ((JPasswordField)comp).echoCharIsSet()) {
457                 return "PasswordField";
458             } else {
459                 return "TextField";
460             }
461         }
462 
463         @Override
installUI(JComponent c)464         public void installUI(JComponent c) {
465             super.installUI(c);
466 
467             jtf = (JTextField) c;
468 
469             JTextField editor = jtf;
470 
471             UIDefaults uidefaults = XToolkit.getUIDefaults();
472 
473             String prefix = getPropertyPrefix();
474             Font f = editor.getFont();
475             if ((f == null) || (f instanceof UIResource)) {
476                 editor.setFont(uidefaults.getFont(prefix + ".font"));
477             }
478 
479             Color bg = editor.getBackground();
480             if ((bg == null) || (bg instanceof UIResource)) {
481                 editor.setBackground(uidefaults.getColor(prefix + ".background"));
482             }
483 
484             Color fg = editor.getForeground();
485             if ((fg == null) || (fg instanceof UIResource)) {
486                 editor.setForeground(uidefaults.getColor(prefix + ".foreground"));
487             }
488 
489             Color color = editor.getCaretColor();
490             if ((color == null) || (color instanceof UIResource)) {
491                 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground"));
492             }
493 
494             Color s = editor.getSelectionColor();
495             if ((s == null) || (s instanceof UIResource)) {
496                 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground"));
497             }
498 
499             Color sfg = editor.getSelectedTextColor();
500             if ((sfg == null) || (sfg instanceof UIResource)) {
501                 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground"));
502             }
503 
504             Color dfg = editor.getDisabledTextColor();
505             if ((dfg == null) || (dfg instanceof UIResource)) {
506                 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground"));
507             }
508 
509             Border b = editor.getBorder();
510             if ((b == null) || (b instanceof UIResource)) {
511                 editor.setBorder(uidefaults.getBorder(prefix + ".border"));
512             }
513 
514             Insets margin = editor.getMargin();
515             if (margin == null || margin instanceof UIResource) {
516                 editor.setMargin(uidefaults.getInsets(prefix + ".margin"));
517             }
518         }
519 
520         @Override
installKeyboardActions()521         protected void installKeyboardActions() {
522             super.installKeyboardActions();
523 
524             JTextComponent comp = getComponent();
525 
526             UIDefaults uidefaults = XToolkit.getUIDefaults();
527 
528             String prefix = getPropertyPrefix();
529 
530             InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap");
531 
532             if (map != null) {
533                 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED,
534                                                  map);
535             }
536         }
537 
538         @Override
createCaret()539         protected Caret createCaret() {
540             return new XTextAreaPeer.XAWTCaret();
541         }
542     }
543 
544     final class XAWTTextField extends JPasswordField
545             implements ActionListener, DocumentListener {
546 
547         private boolean isFocused = false;
548         private final XComponentPeer peer;
549 
XAWTTextField(String text, XComponentPeer peer, Container parent)550         XAWTTextField(String text, XComponentPeer peer, Container parent) {
551             super(text);
552             this.peer = peer;
553             setDoubleBuffered(true);
554             setFocusable(false);
555             AWTAccessor.getComponentAccessor().setParent(this,parent);
556             setBackground(peer.getPeerBackground());
557             setForeground(peer.getPeerForeground());
558             setFont(peer.getPeerFont());
559             setCaretPosition(0);
560             addActionListener(this);
561             addNotify();
562 
563         }
564 
565         @Override
actionPerformed( ActionEvent actionEvent )566         public void actionPerformed( ActionEvent actionEvent ) {
567             peer.postEvent(new ActionEvent(peer.target,
568                                            ActionEvent.ACTION_PERFORMED,
569                                            getText(),
570                                            actionEvent.getWhen(),
571                                            actionEvent.getModifiers()));
572 
573         }
574 
575         @Override
insertUpdate(DocumentEvent e)576         public void insertUpdate(DocumentEvent e) {
577             if (peer != null) {
578                 peer.postEvent(new TextEvent(peer.target,
579                                              TextEvent.TEXT_VALUE_CHANGED));
580             }
581         }
582 
583         @Override
removeUpdate(DocumentEvent e)584         public void removeUpdate(DocumentEvent e) {
585             if (peer != null) {
586                 peer.postEvent(new TextEvent(peer.target,
587                                              TextEvent.TEXT_VALUE_CHANGED));
588             }
589         }
590 
591         @Override
changedUpdate(DocumentEvent e)592         public void changedUpdate(DocumentEvent e) {
593             if (peer != null) {
594                 peer.postEvent(new TextEvent(peer.target,
595                                              TextEvent.TEXT_VALUE_CHANGED));
596             }
597         }
598 
599         @Override
getPeer()600         public ComponentPeer getPeer() {
601             return (ComponentPeer) peer;
602         }
603 
repaintNow()604         public void repaintNow() {
605             paintImmediately(getBounds());
606         }
607 
608         @Override
getGraphics()609         public Graphics getGraphics() {
610             return peer.getGraphics();
611         }
612 
613         @Override
updateUI()614         public void updateUI() {
615             ComponentUI ui = new AWTTextFieldUI();
616             setUI(ui);
617         }
618 
forwardFocusGained( FocusEvent e)619         void forwardFocusGained( FocusEvent e) {
620             isFocused = true;
621             FocusEvent fe = CausedFocusEvent.retarget(e, this);
622             super.processFocusEvent(fe);
623         }
624 
forwardFocusLost( FocusEvent e)625         void forwardFocusLost( FocusEvent e) {
626             isFocused = false;
627             FocusEvent fe = CausedFocusEvent.retarget(e, this);
628             super.processFocusEvent(fe);
629 
630         }
631 
632         @Override
hasFocus()633         public boolean hasFocus() {
634             return isFocused;
635         }
636 
processInputMethodEventImpl(InputMethodEvent e)637         public void processInputMethodEventImpl(InputMethodEvent e) {
638             processInputMethodEvent(e);
639         }
640 
processMouseEventImpl(MouseEvent e)641         public void processMouseEventImpl(MouseEvent e) {
642             processMouseEvent(e);
643         }
644 
processMouseMotionEventImpl(MouseEvent e)645         public void processMouseMotionEventImpl(MouseEvent e) {
646             processMouseMotionEvent(e);
647         }
648 
649         // Fix for 4915454 - override the default implementation to avoid
650         // loading SystemFlavorMap and associated classes.
651         @Override
setTransferHandler(TransferHandler newHandler)652         public void setTransferHandler(TransferHandler newHandler) {
653             TransferHandler oldHandler = (TransferHandler)
654                 getClientProperty(AWTAccessor.getClientPropertyKeyAccessor()
655                                       .getJComponent_TRANSFER_HANDLER());
656             putClientProperty(AWTAccessor.getClientPropertyKeyAccessor()
657                                   .getJComponent_TRANSFER_HANDLER(),
658                               newHandler);
659 
660             firePropertyChange("transferHandler", oldHandler, newHandler);
661         }
662 
663         @Override
setEchoChar(char c)664         public void setEchoChar(char c) {
665             super.setEchoChar(c);
666             ((AWTTextFieldUI)ui).installKeyboardActions();
667         }
668     }
669 }
670