1 /* 2 * Copyright (c) 2003, 2015, 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 */ 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 then 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 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 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 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 206 public Dimension getMinimumSize() { 207 return getMinimumSize(10, 60); 208 } 209 210 @Override 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 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 248 public boolean isFocusable() { 249 return true; 250 } 251 252 @Override 253 public void setVisible(boolean b) { 254 super.setVisible(b); 255 if (textPane != null) 256 textPane.setVisible(b); 257 } 258 259 void repaintText() { 260 jtext.repaintNow(); 261 } 262 263 @Override 264 public void focusGained(FocusEvent e) { 265 super.focusGained(e); 266 jtext.forwardFocusGained(e); 267 } 268 269 @Override 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 280 public void repaint() { 281 if (textPane != null) { 282 //textPane.validate(); 283 textPane.repaint(); 284 } 285 } 286 287 @Override 288 void paintPeer(final Graphics g) { 289 if (textPane != null) { 290 textPane.paint(g); 291 } 292 } 293 294 @Override 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 322 void handleJavaKeyEvent(KeyEvent e) { 323 AWTAccessor.getComponentAccessor().processEvent(jtext,e); 324 } 325 326 @Override 327 public boolean handlesWheelScrolling() { return true; } 328 329 @Override 330 void handleJavaMouseWheelEvent(MouseWheelEvent e) { 331 AWTAccessor.getComponentAccessor().processEvent(textPane, e); 332 } 333 334 @Override 335 public void handleJavaMouseEvent( MouseEvent e ) { 336 super.handleJavaMouseEvent( e ); 337 javaMouseEventHandler.handle( e ); 338 } 339 340 @Override 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 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 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 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 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 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 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 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 430 public int getSelectionStart() { 431 return jtext.getSelectionStart(); 432 } 433 434 /** 435 * @see java.awt.peer.TextComponentPeer 436 */ 437 @Override 438 public int getSelectionEnd() { 439 return jtext.getSelectionEnd(); 440 } 441 442 /** 443 * @see java.awt.peer.TextComponentPeer 444 */ 445 @Override 446 public String getText() { 447 return jtext.getText(); 448 } 449 450 /** 451 * @see java.awt.peer.TextComponentPeer 452 */ 453 @Override 454 public void setText(String text) { 455 setTextImpl(text); 456 repaintText(); 457 } 458 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 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 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 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 525 public int getCaretPosition() { 526 return jtext.getCaretPosition(); 527 } 528 529 final class AWTTextAreaUI extends MotifTextAreaUI { 530 531 private JTextArea jta; 532 533 @Override 534 protected String getPropertyPrefix() { return "TextArea"; } 535 536 @Override 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 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 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 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 629 public void focusLost(FocusEvent e) { 630 super.focusLost(e); 631 getComponent().repaint(); 632 } 633 634 // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit 635 // Restoring Motif behaviour 636 // If the text is unhighlighted then we should sets the selection range to zero 637 @Override 638 public void setSelectionVisible(boolean vis) { 639 if (vis){ 640 super.setSelectionVisible(vis); 641 }else{ 642 // In order to de-select the selection 643 setDot(getDot()); 644 } 645 } 646 } 647 648 @SuppressWarnings("serial") // JDK-implementation class 649 final class XAWTScrollBarButton extends BasicArrowButton { 650 651 private UIDefaults uidefaults = XToolkit.getUIDefaults(); 652 private Color darkShadow = SystemColor.controlShadow; 653 private Color lightShadow = SystemColor.controlLtHighlight; 654 private Color buttonBack = uidefaults.getColor("ScrollBar.track"); 655 656 XAWTScrollBarButton(int direction) { 657 super(direction); 658 659 switch (direction) { 660 case NORTH: 661 case SOUTH: 662 case EAST: 663 case WEST: 664 this.direction = direction; 665 break; 666 default: 667 throw new IllegalArgumentException("invalid direction"); 668 } 669 670 setRequestFocusEnabled(false); 671 setOpaque(true); 672 setBackground(uidefaults.getColor("ScrollBar.thumb")); 673 setForeground(uidefaults.getColor("ScrollBar.foreground")); 674 } 675 676 @Override 677 public Dimension getPreferredSize() { 678 switch (direction) { 679 case NORTH: 680 case SOUTH: 681 return new Dimension(11, 12); 682 case EAST: 683 case WEST: 684 default: 685 return new Dimension(12, 11); 686 } 687 } 688 689 @Override 690 public Dimension getMinimumSize() { 691 return getPreferredSize(); 692 } 693 694 @Override 695 public Dimension getMaximumSize() { 696 return getPreferredSize(); 697 } 698 699 @Override 700 public boolean isFocusTraversable() { 701 return false; 702 } 703 704 @Override 705 public void paint(Graphics g) 706 { 707 int w = getWidth(); 708 int h = getHeight(); 709 710 if (isOpaque()) { 711 g.setColor(buttonBack); 712 g.fillRect(0, 0, w, h); 713 } 714 715 boolean isPressed = getModel().isPressed(); 716 Color lead = (isPressed) ? darkShadow : lightShadow; 717 Color trail = (isPressed) ? lightShadow : darkShadow; 718 Color fill = getBackground(); 719 720 int cx = w / 2; 721 int cy = h / 2; 722 int s = Math.min(w, h); 723 724 switch (direction) { 725 case NORTH: 726 g.setColor(lead); 727 g.drawLine(cx, 0, cx, 0); 728 for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { 729 g.setColor(lead); 730 g.drawLine(x, y, x, y); 731 if (y >= (s - 2)) { 732 g.drawLine(x, y + 1, x, y + 1); 733 } 734 g.setColor(fill); 735 g.drawLine(x + 1, y, x + dx, y); 736 if (y < (s - 2)) { 737 g.drawLine(x, y + 1, x + dx + 1, y + 1); 738 } 739 g.setColor(trail); 740 g.drawLine(x + dx + 1, y, x + dx + 1, y); 741 if (y >= (s - 2)) { 742 g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); 743 } 744 dx += 2; 745 x -= 1; 746 } 747 break; 748 749 case SOUTH: 750 g.setColor(trail); 751 g.drawLine(cx, s, cx, s); 752 for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { 753 g.setColor(lead); 754 g.drawLine(x, y, x, y); 755 if (y <= 2) { 756 g.drawLine(x, y - 1, x + dx + 1, y - 1); 757 } 758 g.setColor(fill); 759 g.drawLine(x + 1, y, x + dx, y); 760 if (y > 2) { 761 g.drawLine(x, y - 1, x + dx + 1, y - 1); 762 } 763 g.setColor(trail); 764 g.drawLine(x + dx + 1, y, x + dx + 1, y); 765 766 dx += 2; 767 x -= 1; 768 } 769 break; 770 771 case EAST: 772 g.setColor(lead); 773 g.drawLine(s, cy, s, cy); 774 for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { 775 g.setColor(lead); 776 g.drawLine(x, y, x, y); 777 if (x <= 2) { 778 g.drawLine(x - 1, y, x - 1, y + dy + 1); 779 } 780 g.setColor(fill); 781 g.drawLine(x, y + 1, x, y + dy); 782 if (x > 2) { 783 g.drawLine(x - 1, y, x - 1, y + dy + 1); 784 } 785 g.setColor(trail); 786 g.drawLine(x, y + dy + 1, x, y + dy + 1); 787 788 dy += 2; 789 y -= 1; 790 } 791 break; 792 793 case WEST: 794 g.setColor(trail); 795 g.drawLine(0, cy, 0, cy); 796 for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { 797 g.setColor(lead); 798 g.drawLine(x, y, x, y); 799 if (x >= (s - 2)) { 800 g.drawLine(x + 1, y, x + 1, y); 801 } 802 g.setColor(fill); 803 g.drawLine(x, y + 1, x, y + dy); 804 if (x < (s - 2)) { 805 g.drawLine(x + 1, y, x + 1, y + dy + 1); 806 } 807 g.setColor(trail); 808 g.drawLine(x, y + dy + 1, x, y + dy + 1); 809 if (x >= (s - 2)) { 810 g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); 811 } 812 dy += 2; 813 y -= 1; 814 } 815 break; 816 } 817 } 818 } 819 820 final class XAWTScrollBarUI extends BasicScrollBarUI { 821 822 @Override 823 protected void installDefaults() 824 { 825 super.installDefaults(); 826 scrollbar.setBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 827 } 828 829 @Override 830 protected void configureScrollBarColors() { 831 UIDefaults uidefaults = XToolkit.getUIDefaults(); 832 Color bg = scrollbar.getBackground(); 833 if (bg == null || bg instanceof UIResource) { 834 scrollbar.setBackground(uidefaults.getColor("ScrollBar.background")); 835 } 836 837 Color fg = scrollbar.getForeground(); 838 if (fg == null || fg instanceof UIResource) { 839 scrollbar.setForeground(uidefaults.getColor("ScrollBar.foreground")); 840 } 841 842 thumbHighlightColor = uidefaults.getColor("ScrollBar.thumbHighlight"); 843 thumbLightShadowColor = uidefaults.getColor("ScrollBar.thumbShadow"); 844 thumbDarkShadowColor = uidefaults.getColor("ScrollBar.thumbDarkShadow"); 845 thumbColor = uidefaults.getColor("ScrollBar.thumb"); 846 trackColor = uidefaults.getColor("ScrollBar.track"); 847 848 trackHighlightColor = uidefaults.getColor("ScrollBar.trackHighlight"); 849 850 } 851 852 @Override 853 protected JButton createDecreaseButton(int orientation) { 854 JButton b = new XAWTScrollBarButton(orientation); 855 return b; 856 857 } 858 859 @Override 860 protected JButton createIncreaseButton(int orientation) { 861 JButton b = new XAWTScrollBarButton(orientation); 862 return b; 863 } 864 865 public JButton getDecreaseButton(){ 866 return decrButton; 867 } 868 869 public JButton getIncreaseButton(){ 870 return incrButton; 871 } 872 873 @Override 874 public void paint(Graphics g, JComponent c) { 875 paintTrack(g, c, getTrackBounds()); 876 Rectangle thumbBounds = getThumbBounds(); 877 paintThumb(g, c, thumbBounds); 878 } 879 880 @Override 881 public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) 882 { 883 if(!scrollbar.isEnabled()) { 884 return; 885 } 886 887 if (thumbBounds.isEmpty()) 888 thumbBounds = getTrackBounds(); 889 890 int w = thumbBounds.width; 891 int h = thumbBounds.height; 892 893 g.translate(thumbBounds.x, thumbBounds.y); 894 g.setColor(thumbColor); 895 g.fillRect(0, 0, w-1, h-1); 896 897 g.setColor(thumbHighlightColor); 898 g.drawLine(0, 0, 0, h-1); 899 g.drawLine(1, 0, w-1, 0); 900 901 g.setColor(thumbLightShadowColor); 902 g.drawLine(1, h-1, w-1, h-1); 903 g.drawLine(w-1, 1, w-1, h-2); 904 905 g.translate(-thumbBounds.x, -thumbBounds.y); 906 } 907 } 908 909 @SuppressWarnings("serial") // JDK-implementation class 910 final class AWTTextArea extends JTextArea implements DocumentListener { 911 912 private boolean isFocused = false; 913 private final XTextAreaPeer peer; 914 915 AWTTextArea(String text, XTextAreaPeer peer) { 916 super(text); 917 setFocusable(false); 918 this.peer = peer; 919 } 920 921 @Override 922 public void insertUpdate(DocumentEvent e) { 923 if (peer != null) { 924 peer.postEvent(new TextEvent(peer.target, 925 TextEvent.TEXT_VALUE_CHANGED)); 926 } 927 } 928 929 @Override 930 public void removeUpdate(DocumentEvent e) { 931 if (peer != null) { 932 peer.postEvent(new TextEvent(peer.target, 933 TextEvent.TEXT_VALUE_CHANGED)); 934 } 935 } 936 937 @Override 938 public void changedUpdate(DocumentEvent e) { 939 if (peer != null) { 940 peer.postEvent(new TextEvent(peer.target, 941 TextEvent.TEXT_VALUE_CHANGED)); 942 } 943 } 944 945 void forwardFocusGained( FocusEvent e) { 946 isFocused = true; 947 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 948 e.getOppositeComponent(), e.getCause()); 949 super.processFocusEvent(fe); 950 } 951 952 953 void forwardFocusLost( FocusEvent e) { 954 isFocused = false; 955 FocusEvent fe = new FocusEvent(this, e.getID(), e.isTemporary(), 956 e.getOppositeComponent(), e.getCause()); 957 super.processFocusEvent(fe); 958 } 959 960 @Override 961 public boolean hasFocus() { 962 return isFocused; 963 } 964 965 public void repaintNow() { 966 paintImmediately(getBounds()); 967 } 968 969 public void processMouseEventPublic(MouseEvent e) { 970 processMouseEvent(e); 971 } 972 973 public void processMouseMotionEventPublic(MouseEvent e) { 974 processMouseMotionEvent(e); 975 } 976 977 public void processInputMethodEventPublic(InputMethodEvent e) { 978 processInputMethodEvent(e); 979 } 980 981 @Override 982 public void updateUI() { 983 ComponentUI ui = new AWTTextAreaUI(); 984 setUI(ui); 985 } 986 987 // Fix for 4915454 - override the default implementation to avoid 988 // loading SystemFlavorMap and associated classes. 989 @Override 990 public void setTransferHandler(TransferHandler newHandler) { 991 TransferHandler oldHandler = (TransferHandler) 992 getClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 993 .getJComponent_TRANSFER_HANDLER()); 994 putClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 995 .getJComponent_TRANSFER_HANDLER(), 996 newHandler); 997 998 firePropertyChange("transferHandler", oldHandler, newHandler); 999 } 1000 } 1001 1002 final class XAWTScrollPaneUI extends BasicScrollPaneUI { 1003 1004 private final Border vsbMarginBorderR = new EmptyBorder(0, 2, 0, 0); 1005 private final Border vsbMarginBorderL = new EmptyBorder(0, 0, 0, 2); 1006 private final Border hsbMarginBorder = new EmptyBorder(2, 0, 0, 0); 1007 1008 private Border vsbBorder; 1009 private Border hsbBorder; 1010 1011 private PropertyChangeListener propertyChangeHandler; 1012 1013 @Override 1014 protected void installListeners(JScrollPane scrollPane) { 1015 super.installListeners(scrollPane); 1016 propertyChangeHandler = createPropertyChangeHandler(); 1017 scrollPane.addPropertyChangeListener(propertyChangeHandler); 1018 } 1019 1020 @Override 1021 public void paint(Graphics g, JComponent c) { 1022 Border vpBorder = scrollpane.getViewportBorder(); 1023 if (vpBorder != null) { 1024 Rectangle r = scrollpane.getViewportBorderBounds(); 1025 vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); 1026 } 1027 } 1028 1029 @Override 1030 protected void uninstallListeners(JComponent scrollPane) { 1031 super.uninstallListeners(scrollPane); 1032 scrollPane.removePropertyChangeListener(propertyChangeHandler); 1033 } 1034 1035 private PropertyChangeListener createPropertyChangeHandler() { 1036 return new PropertyChangeListener() { 1037 @Override 1038 public void propertyChange(PropertyChangeEvent e) { 1039 String propertyName = e.getPropertyName(); 1040 1041 if (propertyName.equals("componentOrientation")) { 1042 JScrollPane pane = (JScrollPane)e.getSource(); 1043 JScrollBar vsb = pane.getVerticalScrollBar(); 1044 if (vsb != null) { 1045 if (isLeftToRight(pane)) { 1046 vsbBorder = new CompoundBorder(new EmptyBorder(0, 4, 0, -4), 1047 vsb.getBorder()); 1048 } else { 1049 vsbBorder = new CompoundBorder(new EmptyBorder(0, -4, 0, 4), 1050 vsb.getBorder()); 1051 } 1052 vsb.setBorder(vsbBorder); 1053 } 1054 } 1055 }}; 1056 } 1057 1058 boolean isLeftToRight( Component c ) { 1059 return c.getComponentOrientation().isLeftToRight(); 1060 } 1061 1062 @Override 1063 protected void installDefaults(JScrollPane scrollpane) { 1064 Border b = scrollpane.getBorder(); 1065 UIDefaults uidefaults = XToolkit.getUIDefaults(); 1066 scrollpane.setBorder(uidefaults.getBorder("ScrollPane.border")); 1067 scrollpane.setBackground(uidefaults.getColor("ScrollPane.background")); 1068 scrollpane.setViewportBorder(uidefaults.getBorder("TextField.border")); 1069 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1070 if (vsb != null) { 1071 if (isLeftToRight(scrollpane)) { 1072 vsbBorder = new CompoundBorder(vsbMarginBorderR, 1073 vsb.getBorder()); 1074 } 1075 else { 1076 vsbBorder = new CompoundBorder(vsbMarginBorderL, 1077 vsb.getBorder()); 1078 } 1079 vsb.setBorder(vsbBorder); 1080 } 1081 1082 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1083 if (hsb != null) { 1084 hsbBorder = new CompoundBorder(hsbMarginBorder, hsb.getBorder()); 1085 hsb.setBorder(hsbBorder); 1086 } 1087 } 1088 1089 @Override 1090 protected void uninstallDefaults(JScrollPane c) { 1091 super.uninstallDefaults(c); 1092 1093 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1094 if (vsb != null) { 1095 if (vsb.getBorder() == vsbBorder) { 1096 vsb.setBorder(null); 1097 } 1098 vsbBorder = null; 1099 } 1100 1101 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1102 if (hsb != null) { 1103 if (hsb.getBorder() == hsbBorder) { 1104 hsb.setBorder(null); 1105 } 1106 hsbBorder = null; 1107 } 1108 } 1109 } 1110 1111 @SuppressWarnings("serial") // JDK-implementation class 1112 private class AWTTextPane extends JScrollPane implements FocusListener { 1113 1114 private final JTextArea jtext; 1115 private final XWindow xwin; 1116 1117 private final Color control = SystemColor.control; 1118 private final Color focus = SystemColor.activeCaptionBorder; 1119 1120 AWTTextPane(JTextArea jt, XWindow xwin, Container parent) { 1121 super(jt); 1122 this.xwin = xwin; 1123 setDoubleBuffered(true); 1124 jt.addFocusListener(this); 1125 AWTAccessor.getComponentAccessor().setParent(this,parent); 1126 setViewportBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 1127 this.jtext = jt; 1128 setFocusable(false); 1129 addNotify(); 1130 } 1131 1132 @Override 1133 public void invalidate() { 1134 synchronized (getTreeLock()) { 1135 final Container parent = getParent(); 1136 AWTAccessor.getComponentAccessor().setParent(this, null); 1137 try { 1138 super.invalidate(); 1139 } finally { 1140 AWTAccessor.getComponentAccessor().setParent(this, parent); 1141 } 1142 } 1143 } 1144 1145 @Override 1146 public void focusGained(FocusEvent e) { 1147 Graphics g = getGraphics(); 1148 Rectangle r = getViewportBorderBounds(); 1149 g.setColor(focus); 1150 g.drawRect(r.x,r.y,r.width,r.height); 1151 g.dispose(); 1152 } 1153 1154 @Override 1155 public void focusLost(FocusEvent e) { 1156 Graphics g = getGraphics(); 1157 Rectangle r = getViewportBorderBounds(); 1158 g.setColor(control); 1159 g.drawRect(r.x,r.y,r.width,r.height); 1160 g.dispose(); 1161 } 1162 1163 public Window getRealParent() { 1164 return (Window) xwin.target; 1165 } 1166 1167 @Override 1168 public void updateUI() { 1169 ComponentUI ui = new XAWTScrollPaneUI(); 1170 setUI(ui); 1171 } 1172 1173 @Override 1174 public JScrollBar createVerticalScrollBar() { 1175 return new XAWTScrollBar(JScrollBar.VERTICAL); 1176 } 1177 1178 @Override 1179 public JScrollBar createHorizontalScrollBar() { 1180 return new XAWTScrollBar(JScrollBar.HORIZONTAL); 1181 } 1182 1183 public JTextArea getTextArea () { 1184 return this.jtext; 1185 } 1186 1187 @Override 1188 public Graphics getGraphics() { 1189 return xwin.getGraphics(); 1190 } 1191 1192 @SuppressWarnings("serial") // JDK-implementation class 1193 final class XAWTScrollBar extends ScrollBar { 1194 1195 XAWTScrollBar(int i) { 1196 super(i); 1197 setFocusable(false); 1198 } 1199 1200 @Override 1201 public void updateUI() { 1202 ComponentUI ui = new XAWTScrollBarUI(); 1203 setUI(ui); 1204 } 1205 } 1206 } 1207 1208 @SuppressWarnings("serial") // JDK-implementation class 1209 static class BevelBorder extends AbstractBorder implements UIResource { 1210 private Color darkShadow = SystemColor.controlDkShadow; 1211 private Color lightShadow = SystemColor.controlLtHighlight; 1212 private Color control = SystemColor.controlShadow; 1213 private boolean isRaised; 1214 1215 BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) { 1216 this.isRaised = isRaised; 1217 this.darkShadow = darkShadow; 1218 this.lightShadow = lightShadow; 1219 } 1220 1221 @Override 1222 public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { 1223 g.setColor((isRaised) ? lightShadow : darkShadow); 1224 g.drawLine(x, y, x+w-1, y); // top 1225 g.drawLine(x, y+h-1, x, y+1); // left 1226 1227 g.setColor(control); 1228 g.drawLine(x+1, y+1, x+w-2, y+1); // top 1229 g.drawLine(x+1, y+h-1, x+1, y+1); // left 1230 1231 g.setColor((isRaised) ? darkShadow : lightShadow); 1232 g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom 1233 g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right 1234 1235 g.setColor(control); 1236 g.drawLine(x+1, y+h-2, x+w-2, y+h-2); // bottom 1237 g.drawLine(x+w-2, y+h-2, x+w-2, y+1); // right 1238 } 1239 1240 @Override 1241 public Insets getBorderInsets(Component c) { 1242 return getBorderInsets(c, new Insets(0,0,0,0)); 1243 } 1244 1245 @Override 1246 public Insets getBorderInsets(Component c, Insets insets) { 1247 insets.top = insets.left = insets.bottom = insets.right = 2; 1248 return insets; 1249 } 1250 1251 public boolean isOpaque(Component c) { 1252 return true; 1253 } 1254 } 1255 1256 1257 // This class dispatches 'MouseEvent's to 'XTextAreaPeer''s (hidden) 1258 // subcomponents, and overrides mouse cursor, e.g. for scrollbars. 1259 // 1260 // However, current dispatching is a kind of fake, and is tuned to do only 1261 // what is necessary/possible. E.g. no additional mouse-exited/entered 1262 // events are generated, when mouse exits scrollbar and enters viewport 1263 // with JTextArea inside. Actually, no events are ever generated here (for 1264 // now). They are only dispatched as correctly as possible/neccessary. 1265 // 1266 // In future, it would be better to replace fake-emulation of grab-detection 1267 // and event-dispatching here, by reusing some common implementation of this 1268 // functionality. Mouse-cursor setting should also be freed of hacked 1269 // overloading here. 1270 1271 private static final class JavaMouseEventHandler { 1272 private final XTextAreaPeer outer; 1273 private final Pointer current = new Pointer(); 1274 private boolean grabbed = false; 1275 1276 JavaMouseEventHandler( XTextAreaPeer outer ) { 1277 this.outer = outer; 1278 } 1279 1280 1281 // 1. We can make grab-tracking emulation here more robust to variations in 1282 // in mouse-events order and consistence. E.g. by using such code: 1283 // if( grabbed && event.getID()==MouseEvent.MOUSE_MOVED ) grabbed = false; 1284 // Or we can also use 'assert'ions. 1285 // 2. WARNING: Currently, while grab-detection mechanism _here_ says, that 1286 // grab is in progress, we do not update 'current'. In case 'current' 1287 // is set to a scrollbar or to a scroll-button, then references to their 1288 // 'Component'-instances are "remembered". And events are dispatched to 1289 // these remembered components, without checking, if XTextAreaPeer has 1290 // replaced these instances with another ones. This also aplies to 1291 // mouse-drags-from-outside (see comment in 'grabbed_update' method). 1292 1293 void handle( MouseEvent event ) { 1294 if ( ! grabbed ) { 1295 // dispatch() needs up-to-date pointer in ungrabbed case. 1296 setPointerToUnderPoint( event.getPoint() ); 1297 } 1298 dispatch( event ); 1299 boolean wasGrabbed = grabbed; 1300 grabbed_update( event ); 1301 if ( wasGrabbed && ! grabbed ) { 1302 setPointerToUnderPoint( event.getPoint() ); 1303 } 1304 setCursor(); 1305 } 1306 1307 // Following is internally private: 1308 1309 // Here dispatching is performed, of 'MouseEvent's to (some) 1310 // 'XTextAreaPeer''s (hidden) subcomponents. 1311 private void dispatch( MouseEvent event ) { 1312 switch( current.getType() ) 1313 { 1314 case TEXT: 1315 Point point = toViewportChildLocalSpace( 1316 outer.textPane.getViewport(), event.getPoint() ); 1317 XTextAreaPeer.AWTTextArea jtext = outer.jtext; 1318 MouseEvent newEvent = newMouseEvent( jtext, point, event ); 1319 int id = newEvent.getID(); 1320 if ( id==MouseEvent.MOUSE_MOVED || id==MouseEvent.MOUSE_DRAGGED ) { 1321 jtext.processMouseMotionEventPublic( newEvent ); 1322 } else { 1323 jtext.processMouseEventPublic( newEvent ); 1324 } 1325 break; 1326 1327 // We perform (additional) dispatching of events to buttons of 1328 // scrollbar, instead of leaving it to JScrollbar. This is 1329 // required, because of different listeners in Swing and AWT, 1330 // which trigger scrolling (ArrowButtonListener vs. TrackListener, 1331 // accordingly). So we dispatch events to scroll-buttons, to 1332 // invoke a correct Swing button listener. 1333 // See CR 6175401 for more information. 1334 case BAR: 1335 case BUTTON: 1336 Component c = current.getBar(); 1337 Point p = toLocalSpace( c, event.getPoint() ); 1338 if ( current.getType()==Pointer.Type.BUTTON ) { 1339 c = current.getButton(); 1340 p = toLocalSpace( c, p ); 1341 } 1342 AWTAccessor.getComponentAccessor().processEvent( c, newMouseEvent( c, p, event ) ); 1343 break; 1344 } 1345 } 1346 1347 private static MouseEvent newMouseEvent( 1348 Component source, Point point, MouseEvent template ) 1349 { 1350 MouseEvent e = template; 1351 MouseEvent nme = new MouseEvent( 1352 source, 1353 e.getID(), e.getWhen(), 1354 e.getModifiersEx() | e.getModifiers(), 1355 point.x, point.y, 1356 e.getXOnScreen(), e.getYOnScreen(), 1357 e.getClickCount(), e.isPopupTrigger(), e.getButton() ); 1358 // Because these MouseEvents are dispatched directly to 1359 // their target, we need to mark them as being 1360 // system-generated here 1361 SunToolkit.setSystemGenerated(nme); 1362 return nme; 1363 } 1364 1365 private void setCursor() { 1366 if ( current.getType()==Pointer.Type.TEXT ) { 1367 // 'target.getCursor()' is also applied from elsewhere 1368 // (at least now), but only when mouse "entered", and 1369 // before 'XTextAreaPeer.handleJavaMouseEvent' is invoked. 1370 outer.pSetCursor( outer.target.getCursor(), true ); 1371 } 1372 else { 1373 // We can write here a more intelligent cursor selection 1374 // mechanism, like getting cursor from 'current' component. 1375 // However, I see no point in doing so now. But if you feel 1376 // like implementing it, you'll probably need to introduce 1377 // 'Pointer.Type.PANEL'. 1378 outer.pSetCursor( outer.textPane.getCursor(), true ); 1379 } 1380 } 1381 1382 1383 // Current way of grab-detection causes interesting (but harmless) 1384 // side-effect. If mouse is draged from outside to inside of TextArea, 1385 // we will then (in some cases) be asked to dispatch mouse-entered/exited 1386 // events. But, as at least one mouse-button is down, we will detect 1387 // grab-mode is on (though the grab isn't ours). 1388 // 1389 // Thus, we will not update 'current' (see 'handle' method), and will 1390 // dispatch events to the last subcomponent, the 'current' was set to. 1391 // As always, we set cursor in this case also. But, all this seems 1392 // harmless, because mouse entered/exited events seem to have no effect 1393 // here, and cursor setting is ignored in case of drags from outside. 1394 // 1395 // Grab-detection can be further improved, e.g. by taking into account 1396 // current event-ID, but I see not point in doing it now. 1397 1398 private void grabbed_update( MouseEvent event ) { 1399 final int allButtonsMask 1400 = MouseEvent.BUTTON1_DOWN_MASK 1401 | MouseEvent.BUTTON2_DOWN_MASK 1402 | MouseEvent.BUTTON3_DOWN_MASK; 1403 grabbed = ( (event.getModifiersEx() & allButtonsMask) != 0 ); 1404 } 1405 1406 // 'toLocalSpace' and 'toViewportChildLocalSpace' can be "optimized" to 1407 // 'return' 'void' and use 'Point' input-argument also as output. 1408 private static Point toLocalSpace( Component local, Point inParentSpace ) 1409 { 1410 Point p = inParentSpace; 1411 Point l = local.getLocation(); 1412 return new Point( p.x - l.x, p.y - l.y ); 1413 } 1414 private static Point toViewportChildLocalSpace( JViewport v, Point inViewportParentSpace ) 1415 { 1416 Point l = toLocalSpace(v, inViewportParentSpace); 1417 Point p = v.getViewPosition(); 1418 l.x += p.x; 1419 l.y += p.y; 1420 return l; 1421 } 1422 1423 private void setPointerToUnderPoint( Point point ) { 1424 if ( outer.textPane.getViewport().getBounds().contains( point ) ) { 1425 current.setText(); 1426 } 1427 else if ( ! setPointerIfPointOverScrollbar( 1428 outer.textPane.getVerticalScrollBar(), point ) ) 1429 { 1430 if ( ! setPointerIfPointOverScrollbar( 1431 outer.textPane.getHorizontalScrollBar(), point ) ) 1432 { 1433 current.setNone(); 1434 } 1435 } 1436 } 1437 1438 private boolean setPointerIfPointOverScrollbar( JScrollBar bar, Point point ) { 1439 if ( ! bar.getBounds().contains( point ) ) { 1440 return false; 1441 } 1442 current.setBar( bar ); 1443 Point local = toLocalSpace( bar, point ); 1444 1445 XTextAreaPeer.XAWTScrollBarUI ui = 1446 (XTextAreaPeer.XAWTScrollBarUI) bar.getUI(); 1447 1448 if ( ! setPointerIfPointOverButton( ui.getIncreaseButton(), local ) ) { 1449 setPointerIfPointOverButton( ui.getDecreaseButton(), local ); 1450 } 1451 1452 return true; 1453 } 1454 1455 private boolean setPointerIfPointOverButton( JButton button, Point point ) { 1456 if ( ! button.getBounds().contains( point ) ) { 1457 return false; 1458 } 1459 current.setButton( button ); 1460 return true; 1461 } 1462 1463 private static final class Pointer { 1464 static enum Type { 1465 NONE, TEXT, BAR, BUTTON // , PANEL 1466 } 1467 Type getType() { 1468 return type; 1469 } 1470 boolean isNone() { 1471 return type==Type.NONE; 1472 } 1473 JScrollBar getBar() { 1474 boolean ok = type==Type.BAR || type==Type.BUTTON; 1475 assert ok; 1476 return ok ? bar : null; 1477 } 1478 JButton getButton() { 1479 boolean ok = type==Type.BUTTON; 1480 assert ok; 1481 return ok ? button : null; 1482 } 1483 void setNone() { 1484 type = Type.NONE; 1485 } 1486 void setText() { 1487 type = Type.TEXT; 1488 } 1489 void setBar( JScrollBar bar ) { 1490 this.bar=bar; 1491 type=Type.BAR; 1492 } 1493 void setButton( JButton button ) { 1494 this.button=button; 1495 type=Type.BUTTON; 1496 } 1497 1498 private Type type; 1499 private JScrollBar bar; 1500 private JButton button; 1501 } 1502 } 1503 }