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