1 /* 2 * Copyright (c) 2003, 2018, 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.AWTAccessor; 58 59 final class XTextFieldPeer extends XComponentPeer implements TextFieldPeer { 60 private static final PlatformLogger log = PlatformLogger.getLogger("sun.awt.X11.XTextField"); 61 62 private String text; 63 private final XAWTTextField xtext; 64 private final boolean firstChangeSkipped; 65 XTextFieldPeer(TextField target)66 XTextFieldPeer(TextField target) { 67 super(target); 68 text = target.getText(); 69 xtext = new XAWTTextField(text,this, target.getParent()); 70 xtext.getDocument().addDocumentListener(xtext); 71 xtext.setCursor(target.getCursor()); 72 XToolkit.specialPeerMap.put(xtext,this); 73 74 initTextField(); 75 setText(target.getText()); 76 if (target.echoCharIsSet()) { 77 setEchoChar(target.getEchoChar()); 78 } 79 else setEchoChar((char)0); 80 81 int start = target.getSelectionStart(); 82 int end = target.getSelectionEnd(); 83 // Fix for 5100200 84 // Restoring Motif behaviour 85 // Since the end position of the selected text can be greater than the length of the text, 86 // so we should set caret to max position of the text 87 setCaretPosition(Math.min(end, text.length())); 88 if (end > start) { 89 // Should be called after setText() and setCaretPosition() 90 select(start, end); 91 } 92 93 setEditable(target.isEditable()); 94 95 // After this line we should not change the component's text 96 firstChangeSkipped = true; 97 AWTAccessor.getComponentAccessor().setPeer(xtext, this); 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 super.dispose(); 106 } 107 initTextField()108 void initTextField() { 109 setVisible(target.isVisible()); 110 111 setBounds(x, y, width, height, SET_BOUNDS); 112 113 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 114 foreground = compAccessor.getForeground(target); 115 if (foreground == null) 116 foreground = SystemColor.textText; 117 118 setForeground(foreground); 119 120 background = compAccessor.getBackground(target); 121 if (background == null) { 122 if (((TextField)target).isEditable()) background = SystemColor.text; 123 else background = SystemColor.control; 124 } 125 setBackground(background); 126 127 if (!target.isBackgroundSet()) { 128 // This is a way to set the background color of the TextArea 129 // without calling setBackground - go through accessor 130 compAccessor.setBackground(target, background); 131 } 132 if (!target.isForegroundSet()) { 133 target.setForeground(SystemColor.textText); 134 } 135 136 setFont(font); 137 } 138 139 /** 140 * @see java.awt.peer.TextComponentPeer 141 */ 142 @Override setEditable(boolean editable)143 public void setEditable(boolean editable) { 144 if (xtext != null) { 145 xtext.setEditable(editable); 146 xtext.repaint(); 147 } 148 } 149 150 /** 151 * @see java.awt.peer.ComponentPeer 152 */ 153 @Override setEnabled(boolean enabled)154 public void setEnabled(boolean enabled) { 155 super.setEnabled(enabled); 156 if (xtext != null) { 157 xtext.setEnabled(enabled); 158 xtext.repaint(); 159 } 160 } 161 162 /** 163 * @see java.awt.peer.TextComponentPeer 164 */ 165 @Override getInputMethodRequests()166 public InputMethodRequests getInputMethodRequests() { 167 if (xtext != null) return xtext.getInputMethodRequests(); 168 else return null; 169 170 } 171 172 @Override handleJavaInputMethodEvent(InputMethodEvent e)173 void handleJavaInputMethodEvent(InputMethodEvent e) { 174 if (xtext != null) 175 xtext.processInputMethodEventImpl(e); 176 } 177 178 /** 179 * @see java.awt.peer.TextFieldPeer 180 */ 181 @Override setEchoChar(char c)182 public void setEchoChar(char c) { 183 if (xtext != null) { 184 xtext.setEchoChar(c); 185 xtext.putClientProperty("JPasswordField.cutCopyAllowed", 186 xtext.echoCharIsSet() ? Boolean.FALSE : Boolean.TRUE); 187 } 188 } 189 190 /** 191 * @see java.awt.peer.TextComponentPeer 192 */ 193 @Override getSelectionStart()194 public int getSelectionStart() { 195 return xtext.getSelectionStart(); 196 } 197 198 /** 199 * @see java.awt.peer.TextComponentPeer 200 */ 201 @Override getSelectionEnd()202 public int getSelectionEnd() { 203 return xtext.getSelectionEnd(); 204 } 205 206 /** 207 * @see java.awt.peer.TextComponentPeer 208 */ 209 @Override 210 @SuppressWarnings("deprecation") 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 if (xtext.getBackground() != c) { 262 xtext.setBackground(c); 263 } 264 xtext.setSelectedTextColor(c); 265 } 266 repaintText(); 267 } 268 269 @Override setForeground(Color c)270 public void setForeground(Color c) { 271 foreground = c; 272 if (xtext != null) { 273 if (xtext.getForeground() != c) { 274 xtext.setForeground(foreground); 275 } 276 xtext.setSelectionColor(foreground); 277 xtext.setCaretColor(foreground); 278 } 279 repaintText(); 280 } 281 282 @Override setFont(Font f)283 public void setFont(Font f) { 284 boolean isChanged = false; 285 synchronized (getStateLock()) { 286 font = f; 287 if (xtext != null && xtext.getFont() != f) { 288 xtext.setFont(font); 289 isChanged = true; 290 } 291 } 292 if (isChanged) 293 xtext.validate(); 294 } 295 296 /** 297 * Deselects the highlighted text. 298 */ deselect()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 * to be implemented. 309 * @see java.awt.peer.TextComponentPeer 310 */ 311 @Override getCaretPosition()312 public int getCaretPosition() { 313 return xtext.getCaretPosition(); 314 } 315 316 /** 317 * @see java.awt.peer.TextComponentPeer 318 */ 319 @Override select(int s, int e)320 public void select(int s, int e) { 321 xtext.select(s,e); 322 // Fixed 5100806 323 // We must take care that Swing components repainted correctly 324 xtext.repaint(); 325 } 326 327 @Override getMinimumSize()328 public Dimension getMinimumSize() { 329 return xtext.getMinimumSize(); 330 } 331 332 @Override getPreferredSize()333 public Dimension getPreferredSize() { 334 return xtext.getPreferredSize(); 335 } 336 337 @Override getPreferredSize(int cols)338 public Dimension getPreferredSize(int cols) { 339 return getMinimumSize(cols); 340 } 341 342 private static final int PADDING = 16; 343 344 @Override getMinimumSize(int cols)345 public Dimension getMinimumSize(int cols) { 346 Font f = xtext.getFont(); 347 FontMetrics fm = xtext.getFontMetrics(f); 348 return new Dimension(fm.charWidth('0') * cols + 10, 349 fm.getMaxDescent() + fm.getMaxAscent() + PADDING); 350 } 351 352 @Override isFocusable()353 public boolean isFocusable() { 354 return true; 355 } 356 357 // NOTE: This method is called by privileged threads. 358 // DO NOT INVOKE CLIENT CODE ON THIS THREAD! action(final long when, final int modifiers)359 public void action(final long when, final int modifiers) { 360 postEvent(new ActionEvent(target, ActionEvent.ACTION_PERFORMED, 361 text, when, 362 modifiers)); 363 } 364 disposeImpl()365 protected void disposeImpl() { 366 } 367 368 @Override repaint()369 public void repaint() { 370 if (xtext != null) xtext.repaint(); 371 } 372 @Override paintPeer(final Graphics g)373 void paintPeer(final Graphics g) { 374 if (xtext != null) xtext.paint(g); 375 } 376 377 @Override print(Graphics g)378 public void print(Graphics g) { 379 if (xtext != null) { 380 xtext.print(g); 381 } 382 } 383 384 @Override focusLost(FocusEvent e)385 public void focusLost(FocusEvent e) { 386 super.focusLost(e); 387 xtext.forwardFocusLost(e); 388 } 389 390 @Override focusGained(FocusEvent e)391 public void focusGained(FocusEvent e) { 392 super.focusGained(e); 393 xtext.forwardFocusGained(e); 394 } 395 396 @Override handleJavaKeyEvent(KeyEvent e)397 void handleJavaKeyEvent(KeyEvent e) { 398 AWTAccessor.getComponentAccessor().processEvent(xtext,e); 399 } 400 401 402 @Override handleJavaMouseEvent( MouseEvent mouseEvent )403 public void handleJavaMouseEvent( MouseEvent mouseEvent ) { 404 super.handleJavaMouseEvent(mouseEvent); 405 if (xtext != null) { 406 mouseEvent.setSource(xtext); 407 int id = mouseEvent.getID(); 408 if (id == MouseEvent.MOUSE_DRAGGED || id == MouseEvent.MOUSE_MOVED) 409 xtext.processMouseMotionEventImpl(mouseEvent); 410 else 411 xtext.processMouseEventImpl(mouseEvent); 412 } 413 } 414 415 @Override setVisible(boolean b)416 public void setVisible(boolean b) { 417 super.setVisible(b); 418 if (xtext != null) xtext.setVisible(b); 419 } 420 421 @Override setBounds(int x, int y, int width, int height, int op)422 public void setBounds(int x, int y, int width, int height, int op) { 423 super.setBounds(x, y, width, height, op); 424 if (xtext != null) { 425 /* 426 * Fixed 6277332, 6198290: 427 * the coordinates is coming (to peer): relatively to closest HW parent 428 * the coordinates is setting (to textField): relatively to closest ANY parent 429 * the parent of peer is target.getParent() 430 * the parent of textField is the same 431 * see 6277332, 6198290 for more information 432 */ 433 int childX = x; 434 int childY = y; 435 Component parent = target.getParent(); 436 // we up to heavyweight parent in order to be sure 437 // that the coordinates of the text pane is relatively to closest parent 438 while (parent.isLightweight()){ 439 childX -= parent.getX(); 440 childY -= parent.getY(); 441 parent = parent.getParent(); 442 } 443 xtext.setBounds(childX,childY,width,height); 444 xtext.validate(); 445 } 446 } 447 448 final class AWTTextFieldUI extends MotifPasswordFieldUI { 449 450 private JTextField jtf; 451 452 @Override getPropertyPrefix()453 protected String getPropertyPrefix() { 454 JTextComponent comp = getComponent(); 455 if (comp instanceof JPasswordField && ((JPasswordField)comp).echoCharIsSet()) { 456 return "PasswordField"; 457 } else { 458 return "TextField"; 459 } 460 } 461 462 @Override installUI(JComponent c)463 public void installUI(JComponent c) { 464 super.installUI(c); 465 466 jtf = (JTextField) c; 467 468 JTextField editor = jtf; 469 470 UIDefaults uidefaults = XToolkit.getUIDefaults(); 471 472 String prefix = getPropertyPrefix(); 473 Font f = editor.getFont(); 474 if ((f == null) || (f instanceof UIResource)) { 475 editor.setFont(uidefaults.getFont(prefix + ".font")); 476 } 477 478 Color bg = editor.getBackground(); 479 if ((bg == null) || (bg instanceof UIResource)) { 480 editor.setBackground(uidefaults.getColor(prefix + ".background")); 481 } 482 483 Color fg = editor.getForeground(); 484 if ((fg == null) || (fg instanceof UIResource)) { 485 editor.setForeground(uidefaults.getColor(prefix + ".foreground")); 486 } 487 488 Color color = editor.getCaretColor(); 489 if ((color == null) || (color instanceof UIResource)) { 490 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); 491 } 492 493 Color s = editor.getSelectionColor(); 494 if ((s == null) || (s instanceof UIResource)) { 495 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); 496 } 497 498 Color sfg = editor.getSelectedTextColor(); 499 if ((sfg == null) || (sfg instanceof UIResource)) { 500 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); 501 } 502 503 Color dfg = editor.getDisabledTextColor(); 504 if ((dfg == null) || (dfg instanceof UIResource)) { 505 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); 506 } 507 508 Border b = editor.getBorder(); 509 if ((b == null) || (b instanceof UIResource)) { 510 editor.setBorder(uidefaults.getBorder(prefix + ".border")); 511 } 512 513 Insets margin = editor.getMargin(); 514 if (margin == null || margin instanceof UIResource) { 515 editor.setMargin(uidefaults.getInsets(prefix + ".margin")); 516 } 517 } 518 519 @Override installKeyboardActions()520 protected void installKeyboardActions() { 521 super.installKeyboardActions(); 522 523 JTextComponent comp = getComponent(); 524 525 UIDefaults uidefaults = XToolkit.getUIDefaults(); 526 527 String prefix = getPropertyPrefix(); 528 529 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); 530 531 if (map != null) { 532 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, 533 map); 534 } 535 } 536 537 @Override createCaret()538 protected Caret createCaret() { 539 return new XTextAreaPeer.XAWTCaret(); 540 } 541 } 542 543 @SuppressWarnings("serial") // JDK-implementation class 544 final class XAWTTextField extends JPasswordField 545 implements ActionListener, DocumentListener { 546 547 private boolean isFocused = false; 548 private final XComponentPeer xwin; 549 XAWTTextField(String text, XComponentPeer xwin, Container parent)550 XAWTTextField(String text, XComponentPeer xwin, Container parent) { 551 super(text); 552 this.xwin = xwin; 553 setDoubleBuffered(true); 554 setFocusable(false); 555 AWTAccessor.getComponentAccessor().setParent(this,parent); 556 setBackground(xwin.getPeerBackground()); 557 setForeground(xwin.getPeerForeground()); 558 setFont(xwin.getPeerFont()); 559 setCaretPosition(0); 560 addActionListener(this); 561 addNotify(); 562 } 563 564 @Override 565 @SuppressWarnings("deprecation") actionPerformed( ActionEvent actionEvent )566 public void actionPerformed( ActionEvent actionEvent ) { 567 xwin.postEvent( 568 new ActionEvent(xwin.target, ActionEvent.ACTION_PERFORMED, 569 getText(), actionEvent.getWhen(), 570 actionEvent.getModifiers())); 571 572 } 573 574 @Override insertUpdate(DocumentEvent e)575 public void insertUpdate(DocumentEvent e) { 576 if (xwin != null) { 577 xwin.postEvent(new TextEvent(xwin.target, 578 TextEvent.TEXT_VALUE_CHANGED)); 579 } 580 } 581 582 @Override removeUpdate(DocumentEvent e)583 public void removeUpdate(DocumentEvent e) { 584 if (xwin != null) { 585 xwin.postEvent(new TextEvent(xwin.target, 586 TextEvent.TEXT_VALUE_CHANGED)); 587 } 588 } 589 590 @Override changedUpdate(DocumentEvent e)591 public void changedUpdate(DocumentEvent e) { 592 if (xwin != null) { 593 xwin.postEvent(new TextEvent(xwin.target, 594 TextEvent.TEXT_VALUE_CHANGED)); 595 } 596 } 597 repaintNow()598 public void repaintNow() { 599 paintImmediately(getBounds()); 600 } 601 602 @Override getGraphics()603 public Graphics getGraphics() { 604 return xwin.getGraphics(); 605 } 606 607 @Override updateUI()608 public void updateUI() { 609 ComponentUI ui = new AWTTextFieldUI(); 610 setUI(ui); 611 } 612 forwardFocusGained( FocusEvent e)613 void forwardFocusGained( FocusEvent e) { 614 isFocused = true; 615 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 616 e.getOppositeComponent(), e.getCause()); 617 super.processFocusEvent(fe); 618 } 619 forwardFocusLost( FocusEvent e)620 void forwardFocusLost( FocusEvent e) { 621 isFocused = false; 622 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 623 e.getOppositeComponent(), e.getCause()); 624 super.processFocusEvent(fe); 625 626 } 627 628 @Override hasFocus()629 public boolean hasFocus() { 630 return isFocused; 631 } 632 processInputMethodEventImpl(InputMethodEvent e)633 public void processInputMethodEventImpl(InputMethodEvent e) { 634 processInputMethodEvent(e); 635 } 636 processMouseEventImpl(MouseEvent e)637 public void processMouseEventImpl(MouseEvent e) { 638 processMouseEvent(e); 639 } 640 processMouseMotionEventImpl(MouseEvent e)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 setTransferHandler(TransferHandler newHandler)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 setEchoChar(char c)660 public void setEchoChar(char c) { 661 super.setEchoChar(c); 662 ((AWTTextFieldUI)ui).installKeyboardActions(); 663 } 664 } 665 } 666