blob: 8d0d79e8a27940aa97512e039b4da6427fcc5d9a [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 2003-2007 Sun Microsystems, Inc. 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. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package sun.awt.X11;
27
28import java.awt.*;
29import java.awt.peer.*;
30import java.awt.event.*;
31import java.awt.event.ActionEvent;
32import java.awt.event.ActionListener;
33import java.awt.event.TextEvent;
34import javax.swing.text.*;
35import javax.swing.event.DocumentListener;
36import javax.swing.event.DocumentEvent;
37import javax.swing.plaf.ComponentUI;
38import javax.swing.InputMap;
39import javax.swing.JPasswordField;
40import javax.swing.SwingUtilities;
41import javax.swing.TransferHandler;
42
43import java.awt.event.MouseEvent;
44import java.awt.event.FocusEvent;
45import java.awt.event.KeyEvent;
46
47import javax.swing.plaf.UIResource;
48import javax.swing.UIDefaults;
49import javax.swing.JTextField;
50import javax.swing.JComponent;
51import javax.swing.border.Border;
52import com.sun.java.swing.plaf.motif.*;
53import java.awt.im.InputMethodRequests;
54
55import java.util.logging.*;
56import sun.awt.CausedFocusEvent;
57import sun.awt.ComponentAccessor;
58
59public class XTextFieldPeer extends XComponentPeer implements TextFieldPeer {
60 private static final Logger log = Logger.getLogger("sun.awt.X11.XTextField");
61
62 String text;
63 XAWTTextField xtext;
64
65 boolean firstChangeSkipped;
66
67 public XTextFieldPeer(TextField target) {
68 super(target);
69 int start, end;
70 firstChangeSkipped = false;
71 text = target.getText();
72 xtext = new XAWTTextField(text,this, target.getParent());
73 xtext.getDocument().addDocumentListener(xtext);
74 xtext.setCursor(target.getCursor());
75 target.enableInputMethods(true);
76 xtext.enableInputMethods(true);
77 XToolkit.specialPeerMap.put(xtext,this);
78
79 TextField txt = (TextField) target;
80 initTextField();
81 setText(txt.getText());
82 if (txt.echoCharIsSet()) {
83 setEchoChar(txt.getEchoChar());
84 }
85 else setEchoChar((char)0);
86
87 start = txt.getSelectionStart();
88 end = txt.getSelectionEnd();
89
90 if (end > start) {
91 select(start, end);
92 }
93 // Fix for 5100200
94 // Restoring Motif behaviour
95 // Since the end position of the selected text can be greater then the length of the text,
96 // so we should set caret to max position of the text
97 int caretPosition = Math.min(end, text.length());
98 setCaretPosition(caretPosition);
99
100 setEditable(txt.isEditable());
101
102 // After this line we should not change the component's text
103 firstChangeSkipped = true;
104 }
105
106 public void dispose() {
107 XToolkit.specialPeerMap.remove(xtext);
108 xtext.removeNotify();
109 super.dispose();
110 }
111
112 void initTextField() {
113 setVisible(target.isVisible());
114
115 setBounds(x, y, width, height, SET_BOUNDS);
116
117 foreground = ComponentAccessor.getForeground(target);
118 if (foreground == null)
119 foreground = SystemColor.textText;
120
121 setForeground(foreground);
122
123 background = ComponentAccessor.getBackground(target);
124 if (background == null) {
125 if (((TextField)target).isEditable()) background = SystemColor.text;
126 else background = SystemColor.control;
127 }
128 setBackground(background);
129
130 if (!target.isBackgroundSet()) {
131 // This is a way to set the background color of the TextArea
132 // without calling setBackground - go through reflection
133 ComponentAccessor.setBackground(target, background);
134 }
135 if (!target.isForegroundSet()) {
136 target.setForeground(SystemColor.textText);
137 }
138
139 setFont(font);
140 }
141
142
143 /**
144 * @see java.awt.peer.TextComponentPeer
145 */
146 public void setEditable(boolean editable) {
147 if (xtext != null) {
148 xtext.setEditable(editable);
149 xtext.repaint();
150 }
151 }
152
153 /**
154 * @see java.awt.peer.ComponentPeer
155 */
156 public void setEnabled(boolean enabled) {
157 super.setEnabled(enabled);
158 if (xtext != null) {
159 xtext.setEnabled(enabled);
160 xtext.repaint();
161 }
162 }
163
164 /**
165 * @see java.awt.peer.TextComponentPeer
166 */
167
168 public InputMethodRequests getInputMethodRequests() {
169 if (xtext != null) return xtext.getInputMethodRequests();
170 else return null;
171
172 }
173
174 void handleJavaInputMethodEvent(InputMethodEvent e) {
175 if (xtext != null)
176 xtext.processInputMethodEventImpl(e);
177 }
178
179
180 /**
181 * @see java.awt.peer.TextFieldPeer
182 */
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 public int getSelectionStart() {
195 return xtext.getSelectionStart();
196 }
197
198 /**
199 * @see java.awt.peer.TextComponentPeer
200 */
201 public int getSelectionEnd() {
202 return xtext.getSelectionEnd();
203 }
204
205 /**
206 * @see java.awt.peer.TextComponentPeer
207 */
208 public String getText() {
209 return xtext.getText();
210 }
211
212 /**
213 * @see java.awt.peer.TextComponentPeer
214 */
215 public void setText(String txt) {
216 setXAWTTextField(txt);
217 repaint();
218 }
219
220 protected boolean setXAWTTextField(String txt) {
221 text = txt;
222 if (xtext != null) {
223 // JTextField.setText() posts two different events (remove & insert).
224 // Since we make no differences between text events,
225 // the document listener has to be disabled while
226 // JTextField.setText() is called.
227 xtext.getDocument().removeDocumentListener(xtext);
228 xtext.setText(txt);
229 if (firstChangeSkipped) {
230 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED));
231 }
232 xtext.getDocument().addDocumentListener(xtext);
233 xtext.setCaretPosition(0);
234 }
235 return true;
236 }
237
238 /**
239 * to be implemented.
240 * @see java.awt.peer.TextComponentPeer
241 */
242 public void setCaretPosition(int position) {
243 if (xtext != null) xtext.setCaretPosition(position);
244 }
245
246 /**
247 * DEPRECATED
248 * @see java.awt.peer.TextFieldPeer
249 */
250 public void setEchoCharacter(char c) {
251 setEchoChar(c);
252 }
253
254 void repaintText() {
255 xtext.repaintNow();
256 }
257
258 public void setBackground(Color c) {
259 if (log.isLoggable(Level.FINE)) log.fine("target="+ target + ", old=" + background + ", new=" + c);
260 background = c;
261 if (xtext != null) {
262 xtext.setBackground(c);
263 xtext.setSelectedTextColor(c);
264 }
265 repaintText();
266 }
267
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 public void setFont(Font f) {
279 synchronized (getStateLock()) {
280 font = f;
281 if (xtext != null) {
282 xtext.setFont(font);
283 }
284 }
285 xtext.validate();
286 }
287
288 /**
289 * DEPRECATED
290 * @see java.awt.peer.TextFieldPeer
291 */
292 public Dimension preferredSize(int cols) {
293 return getPreferredSize(cols);
294 }
295
296 /**
297 * Deselects the the highlighted text.
298 */
299 public void deselect() {
300 int selStart=xtext.getSelectionStart();
301 int selEnd=xtext.getSelectionEnd();
302 if (selStart != selEnd) {
303 xtext.select(selStart,selStart);
304 }
305 }
306
307
308 /**
309 * to be implemented.
310 * @see java.awt.peer.TextComponentPeer
311 */
312 public int getCaretPosition() {
313 return xtext.getCaretPosition();
314 }
315
316
317
318 /**
319 * @see java.awt.peer.TextComponentPeer
320 */
321 public void select(int s, int e) {
322 xtext.select(s,e);
323 // Fixed 5100806
324 // We must take care that Swing components repainted correctly
325 xtext.repaint();
326 }
327
328
329 public Dimension getMinimumSize() {
330 return xtext.getMinimumSize();
331 }
332
333 public Dimension getPreferredSize() {
334 return xtext.getPreferredSize();
335 }
336
337 public Dimension getPreferredSize(int cols) {
338 return getMinimumSize(cols);
339 }
340
341 private static final int PADDING = 16;
342
343 public Dimension getMinimumSize(int cols) {
344 Font f = xtext.getFont();
345 FontMetrics fm = xtext.getFontMetrics(f);
346 return new Dimension(fm.charWidth('0') * cols + 10,
347 fm.getMaxDescent() + fm.getMaxAscent() + PADDING);
348
349 }
350
351 public boolean isFocusable() {
352 return true;
353 }
354
355 // NOTE: This method is called by privileged threads.
356 // DO NOT INVOKE CLIENT CODE ON THIS THREAD!
357 public void action(final long when, final int modifiers) {
358 postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED,
359 text, when,
360 modifiers));
361 }
362
363
364 protected void disposeImpl() {
365 }
366
367
368 public void repaint() {
369 if (xtext != null) xtext.repaint();
370 }
371
372 public void paint(Graphics g) {
373 if (xtext != null) xtext.paint(g);
374 }
375
376
377 public void print(Graphics g) {
378 if (xtext != null) {
379 xtext.print(g);
380 }
381 }
382
383 public void focusLost(FocusEvent e) {
384 super.focusLost(e);
385 xtext.forwardFocusLost(e);
386 }
387
388 public void focusGained(FocusEvent e) {
389 super.focusGained(e);
390 xtext.forwardFocusGained(e);
391 }
392
393 void handleJavaKeyEvent(KeyEvent e) {
394 ComponentAccessor.processEvent(xtext,e);
395 }
396
397
398 public void handleJavaMouseEvent( MouseEvent mouseEvent ) {
399 super.handleJavaMouseEvent(mouseEvent);
400 if (xtext != null) {
401 mouseEvent.setSource(xtext);
402 int id = mouseEvent.getID();
403 if (id == MouseEvent.MOUSE_DRAGGED || id == MouseEvent.MOUSE_MOVED)
404 xtext.processMouseMotionEventImpl(mouseEvent);
405 else
406 xtext.processMouseEventImpl(mouseEvent);
407 }
408 }
409
410
411 /**
412 * DEPRECATED
413 */
414 public Dimension minimumSize() {
415 return getMinimumSize();
416 }
417
418 /**
419 * DEPRECATED
420 */
421 public Dimension minimumSize(int cols) {
422 return getMinimumSize(cols);
423 }
424
425 public void setVisible(boolean b) {
426 super.setVisible(b);
427 if (xtext != null) xtext.setVisible(b);
428 }
429
430 public void setBounds(int x, int y, int width, int height, int op) {
431 super.setBounds(x, y, width, height, op);
432 if (xtext != null) {
433 /*
434 * Fixed 6277332, 6198290:
435 * the coordinates is coming (to peer): relatively to closest HW parent
436 * the coordinates is setting (to textField): relatively to closest ANY parent
437 * the parent of peer is target.getParent()
438 * the parent of textField is the same
439 * see 6277332, 6198290 for more information
440 */
441 int childX = x;
442 int childY = y;
443 Component parent = target.getParent();
444 // we up to heavyweight parent in order to be sure
445 // that the coordinates of the text pane is relatively to closest parent
446 while (parent.isLightweight()){
447 childX -= parent.getX();
448 childY -= parent.getY();
449 parent = parent.getParent();
450 }
451 xtext.setBounds(childX,childY,width,height);
452 xtext.validate();
453 }
454 }
455
456
457 //
458 // Accessibility support
459 //
460
461 // stub functions: to be fully implemented in a future release
462 public int getIndexAtPoint(int x, int y) { return -1; }
463 public Rectangle getCharacterBounds(int i) { return null; }
464 public long filterEvents(long mask) { return 0; }
465
466
467 /* To be fully implemented in a future release
468
469 int oldSelectionStart;
470 int oldSelectionEnd;
471
472 public native int getIndexAtPoint(int x, int y);
473 public native Rectangle getCharacterBounds(int i);
474 public native long filterEvents(long mask);
475
476 /**
477 * Handle a change in the text selection endpoints
478 * (Note: could be simply a change in the caret location)
479 *
480 public void selectionValuesChanged(int start, int end) {
481 return; // Need to write implemetation of this.
482 }
483 */
484
485
486 class AWTTextFieldUI extends MotifPasswordFieldUI {
487
488 /**
489 * Creates a UI for a JTextField.
490 *
491 * @param c the text field
492 * @return the UI
493 */
494 JTextField jtf;
495
496
497 protected String getPropertyPrefix() {
498 JTextComponent comp = getComponent();
499 if (comp instanceof JPasswordField && ((JPasswordField)comp).echoCharIsSet()) {
500 return "PasswordField";
501 } else {
502 return "TextField";
503 }
504 }
505
506 public void installUI(JComponent c) {
507 super.installUI(c);
508
509 jtf = (JTextField) c;
510
511 JTextField editor = jtf;
512
513 UIDefaults uidefaults = XToolkit.getUIDefaults();
514
515 String prefix = getPropertyPrefix();
516 Font f = editor.getFont();
517 if ((f == null) || (f instanceof UIResource)) {
518 editor.setFont(uidefaults.getFont(prefix + ".font"));
519 }
520
521 Color bg = editor.getBackground();
522 if ((bg == null) || (bg instanceof UIResource)) {
523 editor.setBackground(uidefaults.getColor(prefix + ".background"));
524 }
525
526 Color fg = editor.getForeground();
527 if ((fg == null) || (fg instanceof UIResource)) {
528 editor.setForeground(uidefaults.getColor(prefix + ".foreground"));
529 }
530
531 Color color = editor.getCaretColor();
532 if ((color == null) || (color instanceof UIResource)) {
533 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground"));
534 }
535
536 Color s = editor.getSelectionColor();
537 if ((s == null) || (s instanceof UIResource)) {
538 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground"));
539 }
540
541 Color sfg = editor.getSelectedTextColor();
542 if ((sfg == null) || (sfg instanceof UIResource)) {
543 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground"));
544 }
545
546 Color dfg = editor.getDisabledTextColor();
547 if ((dfg == null) || (dfg instanceof UIResource)) {
548 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground"));
549 }
550
551 Border b = editor.getBorder();
552 if ((b == null) || (b instanceof UIResource)) {
553 editor.setBorder(uidefaults.getBorder(prefix + ".border"));
554 }
555
556 Insets margin = editor.getMargin();
557 if (margin == null || margin instanceof UIResource) {
558 editor.setMargin(uidefaults.getInsets(prefix + ".margin"));
559 }
560 }
561
562 protected void installKeyboardActions() {
563 super.installKeyboardActions();
564
565 JTextComponent comp = getComponent();
566
567 UIDefaults uidefaults = XToolkit.getUIDefaults();
568
569 String prefix = getPropertyPrefix();
570
571 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap");
572
573 if (map != null) {
574 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED,
575 map);
576 }
577 }
578
579 protected Caret createCaret() {
580 return new XAWTCaret();
581 }
582 }
583
584 class XAWTCaret extends DefaultCaret {
585 public void focusGained(FocusEvent e) {
586 super.focusGained(e);
587 getComponent().repaint();
588 }
589
590 public void focusLost(FocusEvent e) {
591 super.focusLost(e);
592 getComponent().repaint();
593 }
594
595 // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit
596 // Restoring Motif behaviour
597 // If the text is unhighlighted then we should sets the selection range to zero
598 public void setSelectionVisible(boolean vis) {
599 if (vis){
600 super.setSelectionVisible(vis);
601 }else{
602 // In order to de-select the selection
603 setDot(getDot());
604 }
605 }
606 }
607
608 class XAWTTextField extends JPasswordField
609 implements ActionListener,
610 DocumentListener
611 {
612
613 boolean isFocused = false;
614
615 XComponentPeer peer;
616
617 public XAWTTextField(String text, XComponentPeer peer, Container parent) {
618 super(text);
619 this.peer = peer;
620 setDoubleBuffered(true);
621 setFocusable(false);
622 ComponentAccessor.setParent(this,parent);
623 setBackground(peer.getPeerBackground());
624 setForeground(peer.getPeerForeground());
625 setFont(peer.getPeerFont());
626 setCaretPosition(0);
627 addActionListener(this);
628 addNotify();
629
630 }
631
632 public void actionPerformed( ActionEvent actionEvent ) {
633 peer.postEvent(new ActionEvent(peer.target,
634 ActionEvent.ACTION_PERFORMED,
635 getText(),
636 actionEvent.getWhen(),
637 actionEvent.getModifiers()));
638
639 }
640
641 public void insertUpdate(DocumentEvent e) {
642 if (peer != null) {
643 peer.postEvent(new TextEvent(peer.target,
644 TextEvent.TEXT_VALUE_CHANGED));
645 }
646 }
647
648 public void removeUpdate(DocumentEvent e) {
649 if (peer != null) {
650 peer.postEvent(new TextEvent(peer.target,
651 TextEvent.TEXT_VALUE_CHANGED));
652 }
653 }
654
655 public void changedUpdate(DocumentEvent e) {
656 if (peer != null) {
657 peer.postEvent(new TextEvent(peer.target,
658 TextEvent.TEXT_VALUE_CHANGED));
659 }
660 }
661
662 public ComponentPeer getPeer() {
663 return (ComponentPeer) peer;
664 }
665
666
667 public void repaintNow() {
668 paintImmediately(getBounds());
669 }
670
671 public Graphics getGraphics() {
672 return peer.getGraphics();
673 }
674
675 public void updateUI() {
676 ComponentUI ui = new AWTTextFieldUI();
677 setUI(ui);
678 }
679
680
681 void forwardFocusGained( FocusEvent e) {
682 isFocused = true;
683 FocusEvent fe = CausedFocusEvent.retarget(e, this);
684 super.processFocusEvent(fe);
685
686 }
687
688
689 void forwardFocusLost( FocusEvent e) {
690 isFocused = false;
691 FocusEvent fe = CausedFocusEvent.retarget(e, this);
692 super.processFocusEvent(fe);
693
694 }
695
696 public boolean hasFocus() {
697 return isFocused;
698 }
699
700
701 public void processInputMethodEventImpl(InputMethodEvent e) {
702 processInputMethodEvent(e);
703 }
704
705 public void processMouseEventImpl(MouseEvent e) {
706 processMouseEvent(e);
707 }
708
709 public void processMouseMotionEventImpl(MouseEvent e) {
710 processMouseMotionEvent(e);
711 }
712
713 // Fix for 4915454 - override the default implementation to avoid
714 // loading SystemFlavorMap and associated classes.
715 public void setTransferHandler(TransferHandler newHandler) {
716 TransferHandler oldHandler = (TransferHandler)
717 getClientProperty(XTextTransferHelper.getTransferHandlerKey());
718 putClientProperty(XTextTransferHelper.getTransferHandlerKey(),
719 newHandler);
720
721 firePropertyChange("transferHandler", oldHandler, newHandler);
722 }
723
724 public void setEchoChar(char c) {
725 super.setEchoChar(c);
726 ((AWTTextFieldUI)ui).installKeyboardActions();
727 }
728 }
729}