1 /* 2 * Copyright (c) 2003, 2016, 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.ComponentPeer; 30 import java.awt.peer.TextAreaPeer; 31 import java.awt.event.*; 32 import javax.swing.event.DocumentListener; 33 import javax.swing.event.DocumentEvent; 34 import javax.swing.JTextArea; 35 import javax.swing.JComponent; 36 import javax.swing.JScrollPane; 37 import javax.swing.JScrollBar; 38 import javax.swing.plaf.ComponentUI; 39 import com.sun.java.swing.plaf.motif.MotifTextAreaUI; 40 import javax.swing.plaf.UIResource; 41 import javax.swing.UIDefaults; 42 import javax.swing.border.Border; 43 import javax.swing.border.EmptyBorder; 44 import javax.swing.border.CompoundBorder; 45 import javax.swing.border.AbstractBorder; 46 import javax.swing.JButton; 47 import javax.swing.JViewport; 48 import javax.swing.InputMap; 49 import javax.swing.SwingUtilities; 50 import javax.swing.TransferHandler; 51 import javax.swing.plaf.basic.BasicArrowButton; 52 import javax.swing.plaf.basic.BasicScrollBarUI; 53 import javax.swing.plaf.basic.BasicScrollPaneUI; 54 import java.beans.PropertyChangeEvent; 55 import java.beans.PropertyChangeListener; 56 import javax.swing.text.Caret; 57 import javax.swing.text.DefaultCaret; 58 import javax.swing.text.JTextComponent; 59 60 import javax.swing.plaf.BorderUIResource; 61 import java.awt.im.InputMethodRequests; 62 import sun.awt.AWTAccessor; 63 import sun.awt.SunToolkit; 64 65 final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { 66 67 private final AWTTextPane textPane; 68 private final AWTTextArea jtext; 69 private final boolean firstChangeSkipped; 70 71 private final JavaMouseEventHandler javaMouseEventHandler = 72 new JavaMouseEventHandler(this); 73 74 /** 75 * Create a Text area. 76 */ XTextAreaPeer(TextArea target)77 XTextAreaPeer(TextArea target) { 78 super(target); 79 80 // some initializations require that target be set even 81 // though init(target) has not been called 82 this.target = target; 83 84 //ComponentAccessor.enableEvents(target,AWTEvent.MOUSE_WHEEL_EVENT_MASK); 85 86 String text = target.getText(); 87 jtext = new AWTTextArea(text, this); 88 jtext.setWrapStyleWord(true); 89 jtext.getDocument().addDocumentListener(jtext); 90 XToolkit.specialPeerMap.put(jtext,this); 91 textPane = new AWTTextPane(jtext,this, target.getParent()); 92 93 setBounds(x, y, width, height, SET_BOUNDS); 94 textPane.setVisible(true); 95 textPane.validate(); 96 97 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 98 foreground = compAccessor.getForeground(target); 99 if (foreground == null) { 100 foreground = SystemColor.textText; 101 } 102 setForeground(foreground); 103 104 background = compAccessor.getBackground(target); 105 if (background == null) { 106 if (target.isEditable()) background = SystemColor.text; 107 else background = SystemColor.control; 108 } 109 setBackground(background); 110 111 if (!target.isBackgroundSet()) { 112 // This is a way to set the background color of the TextArea 113 // without calling setBackground - go through accessor 114 compAccessor.setBackground(target, background); 115 } 116 if (!target.isForegroundSet()) { 117 target.setForeground(SystemColor.textText); 118 } 119 120 setFont(font); 121 122 // set the text of this object to the text of its target 123 setTextImpl(target.getText()); //?? should this be setText 124 125 int start = target.getSelectionStart(); 126 int end = target.getSelectionEnd(); 127 // Fix for 5100200 128 // Restoring Motif behaviour 129 // Since the end position of the selected text can be greater than the length of the text, 130 // so we should set caret to max position of the text 131 setCaretPosition(Math.min(end, text.length())); 132 if (end > start) { 133 // Should be called after setText() and setCaretPosition() 134 select(start, end); 135 } 136 setEditable(target.isEditable()); 137 setScrollBarVisibility(); 138 // After this line we should not change the component's text 139 firstChangeSkipped = true; 140 compAccessor.setPeer(textPane, this); 141 } 142 143 @Override dispose()144 public void dispose() { 145 XToolkit.specialPeerMap.remove(jtext); 146 // visible caret has a timer thread which must be stopped 147 jtext.getCaret().setVisible(false); 148 jtext.removeNotify(); 149 super.dispose(); 150 } 151 152 /* 153 * The method overrides one from XComponentPeer 154 * If ignoreSubComponents=={@code true} it calls super. 155 * If ignoreSubComponents=={@code false} it uses the XTextArea machinery 156 * to change cursor appropriately. In particular it changes the cursor to 157 * default if over scrollbars. 158 */ 159 @Override pSetCursor(Cursor cursor, boolean ignoreSubComponents)160 public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) { 161 if (ignoreSubComponents || 162 javaMouseEventHandler == null) { 163 super.pSetCursor(cursor, true); 164 return; 165 } 166 167 Point cursorPos = new Point(); 168 ((XGlobalCursorManager)XGlobalCursorManager.getCursorManager()).getCursorPos(cursorPos); 169 170 final Point onScreen = getLocationOnScreen(); 171 Point localPoint = new Point(cursorPos.x - onScreen.x, cursorPos.y - onScreen.y ); 172 173 javaMouseEventHandler.setPointerToUnderPoint(localPoint); 174 javaMouseEventHandler.setCursor(); 175 } 176 setScrollBarVisibility()177 private void setScrollBarVisibility() { 178 int visibility = ((TextArea)target).getScrollbarVisibility(); 179 jtext.setLineWrap(false); 180 181 if (visibility == TextArea.SCROLLBARS_NONE) { 182 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 183 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 184 jtext.setLineWrap(true); 185 } 186 else if (visibility == TextArea.SCROLLBARS_BOTH) { 187 188 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 189 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 190 } 191 else if (visibility == TextArea.SCROLLBARS_VERTICAL_ONLY) { 192 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 193 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 194 jtext.setLineWrap(true); 195 } 196 else if (visibility == TextArea.SCROLLBARS_HORIZONTAL_ONLY) { 197 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 198 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 199 } 200 } 201 202 /** 203 * Compute minimum size. 204 */ 205 @Override getMinimumSize()206 public Dimension getMinimumSize() { 207 return getMinimumSize(10, 60); 208 } 209 210 @Override getPreferredSize(int rows, int cols)211 public Dimension getPreferredSize(int rows, int cols) { 212 return getMinimumSize(rows, cols); 213 } 214 215 /** 216 * @see java.awt.peer.TextAreaPeer 217 */ 218 @Override getMinimumSize(int rows, int cols)219 public Dimension getMinimumSize(int rows, int cols) { 220 /* Dimension d = null; 221 if (jtext != null) { 222 d = jtext.getMinimumSize(rows,cols); 223 } 224 return d; 225 */ 226 227 int vsbwidth=0; 228 int hsbheight=0; 229 230 JScrollBar vsb = textPane.getVerticalScrollBar(); 231 if (vsb != null) { 232 vsbwidth = vsb.getMinimumSize().width; 233 } 234 235 JScrollBar hsb = textPane.getHorizontalScrollBar(); 236 if (hsb != null) { 237 hsbheight = hsb.getMinimumSize().height; 238 } 239 240 Font f = jtext.getFont(); 241 FontMetrics fm = jtext.getFontMetrics(f); 242 243 return new Dimension(fm.charWidth('0') * cols + /*2*XMARGIN +*/ vsbwidth, 244 fm.getHeight() * rows + /*2*YMARGIN +*/ hsbheight); 245 } 246 247 @Override isFocusable()248 public boolean isFocusable() { 249 return true; 250 } 251 252 @Override setVisible(boolean b)253 public void setVisible(boolean b) { 254 super.setVisible(b); 255 if (textPane != null) 256 textPane.setVisible(b); 257 } 258 repaintText()259 void repaintText() { 260 jtext.repaintNow(); 261 } 262 263 @Override focusGained(FocusEvent e)264 public void focusGained(FocusEvent e) { 265 super.focusGained(e); 266 jtext.forwardFocusGained(e); 267 } 268 269 @Override focusLost(FocusEvent e)270 public void focusLost(FocusEvent e) { 271 super.focusLost(e); 272 jtext.forwardFocusLost(e); 273 } 274 275 /** 276 * Paint the component 277 * this method is called when the repaint instruction has been used 278 */ 279 @Override repaint()280 public void repaint() { 281 if (textPane != null) { 282 //textPane.validate(); 283 textPane.repaint(); 284 } 285 } 286 287 @Override paintPeer(final Graphics g)288 void paintPeer(final Graphics g) { 289 if (textPane != null) { 290 textPane.paint(g); 291 } 292 } 293 294 @Override setBounds(int x, int y, int width, int height, int op)295 public void setBounds(int x, int y, int width, int height, int op) { 296 super.setBounds(x, y, width, height, op); 297 if (textPane != null) { 298 /* 299 * Fixed 6277332, 6198290: 300 * the coordinates is coming (to peer): relatively to closest HW parent 301 * the coordinates is setting (to textPane): relatively to closest ANY parent 302 * the parent of peer is target.getParent() 303 * the parent of textPane is the same 304 * see 6277332, 6198290 for more information 305 */ 306 int childX = x; 307 int childY = y; 308 Component parent = target.getParent(); 309 // we up to heavyweight parent in order to be sure 310 // that the coordinates of the text pane is relatively to closest parent 311 while (parent.isLightweight()){ 312 childX -= parent.getX(); 313 childY -= parent.getY(); 314 parent = parent.getParent(); 315 } 316 textPane.setBounds(childX,childY,width,height); 317 textPane.validate(); 318 } 319 } 320 321 @Override handleJavaKeyEvent(KeyEvent e)322 void handleJavaKeyEvent(KeyEvent e) { 323 AWTAccessor.getComponentAccessor().processEvent(jtext,e); 324 } 325 326 @Override handlesWheelScrolling()327 public boolean handlesWheelScrolling() { return true; } 328 329 @Override handleJavaMouseWheelEvent(MouseWheelEvent e)330 void handleJavaMouseWheelEvent(MouseWheelEvent e) { 331 AWTAccessor.getComponentAccessor().processEvent(textPane, e); 332 } 333 334 @Override handleJavaMouseEvent( MouseEvent e )335 public void handleJavaMouseEvent( MouseEvent e ) { 336 super.handleJavaMouseEvent( e ); 337 javaMouseEventHandler.handle( e ); 338 } 339 340 @Override handleJavaInputMethodEvent(InputMethodEvent e)341 void handleJavaInputMethodEvent(InputMethodEvent e) { 342 if (jtext != null) 343 jtext.processInputMethodEventPublic(e); 344 } 345 346 /** 347 * @see java.awt.peer.TextComponentPeer 348 */ 349 @Override select(int s, int e)350 public void select(int s, int e) { 351 jtext.select(s, e); 352 // Fixed 5100806 353 // We must take care that Swing components repainted correctly 354 jtext.repaint(); 355 } 356 357 @Override setBackground(Color c)358 public void setBackground(Color c) { 359 super.setBackground(c); 360 // synchronized (getStateLock()) { 361 // background = c; 362 // } 363 if (jtext != null) { 364 jtext.setBackground(c); 365 jtext.setSelectedTextColor(c); 366 } 367 // repaintText(); 368 } 369 370 @Override setForeground(Color c)371 public void setForeground(Color c) { 372 super.setForeground(c); 373 // synchronized (getStateLock()) { 374 // foreground = c; 375 // } 376 if (jtext != null) { 377 jtext.setForeground(foreground); 378 jtext.setSelectionColor(foreground); 379 jtext.setCaretColor(foreground); 380 } 381 // repaintText(); 382 } 383 384 @Override setFont(Font f)385 public void setFont(Font f) { 386 super.setFont(f); 387 // synchronized (getStateLock()) { 388 // font = f; 389 // } 390 if (jtext != null) { 391 jtext.setFont(font); 392 } 393 textPane.validate(); 394 } 395 396 /** 397 * @see java.awt.peer.TextComponentPeer 398 */ 399 @Override setEditable(boolean editable)400 public void setEditable(boolean editable) { 401 if (jtext != null) jtext.setEditable(editable); 402 repaintText(); 403 } 404 405 /** 406 * @see java.awt.peer.ComponentPeer 407 */ 408 @Override setEnabled(boolean enabled)409 public void setEnabled(boolean enabled) { 410 super.setEnabled(enabled); 411 if (jtext != null) { 412 jtext.setEnabled(enabled); 413 jtext.repaint(); 414 } 415 } 416 417 /** 418 * @see java.awt.peer.TextComponentPeer 419 */ 420 @Override getInputMethodRequests()421 public InputMethodRequests getInputMethodRequests() { 422 if (jtext != null) return jtext.getInputMethodRequests(); 423 else return null; 424 } 425 426 /** 427 * @see java.awt.peer.TextComponentPeer 428 */ 429 @Override getSelectionStart()430 public int getSelectionStart() { 431 return jtext.getSelectionStart(); 432 } 433 434 /** 435 * @see java.awt.peer.TextComponentPeer 436 */ 437 @Override getSelectionEnd()438 public int getSelectionEnd() { 439 return jtext.getSelectionEnd(); 440 } 441 442 /** 443 * @see java.awt.peer.TextComponentPeer 444 */ 445 @Override getText()446 public String getText() { 447 return jtext.getText(); 448 } 449 450 /** 451 * @see java.awt.peer.TextComponentPeer 452 */ 453 @Override setText(String text)454 public void setText(String text) { 455 setTextImpl(text); 456 repaintText(); 457 } 458 setTextImpl(String txt)459 private void setTextImpl(String txt) { 460 if (jtext != null) { 461 // JTextArea.setText() posts two different events (remove & insert). 462 // Since we make no differences between text events, 463 // the document listener has to be disabled while 464 // JTextArea.setText() is called. 465 jtext.getDocument().removeDocumentListener(jtext); 466 jtext.setText(txt); 467 if (firstChangeSkipped) { 468 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 469 } 470 jtext.getDocument().addDocumentListener(jtext); 471 } 472 } 473 474 /** 475 * insert the text "txt on position "pos" in the array lines 476 * @see java.awt.peer.TextAreaPeer 477 */ 478 @Override insert(String txt, int p)479 public void insert(String txt, int p) { 480 if (jtext != null) { 481 boolean doScroll = (p >= jtext.getDocument().getLength() && jtext.getDocument().getLength() != 0); 482 jtext.insert(txt,p); 483 textPane.validate(); 484 if (doScroll) { 485 JScrollBar bar = textPane.getVerticalScrollBar(); 486 if (bar != null) { 487 bar.setValue(bar.getMaximum()-bar.getVisibleAmount()); 488 } 489 } 490 } 491 } 492 493 /** 494 * replace the text between the position "s" and "e" with "txt" 495 * @see java.awt.peer.TextAreaPeer 496 */ 497 @Override replaceRange(String txt, int s, int e)498 public void replaceRange(String txt, int s, int e) { 499 if (jtext != null) { 500 // JTextArea.replaceRange() posts two different events. 501 // Since we make no differences between text events, 502 // the document listener has to be disabled while 503 // JTextArea.replaceRange() is called. 504 jtext.getDocument().removeDocumentListener(jtext); 505 jtext.replaceRange(txt, s, e); 506 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 507 jtext.getDocument().addDocumentListener(jtext); 508 } 509 } 510 511 /** 512 * to be implemented. 513 * @see java.awt.peer.TextComponentPeer 514 */ 515 @Override setCaretPosition(int position)516 public void setCaretPosition(int position) { 517 jtext.setCaretPosition(position); 518 } 519 520 /** 521 * to be implemented. 522 * @see java.awt.peer.TextComponentPeer 523 */ 524 @Override getCaretPosition()525 public int getCaretPosition() { 526 return jtext.getCaretPosition(); 527 } 528 529 final class AWTTextAreaUI extends MotifTextAreaUI { 530 531 private JTextArea jta; 532 533 @Override getPropertyPrefix()534 protected String getPropertyPrefix() { return "TextArea"; } 535 536 @Override installUI(JComponent c)537 public void installUI(JComponent c) { 538 super.installUI(c); 539 540 jta = (JTextArea) c; 541 542 JTextArea editor = jta; 543 544 UIDefaults uidefaults = XToolkit.getUIDefaults(); 545 546 String prefix = getPropertyPrefix(); 547 Font f = editor.getFont(); 548 if ((f == null) || (f instanceof UIResource)) { 549 editor.setFont(uidefaults.getFont(prefix + ".font")); 550 } 551 552 Color bg = editor.getBackground(); 553 if ((bg == null) || (bg instanceof UIResource)) { 554 editor.setBackground(uidefaults.getColor(prefix + ".background")); 555 } 556 557 Color fg = editor.getForeground(); 558 if ((fg == null) || (fg instanceof UIResource)) { 559 editor.setForeground(uidefaults.getColor(prefix + ".foreground")); 560 } 561 562 Color color = editor.getCaretColor(); 563 if ((color == null) || (color instanceof UIResource)) { 564 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); 565 } 566 567 Color s = editor.getSelectionColor(); 568 if ((s == null) || (s instanceof UIResource)) { 569 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); 570 } 571 572 Color sfg = editor.getSelectedTextColor(); 573 if ((sfg == null) || (sfg instanceof UIResource)) { 574 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); 575 } 576 577 Color dfg = editor.getDisabledTextColor(); 578 if ((dfg == null) || (dfg instanceof UIResource)) { 579 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); 580 } 581 582 Border b = new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight); 583 editor.setBorder(new BorderUIResource.CompoundBorderUIResource( 584 b,new EmptyBorder(2, 2, 2, 2))); 585 586 Insets margin = editor.getMargin(); 587 if (margin == null || margin instanceof UIResource) { 588 editor.setMargin(uidefaults.getInsets(prefix + ".margin")); 589 } 590 } 591 592 @Override installKeyboardActions()593 protected void installKeyboardActions() { 594 super.installKeyboardActions(); 595 596 JTextComponent comp = getComponent(); 597 598 UIDefaults uidefaults = XToolkit.getUIDefaults(); 599 600 String prefix = getPropertyPrefix(); 601 602 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); 603 604 if (map != null) { 605 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, 606 map); 607 } 608 } 609 610 @Override createCaret()611 protected Caret createCaret() { 612 return new XAWTCaret(); 613 } 614 } 615 616 @SuppressWarnings("serial") // JDK-implementation class 617 static final class XAWTCaret extends DefaultCaret { 618 @Override focusGained(FocusEvent e)619 public void focusGained(FocusEvent e) { 620 super.focusGained(e); 621 if (getComponent().isEnabled()){ 622 // Make sure the cursor is visible in case of non-editable TextArea 623 super.setVisible(true); 624 } 625 getComponent().repaint(); 626 } 627 628 @Override focusLost(FocusEvent e)629 public void focusLost(FocusEvent e) { 630 super.focusLost(e); 631 getComponent().repaint(); 632 } 633 } 634 635 @SuppressWarnings("serial") // JDK-implementation class 636 final class XAWTScrollBarButton extends BasicArrowButton { 637 638 private UIDefaults uidefaults = XToolkit.getUIDefaults(); 639 private Color darkShadow = SystemColor.controlShadow; 640 private Color lightShadow = SystemColor.controlLtHighlight; 641 private Color buttonBack = uidefaults.getColor("ScrollBar.track"); 642 XAWTScrollBarButton(int direction)643 XAWTScrollBarButton(int direction) { 644 super(direction); 645 646 switch (direction) { 647 case NORTH: 648 case SOUTH: 649 case EAST: 650 case WEST: 651 this.direction = direction; 652 break; 653 default: 654 throw new IllegalArgumentException("invalid direction"); 655 } 656 657 setRequestFocusEnabled(false); 658 setOpaque(true); 659 setBackground(uidefaults.getColor("ScrollBar.thumb")); 660 setForeground(uidefaults.getColor("ScrollBar.foreground")); 661 } 662 663 @Override getPreferredSize()664 public Dimension getPreferredSize() { 665 switch (direction) { 666 case NORTH: 667 case SOUTH: 668 return new Dimension(11, 12); 669 case EAST: 670 case WEST: 671 default: 672 return new Dimension(12, 11); 673 } 674 } 675 676 @Override getMinimumSize()677 public Dimension getMinimumSize() { 678 return getPreferredSize(); 679 } 680 681 @Override getMaximumSize()682 public Dimension getMaximumSize() { 683 return getPreferredSize(); 684 } 685 686 @Override isFocusTraversable()687 public boolean isFocusTraversable() { 688 return false; 689 } 690 691 @Override paint(Graphics g)692 public void paint(Graphics g) 693 { 694 int w = getWidth(); 695 int h = getHeight(); 696 697 if (isOpaque()) { 698 g.setColor(buttonBack); 699 g.fillRect(0, 0, w, h); 700 } 701 702 boolean isPressed = getModel().isPressed(); 703 Color lead = (isPressed) ? darkShadow : lightShadow; 704 Color trail = (isPressed) ? lightShadow : darkShadow; 705 Color fill = getBackground(); 706 707 int cx = w / 2; 708 int cy = h / 2; 709 int s = Math.min(w, h); 710 711 switch (direction) { 712 case NORTH: 713 g.setColor(lead); 714 g.drawLine(cx, 0, cx, 0); 715 for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { 716 g.setColor(lead); 717 g.drawLine(x, y, x, y); 718 if (y >= (s - 2)) { 719 g.drawLine(x, y + 1, x, y + 1); 720 } 721 g.setColor(fill); 722 g.drawLine(x + 1, y, x + dx, y); 723 if (y < (s - 2)) { 724 g.drawLine(x, y + 1, x + dx + 1, y + 1); 725 } 726 g.setColor(trail); 727 g.drawLine(x + dx + 1, y, x + dx + 1, y); 728 if (y >= (s - 2)) { 729 g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); 730 } 731 dx += 2; 732 x -= 1; 733 } 734 break; 735 736 case SOUTH: 737 g.setColor(trail); 738 g.drawLine(cx, s, cx, s); 739 for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { 740 g.setColor(lead); 741 g.drawLine(x, y, x, y); 742 if (y <= 2) { 743 g.drawLine(x, y - 1, x + dx + 1, y - 1); 744 } 745 g.setColor(fill); 746 g.drawLine(x + 1, y, x + dx, y); 747 if (y > 2) { 748 g.drawLine(x, y - 1, x + dx + 1, y - 1); 749 } 750 g.setColor(trail); 751 g.drawLine(x + dx + 1, y, x + dx + 1, y); 752 753 dx += 2; 754 x -= 1; 755 } 756 break; 757 758 case EAST: 759 g.setColor(lead); 760 g.drawLine(s, cy, s, cy); 761 for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { 762 g.setColor(lead); 763 g.drawLine(x, y, x, y); 764 if (x <= 2) { 765 g.drawLine(x - 1, y, x - 1, y + dy + 1); 766 } 767 g.setColor(fill); 768 g.drawLine(x, y + 1, x, y + dy); 769 if (x > 2) { 770 g.drawLine(x - 1, y, x - 1, y + dy + 1); 771 } 772 g.setColor(trail); 773 g.drawLine(x, y + dy + 1, x, y + dy + 1); 774 775 dy += 2; 776 y -= 1; 777 } 778 break; 779 780 case WEST: 781 g.setColor(trail); 782 g.drawLine(0, cy, 0, cy); 783 for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { 784 g.setColor(lead); 785 g.drawLine(x, y, x, y); 786 if (x >= (s - 2)) { 787 g.drawLine(x + 1, y, x + 1, y); 788 } 789 g.setColor(fill); 790 g.drawLine(x, y + 1, x, y + dy); 791 if (x < (s - 2)) { 792 g.drawLine(x + 1, y, x + 1, y + dy + 1); 793 } 794 g.setColor(trail); 795 g.drawLine(x, y + dy + 1, x, y + dy + 1); 796 if (x >= (s - 2)) { 797 g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); 798 } 799 dy += 2; 800 y -= 1; 801 } 802 break; 803 } 804 } 805 } 806 807 final class XAWTScrollBarUI extends BasicScrollBarUI { 808 809 @Override installDefaults()810 protected void installDefaults() 811 { 812 super.installDefaults(); 813 scrollbar.setBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 814 } 815 816 @Override configureScrollBarColors()817 protected void configureScrollBarColors() { 818 UIDefaults uidefaults = XToolkit.getUIDefaults(); 819 Color bg = scrollbar.getBackground(); 820 if (bg == null || bg instanceof UIResource) { 821 scrollbar.setBackground(uidefaults.getColor("ScrollBar.background")); 822 } 823 824 Color fg = scrollbar.getForeground(); 825 if (fg == null || fg instanceof UIResource) { 826 scrollbar.setForeground(uidefaults.getColor("ScrollBar.foreground")); 827 } 828 829 thumbHighlightColor = uidefaults.getColor("ScrollBar.thumbHighlight"); 830 thumbLightShadowColor = uidefaults.getColor("ScrollBar.thumbShadow"); 831 thumbDarkShadowColor = uidefaults.getColor("ScrollBar.thumbDarkShadow"); 832 thumbColor = uidefaults.getColor("ScrollBar.thumb"); 833 trackColor = uidefaults.getColor("ScrollBar.track"); 834 835 trackHighlightColor = uidefaults.getColor("ScrollBar.trackHighlight"); 836 837 } 838 839 @Override createDecreaseButton(int orientation)840 protected JButton createDecreaseButton(int orientation) { 841 JButton b = new XAWTScrollBarButton(orientation); 842 return b; 843 844 } 845 846 @Override createIncreaseButton(int orientation)847 protected JButton createIncreaseButton(int orientation) { 848 JButton b = new XAWTScrollBarButton(orientation); 849 return b; 850 } 851 getDecreaseButton()852 public JButton getDecreaseButton(){ 853 return decrButton; 854 } 855 getIncreaseButton()856 public JButton getIncreaseButton(){ 857 return incrButton; 858 } 859 860 @Override paint(Graphics g, JComponent c)861 public void paint(Graphics g, JComponent c) { 862 paintTrack(g, c, getTrackBounds()); 863 Rectangle thumbBounds = getThumbBounds(); 864 paintThumb(g, c, thumbBounds); 865 } 866 867 @Override paintThumb(Graphics g, JComponent c, Rectangle thumbBounds)868 public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) 869 { 870 if(!scrollbar.isEnabled()) { 871 return; 872 } 873 874 if (thumbBounds.isEmpty()) 875 thumbBounds = getTrackBounds(); 876 877 int w = thumbBounds.width; 878 int h = thumbBounds.height; 879 880 g.translate(thumbBounds.x, thumbBounds.y); 881 g.setColor(thumbColor); 882 g.fillRect(0, 0, w-1, h-1); 883 884 g.setColor(thumbHighlightColor); 885 g.drawLine(0, 0, 0, h-1); 886 g.drawLine(1, 0, w-1, 0); 887 888 g.setColor(thumbLightShadowColor); 889 g.drawLine(1, h-1, w-1, h-1); 890 g.drawLine(w-1, 1, w-1, h-2); 891 892 g.translate(-thumbBounds.x, -thumbBounds.y); 893 } 894 } 895 896 @SuppressWarnings("serial") // JDK-implementation class 897 final class AWTTextArea extends JTextArea implements DocumentListener { 898 899 private boolean isFocused = false; 900 private final XTextAreaPeer peer; 901 AWTTextArea(String text, XTextAreaPeer peer)902 AWTTextArea(String text, XTextAreaPeer peer) { 903 super(text); 904 setFocusable(false); 905 this.peer = peer; 906 } 907 908 @Override insertUpdate(DocumentEvent e)909 public void insertUpdate(DocumentEvent e) { 910 if (peer != null) { 911 peer.postEvent(new TextEvent(peer.target, 912 TextEvent.TEXT_VALUE_CHANGED)); 913 } 914 } 915 916 @Override removeUpdate(DocumentEvent e)917 public void removeUpdate(DocumentEvent e) { 918 if (peer != null) { 919 peer.postEvent(new TextEvent(peer.target, 920 TextEvent.TEXT_VALUE_CHANGED)); 921 } 922 } 923 924 @Override changedUpdate(DocumentEvent e)925 public void changedUpdate(DocumentEvent e) { 926 if (peer != null) { 927 peer.postEvent(new TextEvent(peer.target, 928 TextEvent.TEXT_VALUE_CHANGED)); 929 } 930 } 931 forwardFocusGained( FocusEvent e)932 void forwardFocusGained( FocusEvent e) { 933 isFocused = true; 934 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 935 e.getOppositeComponent(), e.getCause()); 936 super.processFocusEvent(fe); 937 } 938 939 forwardFocusLost( FocusEvent e)940 void forwardFocusLost( FocusEvent e) { 941 isFocused = false; 942 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 943 e.getOppositeComponent(), e.getCause()); 944 super.processFocusEvent(fe); 945 } 946 947 @Override hasFocus()948 public boolean hasFocus() { 949 return isFocused; 950 } 951 repaintNow()952 public void repaintNow() { 953 paintImmediately(getBounds()); 954 } 955 processMouseEventPublic(MouseEvent e)956 public void processMouseEventPublic(MouseEvent e) { 957 processMouseEvent(e); 958 } 959 processMouseMotionEventPublic(MouseEvent e)960 public void processMouseMotionEventPublic(MouseEvent e) { 961 processMouseMotionEvent(e); 962 } 963 processInputMethodEventPublic(InputMethodEvent e)964 public void processInputMethodEventPublic(InputMethodEvent e) { 965 processInputMethodEvent(e); 966 } 967 968 @Override updateUI()969 public void updateUI() { 970 ComponentUI ui = new AWTTextAreaUI(); 971 setUI(ui); 972 } 973 974 // Fix for 4915454 - override the default implementation to avoid 975 // loading SystemFlavorMap and associated classes. 976 @Override setTransferHandler(TransferHandler newHandler)977 public void setTransferHandler(TransferHandler newHandler) { 978 TransferHandler oldHandler = (TransferHandler) 979 getClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 980 .getJComponent_TRANSFER_HANDLER()); 981 putClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 982 .getJComponent_TRANSFER_HANDLER(), 983 newHandler); 984 985 firePropertyChange("transferHandler", oldHandler, newHandler); 986 } 987 } 988 989 final class XAWTScrollPaneUI extends BasicScrollPaneUI { 990 991 private final Border vsbMarginBorderR = new EmptyBorder(0, 2, 0, 0); 992 private final Border vsbMarginBorderL = new EmptyBorder(0, 0, 0, 2); 993 private final Border hsbMarginBorder = new EmptyBorder(2, 0, 0, 0); 994 995 private Border vsbBorder; 996 private Border hsbBorder; 997 998 private PropertyChangeListener propertyChangeHandler; 999 1000 @Override installListeners(JScrollPane scrollPane)1001 protected void installListeners(JScrollPane scrollPane) { 1002 super.installListeners(scrollPane); 1003 propertyChangeHandler = createPropertyChangeHandler(); 1004 scrollPane.addPropertyChangeListener(propertyChangeHandler); 1005 } 1006 1007 @Override paint(Graphics g, JComponent c)1008 public void paint(Graphics g, JComponent c) { 1009 Border vpBorder = scrollpane.getViewportBorder(); 1010 if (vpBorder != null) { 1011 Rectangle r = scrollpane.getViewportBorderBounds(); 1012 vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); 1013 } 1014 } 1015 1016 @Override uninstallListeners(JComponent scrollPane)1017 protected void uninstallListeners(JComponent scrollPane) { 1018 super.uninstallListeners(scrollPane); 1019 scrollPane.removePropertyChangeListener(propertyChangeHandler); 1020 } 1021 createPropertyChangeHandler()1022 private PropertyChangeListener createPropertyChangeHandler() { 1023 return new PropertyChangeListener() { 1024 @Override 1025 public void propertyChange(PropertyChangeEvent e) { 1026 String propertyName = e.getPropertyName(); 1027 1028 if (propertyName.equals("componentOrientation")) { 1029 JScrollPane pane = (JScrollPane)e.getSource(); 1030 JScrollBar vsb = pane.getVerticalScrollBar(); 1031 if (vsb != null) { 1032 if (isLeftToRight(pane)) { 1033 vsbBorder = new CompoundBorder(new EmptyBorder(0, 4, 0, -4), 1034 vsb.getBorder()); 1035 } else { 1036 vsbBorder = new CompoundBorder(new EmptyBorder(0, -4, 0, 4), 1037 vsb.getBorder()); 1038 } 1039 vsb.setBorder(vsbBorder); 1040 } 1041 } 1042 }}; 1043 } 1044 isLeftToRight( Component c )1045 boolean isLeftToRight( Component c ) { 1046 return c.getComponentOrientation().isLeftToRight(); 1047 } 1048 1049 @Override installDefaults(JScrollPane scrollpane)1050 protected void installDefaults(JScrollPane scrollpane) { 1051 Border b = scrollpane.getBorder(); 1052 UIDefaults uidefaults = XToolkit.getUIDefaults(); 1053 scrollpane.setBorder(uidefaults.getBorder("ScrollPane.border")); 1054 scrollpane.setBackground(uidefaults.getColor("ScrollPane.background")); 1055 scrollpane.setViewportBorder(uidefaults.getBorder("TextField.border")); 1056 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1057 if (vsb != null) { 1058 if (isLeftToRight(scrollpane)) { 1059 vsbBorder = new CompoundBorder(vsbMarginBorderR, 1060 vsb.getBorder()); 1061 } 1062 else { 1063 vsbBorder = new CompoundBorder(vsbMarginBorderL, 1064 vsb.getBorder()); 1065 } 1066 vsb.setBorder(vsbBorder); 1067 } 1068 1069 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1070 if (hsb != null) { 1071 hsbBorder = new CompoundBorder(hsbMarginBorder, hsb.getBorder()); 1072 hsb.setBorder(hsbBorder); 1073 } 1074 } 1075 1076 @Override uninstallDefaults(JScrollPane c)1077 protected void uninstallDefaults(JScrollPane c) { 1078 super.uninstallDefaults(c); 1079 1080 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1081 if (vsb != null) { 1082 if (vsb.getBorder() == vsbBorder) { 1083 vsb.setBorder(null); 1084 } 1085 vsbBorder = null; 1086 } 1087 1088 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1089 if (hsb != null) { 1090 if (hsb.getBorder() == hsbBorder) { 1091 hsb.setBorder(null); 1092 } 1093 hsbBorder = null; 1094 } 1095 } 1096 } 1097 1098 @SuppressWarnings("serial") // JDK-implementation class 1099 private class AWTTextPane extends JScrollPane implements FocusListener { 1100 1101 private final JTextArea jtext; 1102 private final XWindow xwin; 1103 1104 private final Color control = SystemColor.control; 1105 private final Color focus = SystemColor.activeCaptionBorder; 1106 1107 AWTTextPane(JTextArea jt, XWindow xwin, Container parent) { 1108 super(jt); 1109 this.xwin = xwin; 1110 setDoubleBuffered(true); 1111 jt.addFocusListener(this); 1112 AWTAccessor.getComponentAccessor().setParent(this,parent); 1113 setViewportBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 1114 this.jtext = jt; 1115 setFocusable(false); 1116 addNotify(); 1117 } 1118 1119 @Override 1120 public void invalidate() { 1121 synchronized (getTreeLock()) { 1122 final Container parent = getParent(); 1123 AWTAccessor.getComponentAccessor().setParent(this, null); 1124 try { 1125 super.invalidate(); 1126 } finally { 1127 AWTAccessor.getComponentAccessor().setParent(this, parent); 1128 } 1129 } 1130 } 1131 1132 @Override 1133 public void focusGained(FocusEvent e) { 1134 Graphics g = getGraphics(); 1135 Rectangle r = getViewportBorderBounds(); 1136 g.setColor(focus); 1137 g.drawRect(r.x,r.y,r.width,r.height); 1138 g.dispose(); 1139 } 1140 1141 @Override 1142 public void focusLost(FocusEvent e) { 1143 Graphics g = getGraphics(); 1144 Rectangle r = getViewportBorderBounds(); 1145 g.setColor(control); 1146 g.drawRect(r.x,r.y,r.width,r.height); 1147 g.dispose(); 1148 } 1149 1150 public Window getRealParent() { 1151 return (Window) xwin.target; 1152 } 1153 1154 @Override 1155 public void updateUI() { 1156 ComponentUI ui = new XAWTScrollPaneUI(); 1157 setUI(ui); 1158 } 1159 1160 @Override 1161 public JScrollBar createVerticalScrollBar() { 1162 return new XAWTScrollBar(JScrollBar.VERTICAL); 1163 } 1164 1165 @Override 1166 public JScrollBar createHorizontalScrollBar() { 1167 return new XAWTScrollBar(JScrollBar.HORIZONTAL); 1168 } 1169 1170 public JTextArea getTextArea () { 1171 return this.jtext; 1172 } 1173 1174 @Override 1175 public Graphics getGraphics() { 1176 return xwin.getGraphics(); 1177 } 1178 1179 @SuppressWarnings("serial") // JDK-implementation class 1180 final class XAWTScrollBar extends ScrollBar { 1181 1182 XAWTScrollBar(int i) { 1183 super(i); 1184 setFocusable(false); 1185 } 1186 1187 @Override 1188 public void updateUI() { 1189 ComponentUI ui = new XAWTScrollBarUI(); 1190 setUI(ui); 1191 } 1192 } 1193 } 1194 1195 @SuppressWarnings("serial") // JDK-implementation class 1196 static class BevelBorder extends AbstractBorder implements UIResource { 1197 private Color darkShadow = SystemColor.controlDkShadow; 1198 private Color lightShadow = SystemColor.controlLtHighlight; 1199 private Color control = SystemColor.controlShadow; 1200 private boolean isRaised; 1201 1202 BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) { 1203 this.isRaised = isRaised; 1204 this.darkShadow = darkShadow; 1205 this.lightShadow = lightShadow; 1206 } 1207 1208 @Override 1209 public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { 1210 g.setColor((isRaised) ? lightShadow : darkShadow); 1211 g.drawLine(x, y, x+w-1, y); // top 1212 g.drawLine(x, y+h-1, x, y+1); // left 1213 1214 g.setColor(control); 1215 g.drawLine(x+1, y+1, x+w-2, y+1); // top 1216 g.drawLine(x+1, y+h-1, x+1, y+1); // left 1217 1218 g.setColor((isRaised) ? darkShadow : lightShadow); 1219 g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom 1220 g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right 1221 1222 g.setColor(control); 1223 g.drawLine(x+1, y+h-2, x+w-2, y+h-2); // bottom 1224 g.drawLine(x+w-2, y+h-2, x+w-2, y+1); // right 1225 } 1226 1227 @Override 1228 public Insets getBorderInsets(Component c) { 1229 return getBorderInsets(c, new Insets(0,0,0,0)); 1230 } 1231 1232 @Override 1233 public Insets getBorderInsets(Component c, Insets insets) { 1234 insets.top = insets.left = insets.bottom = insets.right = 2; 1235 return insets; 1236 } 1237 1238 public boolean isOpaque(Component c) { 1239 return true; 1240 } 1241 } 1242 1243 1244 // This class dispatches 'MouseEvent's to 'XTextAreaPeer''s (hidden) 1245 // subcomponents, and overrides mouse cursor, e.g. for scrollbars. 1246 // 1247 // However, current dispatching is a kind of fake, and is tuned to do only 1248 // what is necessary/possible. E.g. no additional mouse-exited/entered 1249 // events are generated, when mouse exits scrollbar and enters viewport 1250 // with JTextArea inside. Actually, no events are ever generated here (for 1251 // now). They are only dispatched as correctly as possible/neccessary. 1252 // 1253 // In future, it would be better to replace fake-emulation of grab-detection 1254 // and event-dispatching here, by reusing some common implementation of this 1255 // functionality. Mouse-cursor setting should also be freed of hacked 1256 // overloading here. 1257 1258 private static final class JavaMouseEventHandler { 1259 private final XTextAreaPeer outer; 1260 private final Pointer current = new Pointer(); 1261 private boolean grabbed = false; 1262 1263 JavaMouseEventHandler( XTextAreaPeer outer ) { 1264 this.outer = outer; 1265 } 1266 1267 1268 // 1. We can make grab-tracking emulation here more robust to variations in 1269 // in mouse-events order and consistence. E.g. by using such code: 1270 // if( grabbed && event.getID()==MouseEvent.MOUSE_MOVED ) grabbed = false; 1271 // Or we can also use 'assert'ions. 1272 // 2. WARNING: Currently, while grab-detection mechanism _here_ says, that 1273 // grab is in progress, we do not update 'current'. In case 'current' 1274 // is set to a scrollbar or to a scroll-button, then references to their 1275 // 'Component'-instances are "remembered". And events are dispatched to 1276 // these remembered components, without checking, if XTextAreaPeer has 1277 // replaced these instances with another ones. This also aplies to 1278 // mouse-drags-from-outside (see comment in 'grabbed_update' method). 1279 1280 void handle( MouseEvent event ) { 1281 if ( ! grabbed ) { 1282 // dispatch() needs up-to-date pointer in ungrabbed case. 1283 setPointerToUnderPoint( event.getPoint() ); 1284 } 1285 dispatch( event ); 1286 boolean wasGrabbed = grabbed; 1287 grabbed_update( event ); 1288 if ( wasGrabbed && ! grabbed ) { 1289 setPointerToUnderPoint( event.getPoint() ); 1290 } 1291 setCursor(); 1292 } 1293 1294 // Following is internally private: 1295 1296 // Here dispatching is performed, of 'MouseEvent's to (some) 1297 // 'XTextAreaPeer''s (hidden) subcomponents. 1298 private void dispatch( MouseEvent event ) { 1299 switch( current.getType() ) 1300 { 1301 case TEXT: 1302 Point point = toViewportChildLocalSpace( 1303 outer.textPane.getViewport(), event.getPoint() ); 1304 XTextAreaPeer.AWTTextArea jtext = outer.jtext; 1305 MouseEvent newEvent = newMouseEvent( jtext, point, event ); 1306 int id = newEvent.getID(); 1307 if ( id==MouseEvent.MOUSE_MOVED || id==MouseEvent.MOUSE_DRAGGED ) { 1308 jtext.processMouseMotionEventPublic( newEvent ); 1309 } else { 1310 jtext.processMouseEventPublic( newEvent ); 1311 } 1312 break; 1313 1314 // We perform (additional) dispatching of events to buttons of 1315 // scrollbar, instead of leaving it to JScrollbar. This is 1316 // required, because of different listeners in Swing and AWT, 1317 // which trigger scrolling (ArrowButtonListener vs. TrackListener, 1318 // accordingly). So we dispatch events to scroll-buttons, to 1319 // invoke a correct Swing button listener. 1320 // See CR 6175401 for more information. 1321 case BAR: 1322 case BUTTON: 1323 Component c = current.getBar(); 1324 Point p = toLocalSpace( c, event.getPoint() ); 1325 if ( current.getType()==Pointer.Type.BUTTON ) { 1326 c = current.getButton(); 1327 p = toLocalSpace( c, p ); 1328 } 1329 AWTAccessor.getComponentAccessor().processEvent( c, newMouseEvent( c, p, event ) ); 1330 break; 1331 } 1332 } 1333 1334 @SuppressWarnings("deprecation") 1335 private static MouseEvent newMouseEvent( 1336 Component source, Point point, MouseEvent template ) 1337 { 1338 MouseEvent e = template; 1339 MouseEvent nme = new MouseEvent( 1340 source, 1341 e.getID(), e.getWhen(), 1342 e.getModifiersEx() | e.getModifiers(), 1343 point.x, point.y, 1344 e.getXOnScreen(), e.getYOnScreen(), 1345 e.getClickCount(), e.isPopupTrigger(), e.getButton() ); 1346 // Because these MouseEvents are dispatched directly to 1347 // their target, we need to mark them as being 1348 // system-generated here 1349 SunToolkit.setSystemGenerated(nme); 1350 return nme; 1351 } 1352 1353 private void setCursor() { 1354 if ( current.getType()==Pointer.Type.TEXT ) { 1355 // 'target.getCursor()' is also applied from elsewhere 1356 // (at least now), but only when mouse "entered", and 1357 // before 'XTextAreaPeer.handleJavaMouseEvent' is invoked. 1358 outer.pSetCursor( outer.target.getCursor(), true ); 1359 } 1360 else { 1361 // We can write here a more intelligent cursor selection 1362 // mechanism, like getting cursor from 'current' component. 1363 // However, I see no point in doing so now. But if you feel 1364 // like implementing it, you'll probably need to introduce 1365 // 'Pointer.Type.PANEL'. 1366 outer.pSetCursor( outer.textPane.getCursor(), true ); 1367 } 1368 } 1369 1370 1371 // Current way of grab-detection causes interesting (but harmless) 1372 // side-effect. If mouse is draged from outside to inside of TextArea, 1373 // we will then (in some cases) be asked to dispatch mouse-entered/exited 1374 // events. But, as at least one mouse-button is down, we will detect 1375 // grab-mode is on (though the grab isn't ours). 1376 // 1377 // Thus, we will not update 'current' (see 'handle' method), and will 1378 // dispatch events to the last subcomponent, the 'current' was set to. 1379 // As always, we set cursor in this case also. But, all this seems 1380 // harmless, because mouse entered/exited events seem to have no effect 1381 // here, and cursor setting is ignored in case of drags from outside. 1382 // 1383 // Grab-detection can be further improved, e.g. by taking into account 1384 // current event-ID, but I see not point in doing it now. 1385 1386 private void grabbed_update( MouseEvent event ) { 1387 final int allButtonsMask 1388 = MouseEvent.BUTTON1_DOWN_MASK 1389 | MouseEvent.BUTTON2_DOWN_MASK 1390 | MouseEvent.BUTTON3_DOWN_MASK; 1391 grabbed = ( (event.getModifiersEx() & allButtonsMask) != 0 ); 1392 } 1393 1394 // 'toLocalSpace' and 'toViewportChildLocalSpace' can be "optimized" to 1395 // 'return' 'void' and use 'Point' input-argument also as output. 1396 private static Point toLocalSpace( Component local, Point inParentSpace ) 1397 { 1398 Point p = inParentSpace; 1399 Point l = local.getLocation(); 1400 return new Point( p.x - l.x, p.y - l.y ); 1401 } 1402 private static Point toViewportChildLocalSpace( JViewport v, Point inViewportParentSpace ) 1403 { 1404 Point l = toLocalSpace(v, inViewportParentSpace); 1405 Point p = v.getViewPosition(); 1406 l.x += p.x; 1407 l.y += p.y; 1408 return l; 1409 } 1410 1411 private void setPointerToUnderPoint( Point point ) { 1412 if ( outer.textPane.getViewport().getBounds().contains( point ) ) { 1413 current.setText(); 1414 } 1415 else if ( ! setPointerIfPointOverScrollbar( 1416 outer.textPane.getVerticalScrollBar(), point ) ) 1417 { 1418 if ( ! setPointerIfPointOverScrollbar( 1419 outer.textPane.getHorizontalScrollBar(), point ) ) 1420 { 1421 current.setNone(); 1422 } 1423 } 1424 } 1425 1426 private boolean setPointerIfPointOverScrollbar( JScrollBar bar, Point point ) { 1427 if ( ! bar.getBounds().contains( point ) ) { 1428 return false; 1429 } 1430 current.setBar( bar ); 1431 Point local = toLocalSpace( bar, point ); 1432 1433 XTextAreaPeer.XAWTScrollBarUI ui = 1434 (XTextAreaPeer.XAWTScrollBarUI) bar.getUI(); 1435 1436 if ( ! setPointerIfPointOverButton( ui.getIncreaseButton(), local ) ) { 1437 setPointerIfPointOverButton( ui.getDecreaseButton(), local ); 1438 } 1439 1440 return true; 1441 } 1442 1443 private boolean setPointerIfPointOverButton( JButton button, Point point ) { 1444 if ( ! button.getBounds().contains( point ) ) { 1445 return false; 1446 } 1447 current.setButton( button ); 1448 return true; 1449 } 1450 1451 private static final class Pointer { 1452 static enum Type { 1453 NONE, TEXT, BAR, BUTTON // , PANEL 1454 } 1455 Type getType() { 1456 return type; 1457 } 1458 boolean isNone() { 1459 return type==Type.NONE; 1460 } 1461 JScrollBar getBar() { 1462 boolean ok = type==Type.BAR || type==Type.BUTTON; 1463 assert ok; 1464 return ok ? bar : null; 1465 } 1466 JButton getButton() { 1467 boolean ok = type==Type.BUTTON; 1468 assert ok; 1469 return ok ? button : null; 1470 } 1471 void setNone() { 1472 type = Type.NONE; 1473 } 1474 void setText() { 1475 type = Type.TEXT; 1476 } 1477 void setBar( JScrollBar bar ) { 1478 this.bar=bar; 1479 type=Type.BAR; 1480 } 1481 void setButton( JButton button ) { 1482 this.button=button; 1483 type=Type.BUTTON; 1484 } 1485 1486 private Type type; 1487 private JScrollBar bar; 1488 private JButton button; 1489 } 1490 } 1491 } 1492