1 /* 2 * Copyright (c) 2003, 2014, 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 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 AWTAccessor.getComponentAccessor().setPeer(xtext, this); 99 } 100 101 @Override 102 public void dispose() { 103 XToolkit.specialPeerMap.remove(xtext); 104 // visible caret has a timer thread which must be stopped 105 xtext.getCaret().setVisible(false); 106 super.dispose(); 107 } 108 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 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 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 167 public InputMethodRequests getInputMethodRequests() { 168 if (xtext != null) return xtext.getInputMethodRequests(); 169 else return null; 170 171 } 172 173 @Override 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 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 195 public int getSelectionStart() { 196 return xtext.getSelectionStart(); 197 } 198 199 /** 200 * @see java.awt.peer.TextComponentPeer 201 */ 202 @Override 203 public int getSelectionEnd() { 204 return xtext.getSelectionEnd(); 205 } 206 207 /** 208 * @see java.awt.peer.TextComponentPeer 209 */ 210 @Override 211 @SuppressWarnings("deprecation") 212 public String getText() { 213 return xtext.getText(); 214 } 215 216 /** 217 * @see java.awt.peer.TextComponentPeer 218 */ 219 @Override 220 public void setText(String text) { 221 setXAWTTextField(text); 222 repaint(); 223 } 224 225 private void 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, TextEvent.TEXT_VALUE_CHANGED)); 236 } 237 xtext.getDocument().addDocumentListener(xtext); 238 xtext.setCaretPosition(0); 239 } 240 } 241 242 /** 243 * to be implemented. 244 * @see java.awt.peer.TextComponentPeer 245 */ 246 @Override 247 public void setCaretPosition(int position) { 248 if (xtext != null) xtext.setCaretPosition(position); 249 } 250 251 void repaintText() { 252 xtext.repaintNow(); 253 } 254 255 @Override 256 public void setBackground(Color c) { 257 if (log.isLoggable(PlatformLogger.Level.FINE)) { 258 log.fine("target="+ target + ", old=" + background + ", new=" + c); 259 } 260 background = c; 261 if (xtext != null) { 262 xtext.setBackground(c); 263 xtext.setSelectedTextColor(c); 264 } 265 repaintText(); 266 } 267 268 @Override 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 @Override 280 public void setFont(Font f) { 281 synchronized (getStateLock()) { 282 font = f; 283 if (xtext != null) { 284 xtext.setFont(font); 285 } 286 } 287 xtext.validate(); 288 } 289 290 /** 291 * Deselects the highlighted text. 292 */ 293 public void deselect() { 294 int selStart=xtext.getSelectionStart(); 295 int selEnd=xtext.getSelectionEnd(); 296 if (selStart != selEnd) { 297 xtext.select(selStart,selStart); 298 } 299 } 300 301 /** 302 * to be implemented. 303 * @see java.awt.peer.TextComponentPeer 304 */ 305 @Override 306 public int getCaretPosition() { 307 return xtext.getCaretPosition(); 308 } 309 310 /** 311 * @see java.awt.peer.TextComponentPeer 312 */ 313 @Override 314 public void select(int s, int e) { 315 xtext.select(s,e); 316 // Fixed 5100806 317 // We must take care that Swing components repainted correctly 318 xtext.repaint(); 319 } 320 321 @Override 322 public Dimension getMinimumSize() { 323 return xtext.getMinimumSize(); 324 } 325 326 @Override 327 public Dimension getPreferredSize() { 328 return xtext.getPreferredSize(); 329 } 330 331 @Override 332 public Dimension getPreferredSize(int cols) { 333 return getMinimumSize(cols); 334 } 335 336 private static final int PADDING = 16; 337 338 @Override 339 public Dimension getMinimumSize(int cols) { 340 Font f = xtext.getFont(); 341 FontMetrics fm = xtext.getFontMetrics(f); 342 return new Dimension(fm.charWidth('0') * cols + 10, 343 fm.getMaxDescent() + fm.getMaxAscent() + PADDING); 344 } 345 346 @Override 347 public boolean isFocusable() { 348 return true; 349 } 350 351 // NOTE: This method is called by privileged threads. 352 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! 353 public void action(final long when, final int modifiers) { 354 postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, 355 text, when, 356 modifiers)); 357 } 358 359 protected void disposeImpl() { 360 } 361 362 @Override 363 public void repaint() { 364 if (xtext != null) xtext.repaint(); 365 } 366 @Override 367 void paintPeer(final Graphics g) { 368 if (xtext != null) xtext.paint(g); 369 } 370 371 @Override 372 public void print(Graphics g) { 373 if (xtext != null) { 374 xtext.print(g); 375 } 376 } 377 378 @Override 379 public void focusLost(FocusEvent e) { 380 super.focusLost(e); 381 xtext.forwardFocusLost(e); 382 } 383 384 @Override 385 public void focusGained(FocusEvent e) { 386 super.focusGained(e); 387 xtext.forwardFocusGained(e); 388 } 389 390 @Override 391 void handleJavaKeyEvent(KeyEvent e) { 392 AWTAccessor.getComponentAccessor().processEvent(xtext,e); 393 } 394 395 396 @Override 397 public void handleJavaMouseEvent( MouseEvent mouseEvent ) { 398 super.handleJavaMouseEvent(mouseEvent); 399 if (xtext != null) { 400 mouseEvent.setSource(xtext); 401 int id = mouseEvent.getID(); 402 if (id == MouseEvent.MOUSE_DRAGGED || id == MouseEvent.MOUSE_MOVED) 403 xtext.processMouseMotionEventImpl(mouseEvent); 404 else 405 xtext.processMouseEventImpl(mouseEvent); 406 } 407 } 408 409 /** 410 * DEPRECATED 411 */ 412 @Override 413 public Dimension minimumSize() { 414 return getMinimumSize(); 415 } 416 417 @Override 418 public void setVisible(boolean b) { 419 super.setVisible(b); 420 if (xtext != null) xtext.setVisible(b); 421 } 422 423 @Override 424 public void setBounds(int x, int y, int width, int height, int op) { 425 super.setBounds(x, y, width, height, op); 426 if (xtext != null) { 427 /* 428 * Fixed 6277332, 6198290: 429 * the coordinates is coming (to peer): relatively to closest HW parent 430 * the coordinates is setting (to textField): relatively to closest ANY parent 431 * the parent of peer is target.getParent() 432 * the parent of textField is the same 433 * see 6277332, 6198290 for more information 434 */ 435 int childX = x; 436 int childY = y; 437 Component parent = target.getParent(); 438 // we up to heavyweight parent in order to be sure 439 // that the coordinates of the text pane is relatively to closest parent 440 while (parent.isLightweight()){ 441 childX -= parent.getX(); 442 childY -= parent.getY(); 443 parent = parent.getParent(); 444 } 445 xtext.setBounds(childX,childY,width,height); 446 xtext.validate(); 447 } 448 } 449 450 final class AWTTextFieldUI extends MotifPasswordFieldUI { 451 452 private JTextField jtf; 453 454 @Override 455 protected String getPropertyPrefix() { 456 JTextComponent comp = getComponent(); 457 if (comp instanceof JPasswordField && ((JPasswordField)comp).echoCharIsSet()) { 458 return "PasswordField"; 459 } else { 460 return "TextField"; 461 } 462 } 463 464 @Override 465 public void installUI(JComponent c) { 466 super.installUI(c); 467 468 jtf = (JTextField) c; 469 470 JTextField editor = jtf; 471 472 UIDefaults uidefaults = XToolkit.getUIDefaults(); 473 474 String prefix = getPropertyPrefix(); 475 Font f = editor.getFont(); 476 if ((f == null) || (f instanceof UIResource)) { 477 editor.setFont(uidefaults.getFont(prefix + ".font")); 478 } 479 480 Color bg = editor.getBackground(); 481 if ((bg == null) || (bg instanceof UIResource)) { 482 editor.setBackground(uidefaults.getColor(prefix + ".background")); 483 } 484 485 Color fg = editor.getForeground(); 486 if ((fg == null) || (fg instanceof UIResource)) { 487 editor.setForeground(uidefaults.getColor(prefix + ".foreground")); 488 } 489 490 Color color = editor.getCaretColor(); 491 if ((color == null) || (color instanceof UIResource)) { 492 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); 493 } 494 495 Color s = editor.getSelectionColor(); 496 if ((s == null) || (s instanceof UIResource)) { 497 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); 498 } 499 500 Color sfg = editor.getSelectedTextColor(); 501 if ((sfg == null) || (sfg instanceof UIResource)) { 502 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); 503 } 504 505 Color dfg = editor.getDisabledTextColor(); 506 if ((dfg == null) || (dfg instanceof UIResource)) { 507 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); 508 } 509 510 Border b = editor.getBorder(); 511 if ((b == null) || (b instanceof UIResource)) { 512 editor.setBorder(uidefaults.getBorder(prefix + ".border")); 513 } 514 515 Insets margin = editor.getMargin(); 516 if (margin == null || margin instanceof UIResource) { 517 editor.setMargin(uidefaults.getInsets(prefix + ".margin")); 518 } 519 } 520 521 @Override 522 protected void installKeyboardActions() { 523 super.installKeyboardActions(); 524 525 JTextComponent comp = getComponent(); 526 527 UIDefaults uidefaults = XToolkit.getUIDefaults(); 528 529 String prefix = getPropertyPrefix(); 530 531 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); 532 533 if (map != null) { 534 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, 535 map); 536 } 537 } 538 539 @Override 540 protected Caret createCaret() { 541 return new XTextAreaPeer.XAWTCaret(); 542 } 543 } 544 545 @SuppressWarnings("serial") // JDK-implementation class 546 final class XAWTTextField extends JPasswordField 547 implements ActionListener, DocumentListener { 548 549 private boolean isFocused = false; 550 private final XComponentPeer xwin; 551 552 XAWTTextField(String text, XComponentPeer xwin, Container parent) { 553 super(text); 554 this.xwin = xwin; 555 setDoubleBuffered(true); 556 setFocusable(false); 557 AWTAccessor.getComponentAccessor().setParent(this,parent); 558 setBackground(xwin.getPeerBackground()); 559 setForeground(xwin.getPeerForeground()); 560 setFont(xwin.getPeerFont()); 561 setCaretPosition(0); 562 addActionListener(this); 563 addNotify(); 564 } 565 566 @Override 567 @SuppressWarnings("deprecation") 568 public void actionPerformed( ActionEvent actionEvent ) { 569 xwin.postEvent( 570 new ActionEvent(xwin.target, ActionEvent.ACTION_PERFORMED, 571 getText(), actionEvent.getWhen(), 572 actionEvent.getModifiers())); 573 574 } 575 576 @Override 577 public void insertUpdate(DocumentEvent e) { 578 if (xwin != null) { 579 xwin.postEvent(new TextEvent(xwin.target, 580 TextEvent.TEXT_VALUE_CHANGED)); 581 } 582 } 583 584 @Override 585 public void removeUpdate(DocumentEvent e) { 586 if (xwin != null) { 587 xwin.postEvent(new TextEvent(xwin.target, 588 TextEvent.TEXT_VALUE_CHANGED)); 589 } 590 } 591 592 @Override 593 public void changedUpdate(DocumentEvent e) { 594 if (xwin != null) { 595 xwin.postEvent(new TextEvent(xwin.target, 596 TextEvent.TEXT_VALUE_CHANGED)); 597 } 598 } 599 600 public void repaintNow() { 601 paintImmediately(getBounds()); 602 } 603 604 @Override 605 public Graphics getGraphics() { 606 return xwin.getGraphics(); 607 } 608 609 @Override 610 public void updateUI() { 611 ComponentUI ui = new AWTTextFieldUI(); 612 setUI(ui); 613 } 614 615 void forwardFocusGained( FocusEvent e) { 616 isFocused = true; 617 FocusEvent fe = CausedFocusEvent.retarget(e, this); 618 super.processFocusEvent(fe); 619 } 620 621 void forwardFocusLost( FocusEvent e) { 622 isFocused = false; 623 FocusEvent fe = CausedFocusEvent.retarget(e, this); 624 super.processFocusEvent(fe); 625 626 } 627 628 @Override 629 public boolean hasFocus() { 630 return isFocused; 631 } 632 633 public void processInputMethodEventImpl(InputMethodEvent e) { 634 processInputMethodEvent(e); 635 } 636 637 public void processMouseEventImpl(MouseEvent e) { 638 processMouseEvent(e); 639 } 640 641 public void processMouseMotionEventImpl(MouseEvent e) { 642 processMouseMotionEvent(e); 643 } 644 645 // Fix for 4915454 - override the default implementation to avoid 646 // loading SystemFlavorMap and associated classes. 647 @Override 648 public void setTransferHandler(TransferHandler newHandler) { 649 TransferHandler oldHandler = (TransferHandler) 650 getClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 651 .getJComponent_TRANSFER_HANDLER()); 652 putClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 653 .getJComponent_TRANSFER_HANDLER(), 654 newHandler); 655 656 firePropertyChange("transferHandler", oldHandler, newHandler); 657 } 658 659 @Override 660 public void setEchoChar(char c) { 661 super.setEchoChar(c); 662 ((AWTTextFieldUI)ui).installKeyboardActions(); 663 } 664 } 665 }