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