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