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