1 /* 2 * Copyright (c) 2003, 2007, 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 public class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { 61 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XTextField"); 62 63 String text; 64 XAWTTextField xtext; 65 66 boolean firstChangeSkipped; 67 68 public XTextFieldPeer(TextField target) { 69 super(target); 70 int start, end; 71 firstChangeSkipped = false; 72 text = target.getText(); 73 xtext = new XAWTTextField(text,this, target.getParent()); 74 xtext.getDocument().addDocumentListener(xtext); 75 xtext.setCursor(target.getCursor()); 76 xtext.enableInputMethods(AWTAccessor.getComponentAccessor().areInputMethodsEnabled(target)); 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 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 118 foreground = compAccessor.getForeground(target); 119 if (foreground == null) 120 foreground = SystemColor.textText; 121 122 setForeground(foreground); 123 124 background = compAccessor.getBackground(target); 125 if (background == null) { 126 if (((TextField)target).isEditable()) background = SystemColor.text; 127 else background = SystemColor.control; 128 } 129 setBackground(background); 130 131 if (!target.isBackgroundSet()) { 132 // This is a way to set the background color of the TextArea 133 // without calling setBackground - go through accessor 134 compAccessor.setBackground(target, background); 135 } 136 if (!target.isForegroundSet()) { 137 target.setForeground(SystemColor.textText); 138 } 139 140 setFont(font); 141 } 142 143 144 /** 145 * @see java.awt.peer.TextComponentPeer 146 */ 147 public void setEditable(boolean editable) { 148 if (xtext != null) { 149 xtext.setEditable(editable); 150 xtext.repaint(); 151 } 152 } 153 154 /** 155 * @see java.awt.peer.ComponentPeer 156 */ 157 public void setEnabled(boolean enabled) { 158 super.setEnabled(enabled); 159 if (xtext != null) { 160 xtext.setEnabled(enabled); 161 xtext.repaint(); 162 } 163 } 164 165 /** 166 * @see java.awt.peer.TextComponentPeer 167 */ 168 169 public InputMethodRequests getInputMethodRequests() { 170 if (xtext != null) return xtext.getInputMethodRequests(); 171 else return null; 172 173 } 174 175 void handleJavaInputMethodEvent(InputMethodEvent e) { 176 if (xtext != null) 177 xtext.processInputMethodEventImpl(e); 178 } 179 180 181 /** 182 * @see java.awt.peer.TextFieldPeer 183 */ 184 public void setEchoChar(char c) { 185 if (xtext != null) { 186 xtext.setEchoChar(c); 187 xtext.putClientProperty("JPasswordField.cutCopyAllowed", 188 xtext.echoCharIsSet() ? Boolean.FALSE : Boolean.TRUE); 189 } 190 } 191 192 /** 193 * @see java.awt.peer.TextComponentPeer 194 */ 195 public int getSelectionStart() { 196 return xtext.getSelectionStart(); 197 } 198 199 /** 200 * @see java.awt.peer.TextComponentPeer 201 */ 202 public int getSelectionEnd() { 203 return xtext.getSelectionEnd(); 204 } 205 206 /** 207 * @see java.awt.peer.TextComponentPeer 208 */ 209 public String getText() { 210 return xtext.getText(); 211 } 212 213 /** 214 * @see java.awt.peer.TextComponentPeer 215 */ 216 public void setText(String txt) { 217 setXAWTTextField(txt); 218 repaint(); 219 } 220 221 protected boolean setXAWTTextField(String txt) { 222 text = txt; 223 if (xtext != null) { 224 // JTextField.setText() posts two different events (remove & insert). 225 // Since we make no differences between text events, 226 // the document listener has to be disabled while 227 // JTextField.setText() is called. 228 xtext.getDocument().removeDocumentListener(xtext); 229 xtext.setText(txt); 230 if (firstChangeSkipped) { 231 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 232 } 233 xtext.getDocument().addDocumentListener(xtext); 234 xtext.setCaretPosition(0); 235 } 236 return true; 237 } 238 239 /** 240 * to be implemented. 241 * @see java.awt.peer.TextComponentPeer 242 */ 243 public void setCaretPosition(int position) { 244 if (xtext != null) xtext.setCaretPosition(position); 245 } 246 247 /** 248 * DEPRECATED 249 * @see java.awt.peer.TextFieldPeer 250 */ 251 public void setEchoCharacter(char c) { 252 setEchoChar(c); 253 } 254 255 void repaintText() { 256 xtext.repaintNow(); 257 } 258 259 public void setBackground(Color c) { 260 if (log.isLoggable(PlatformLogger.FINE)) log.fine("target="+ target + ", old=" + background + ", new=" + c); 261 background = c; 262 if (xtext != null) { 263 xtext.setBackground(c); 264 xtext.setSelectedTextColor(c); 265 } 266 repaintText(); 267 } 268 269 public void setForeground(Color c) { 270 foreground = c; 271 if (xtext != null) { 272 xtext.setForeground(foreground); 273 xtext.setSelectionColor(foreground); 274 xtext.setCaretColor(foreground); 275 } 276 repaintText(); 277 } 278 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 * DEPRECATED 291 * @see java.awt.peer.TextFieldPeer 292 */ 293 public Dimension preferredSize(int cols) { 294 return getPreferredSize(cols); 295 } 296 297 /** 298 * Deselects the the highlighted text. 299 */ 300 public void deselect() { 301 int selStart=xtext.getSelectionStart(); 302 int selEnd=xtext.getSelectionEnd(); 303 if (selStart != selEnd) { 304 xtext.select(selStart,selStart); 305 } 306 } 307 308 309 /** 310 * to be implemented. 311 * @see java.awt.peer.TextComponentPeer 312 */ 313 public int getCaretPosition() { 314 return xtext.getCaretPosition(); 315 } 316 317 318 319 /** 320 * @see java.awt.peer.TextComponentPeer 321 */ 322 public void select(int s, int e) { 323 xtext.select(s,e); 324 // Fixed 5100806 325 // We must take care that Swing components repainted correctly 326 xtext.repaint(); 327 } 328 329 330 public Dimension getMinimumSize() { 331 return xtext.getMinimumSize(); 332 } 333 334 public Dimension getPreferredSize() { 335 return xtext.getPreferredSize(); 336 } 337 338 public Dimension getPreferredSize(int cols) { 339 return getMinimumSize(cols); 340 } 341 342 private static final int PADDING = 16; 343 344 public Dimension getMinimumSize(int cols) { 345 Font f = xtext.getFont(); 346 FontMetrics fm = xtext.getFontMetrics(f); 347 return new Dimension(fm.charWidth('0') * cols + 10, 348 fm.getMaxDescent() + fm.getMaxAscent() + PADDING); 349 350 } 351 352 public boolean isFocusable() { 353 return true; 354 } 355 356 // NOTE: This method is called by privileged threads. 357 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 358 public void action(final long when, final int modifiers) { 359 postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, 360 text, when, 361 modifiers)); 362 } 363 364 365 protected void disposeImpl() { 366 } 367 368 369 public void repaint() { 370 if (xtext != null) xtext.repaint(); 371 } 372 @Override 373 void paintPeer(final Graphics g) { 374 if (xtext != null) xtext.paint(g); 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 AWTAccessor.getComponentAccessor().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 AWTAccessor.getComponentAccessor().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 }