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