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 target.enableInputMethods(true); 109 110 firstChangeSkipped = false; 111 String text = ((TextArea)target).getText(); 112 jtext = new AWTTextArea(text, this); 113 jtext.setWrapStyleWord(true); 114 jtext.getDocument().addDocumentListener(jtext); 115 XToolkit.specialPeerMap.put(jtext,this); 116 jtext.enableInputMethods(true); 117 textPane = new AWTTextPane(jtext,this, target.getParent()); 118 119 setBounds(x, y, width, height, SET_BOUNDS); 120 textPane.setVisible(true); 121 textPane.validate(); 122 123 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 124 foreground = compAccessor.getForeground(target); 125 if (foreground == null) { 126 foreground = SystemColor.textText; 127 } 128 setForeground(foreground); 129 130 background = compAccessor.getBackground(target); 131 if (background == null) { 132 if (target.isEditable()) background = SystemColor.text; 133 else background = SystemColor.control; 134 } 135 setBackground(background); 136 137 if (!target.isBackgroundSet()) { 138 // This is a way to set the background color of the TextArea 139 // without calling setBackground - go through accessor 140 compAccessor.setBackground(target, background); 141 } 142 if (!target.isForegroundSet()) { 143 target.setForeground(SystemColor.textText); 144 } 145 146 setFont(font); 147 148 int start = target.getSelectionStart(); 149 int end = target.getSelectionEnd(); 150 151 if (end > start) { 152 select(start, end); 153 } 154 // Fix for 5100200 155 // Restoring Motif behaviour 156 // Since the end position of the selected text can be greater then the length of the text, 157 // so we should set caret to max position of the text 158 int caretPosition = Math.min(end, text.length()); 159 setCaretPosition(caretPosition); 160 161 setEditable(target.isEditable()); 162 163 setScrollBarVisibility(); 164 // set the text of this object to the text of its target 165 setTextImpl(target.getText()); //?? should this be setText 166 167 // After this line we should not change the component's text 168 firstChangeSkipped = true; 169 } 170 171 public void dispose() { 172 XToolkit.specialPeerMap.remove(jtext); 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 // Please note that we do not want to post an event 467 // if setText() replaces an empty text by an empty text, 468 // that is, if component's text remains unchanged. 469 if (jtext.getDocument().getLength() == 0 && txt.length() == 0) { 470 return true; 471 } 472 473 // JTextArea.setText() posts two different events (remove & insert). 474 // Since we make no differences between text events, 475 // the document listener has to be disabled while 476 // JTextArea.setText() is called. 477 jtext.getDocument().removeDocumentListener(jtext); 478 jtext.setText(txt); 479 if (firstChangeSkipped) { 480 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 481 } 482 jtext.getDocument().addDocumentListener(jtext); 483 } 484 return true; 485 } 486 487 /** 488 * insert the text "txt on position "pos" in the array lines 489 * @see java.awt.peer.TextAreaPeer 490 */ 491 public void insert(String txt, int p) { 492 if (jtext != null) { 493 boolean doScroll = (p >= jtext.getDocument().getLength() && jtext.getDocument().getLength() != 0); 494 jtext.insert(txt,p); 495 textPane.validate(); 496 if (doScroll) { 497 JScrollBar bar = textPane.getVerticalScrollBar(); 498 if (bar != null) { 499 bar.setValue(bar.getMaximum()-bar.getVisibleAmount()); 500 } 501 } 502 } 503 } 504 505 /** 506 * replace the text between the position "s" and "e" with "txt" 507 * @see java.awt.peer.TextAreaPeer 508 */ 509 public void replaceRange(String txt, int s, int e) { 510 if (jtext != null) { 511 // JTextArea.replaceRange() posts two different events. 512 // Since we make no differences between text events, 513 // the document listener has to be disabled while 514 // JTextArea.replaceRange() is called. 515 jtext.getDocument().removeDocumentListener(jtext); 516 jtext.replaceRange(txt, s, e); 517 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 518 jtext.getDocument().addDocumentListener(jtext); 519 } 520 } 521 522 /** 523 * to be implemented. 524 * @see java.awt.peer.TextComponentPeer 525 */ 526 public void setCaretPosition(int position) { 527 jtext.setCaretPosition(position); 528 } 529 530 /** 531 * to be implemented. 532 * @see java.awt.peer.TextComponentPeer 533 */ 534 public int getCaretPosition() { 535 return jtext.getCaretPosition(); 536 } 537 538 /** 539 * DEPRECATED 540 * @see java.awt.peer.TextAreaPeer 541 */ 542 public void insertText(String txt, int pos) { 543 insert(txt, pos); 544 } 545 546 /** 547 * DEPRECATED 548 * @see java.awt.peer.TextAreaPeer 549 */ 550 public void replaceText(String txt, int start, int end) { 551 replaceRange(txt, start, end); 552 } 553 554 /** 555 * DEPRECATED 556 * @see java.awt.peer.TextAreaPeer 557 */ 558 public Dimension minimumSize(int rows, int cols) { 559 return getMinimumSize(rows, cols); 560 } 561 562 /** 563 * DEPRECATED 564 * @see java.awt.peer.TextAreaPeer 565 */ 566 public Dimension preferredSize(int rows, int cols) { 567 return getPreferredSize(rows, cols); 568 } 569 570 571 class AWTTextAreaUI extends MotifTextAreaUI { 572 /** 573 * Creates a UI for a JTextArea. 574 * 575 * @param c the text field 576 * @return the UI 577 */ 578 JTextArea jta; 579 580 protected String getPropertyPrefix() { return "TextArea"; } 581 582 public void installUI(JComponent c) { 583 super.installUI(c); 584 585 jta = (JTextArea) c; 586 587 JTextArea editor = jta; 588 589 UIDefaults uidefaults = XToolkit.getUIDefaults(); 590 591 String prefix = getPropertyPrefix(); 592 Font f = editor.getFont(); 593 if ((f == null) || (f instanceof UIResource)) { 594 editor.setFont(uidefaults.getFont(prefix + ".font")); 595 } 596 597 Color bg = editor.getBackground(); 598 if ((bg == null) || (bg instanceof UIResource)) { 599 editor.setBackground(uidefaults.getColor(prefix + ".background")); 600 } 601 602 Color fg = editor.getForeground(); 603 if ((fg == null) || (fg instanceof UIResource)) { 604 editor.setForeground(uidefaults.getColor(prefix + ".foreground")); 605 } 606 607 Color color = editor.getCaretColor(); 608 if ((color == null) || (color instanceof UIResource)) { 609 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); 610 } 611 612 Color s = editor.getSelectionColor(); 613 if ((s == null) || (s instanceof UIResource)) { 614 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); 615 } 616 617 Color sfg = editor.getSelectedTextColor(); 618 if ((sfg == null) || (sfg instanceof UIResource)) { 619 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); 620 } 621 622 Color dfg = editor.getDisabledTextColor(); 623 if ((dfg == null) || (dfg instanceof UIResource)) { 624 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); 625 } 626 627 Border b = new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight); 628 editor.setBorder(new BorderUIResource.CompoundBorderUIResource( 629 b,new EmptyBorder(2, 2, 2, 2))); 630 631 Insets margin = editor.getMargin(); 632 if (margin == null || margin instanceof UIResource) { 633 editor.setMargin(uidefaults.getInsets(prefix + ".margin")); 634 } 635 } 636 637 protected void installKeyboardActions() { 638 super.installKeyboardActions(); 639 640 JTextComponent comp = getComponent(); 641 642 UIDefaults uidefaults = XToolkit.getUIDefaults(); 643 644 String prefix = getPropertyPrefix(); 645 646 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); 647 648 if (map != null) { 649 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, 650 map); 651 } 652 } 653 654 protected Caret createCaret() { 655 return new XAWTCaret(); 656 } 657 } 658 659 660 // TODO : fix this duplicate code 661 class XAWTCaret extends DefaultCaret { 662 public void focusGained(FocusEvent e) { 663 super.focusGained(e); 664 getComponent().repaint(); 665 } 666 667 public void focusLost(FocusEvent e) { 668 super.focusLost(e); 669 getComponent().repaint(); 670 } 671 672 // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit 673 // Restoring Motif behaviour 674 // If the text is unhighlighted then we should sets the selection range to zero 675 public void setSelectionVisible(boolean vis) { 676 if (vis){ 677 super.setSelectionVisible(vis); 678 }else{ 679 // In order to de-select the selection 680 setDot(getDot()); 681 } 682 } 683 } 684 685 686 class XAWTScrollBarButton extends BasicArrowButton 687 { 688 UIDefaults uidefaults = XToolkit.getUIDefaults(); 689 private Color darkShadow = SystemColor.controlShadow; 690 private Color lightShadow = SystemColor.controlLtHighlight; 691 private Color buttonBack = uidefaults.getColor("ScrollBar.track"); 692 693 public XAWTScrollBarButton(int direction) 694 { 695 super(direction); 696 697 switch (direction) { 698 case NORTH: 699 case SOUTH: 700 case EAST: 701 case WEST: 702 this.direction = direction; 703 break; 704 default: 705 throw new IllegalArgumentException("invalid direction"); 706 } 707 708 setRequestFocusEnabled(false); 709 setOpaque(true); 710 setBackground(uidefaults.getColor("ScrollBar.thumb")); 711 setForeground(uidefaults.getColor("ScrollBar.foreground")); 712 } 713 714 public Dimension getPreferredSize() { 715 switch (direction) { 716 case NORTH: 717 case SOUTH: 718 return new Dimension(11, 12); 719 case EAST: 720 case WEST: 721 default: 722 return new Dimension(12, 11); 723 } 724 } 725 726 public Dimension getMinimumSize() { 727 return getPreferredSize(); 728 } 729 730 public Dimension getMaximumSize() { 731 return getPreferredSize(); 732 } 733 734 public boolean isFocusTraversable() { 735 return false; 736 } 737 738 public void paint(Graphics g) 739 { 740 int w = getWidth(); 741 int h = getHeight(); 742 743 if (isOpaque()) { 744 g.setColor(buttonBack); 745 g.fillRect(0, 0, w, h); 746 } 747 748 boolean isPressed = getModel().isPressed(); 749 Color lead = (isPressed) ? darkShadow : lightShadow; 750 Color trail = (isPressed) ? lightShadow : darkShadow; 751 Color fill = getBackground(); 752 753 int cx = w / 2; 754 int cy = h / 2; 755 int s = Math.min(w, h); 756 757 switch (direction) { 758 case NORTH: 759 g.setColor(lead); 760 g.drawLine(cx, 0, cx, 0); 761 for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { 762 g.setColor(lead); 763 g.drawLine(x, y, x, y); 764 if (y >= (s - 2)) { 765 g.drawLine(x, y + 1, x, y + 1); 766 } 767 g.setColor(fill); 768 g.drawLine(x + 1, y, x + dx, y); 769 if (y < (s - 2)) { 770 g.drawLine(x, y + 1, x + dx + 1, y + 1); 771 } 772 g.setColor(trail); 773 g.drawLine(x + dx + 1, y, x + dx + 1, y); 774 if (y >= (s - 2)) { 775 g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); 776 } 777 dx += 2; 778 x -= 1; 779 } 780 break; 781 782 case SOUTH: 783 g.setColor(trail); 784 g.drawLine(cx, s, cx, s); 785 for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { 786 g.setColor(lead); 787 g.drawLine(x, y, x, y); 788 if (y <= 2) { 789 g.drawLine(x, y - 1, x + dx + 1, y - 1); 790 } 791 g.setColor(fill); 792 g.drawLine(x + 1, y, x + dx, y); 793 if (y > 2) { 794 g.drawLine(x, y - 1, x + dx + 1, y - 1); 795 } 796 g.setColor(trail); 797 g.drawLine(x + dx + 1, y, x + dx + 1, y); 798 799 dx += 2; 800 x -= 1; 801 } 802 break; 803 804 case EAST: 805 g.setColor(lead); 806 g.drawLine(s, cy, s, cy); 807 for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { 808 g.setColor(lead); 809 g.drawLine(x, y, x, y); 810 if (x <= 2) { 811 g.drawLine(x - 1, y, x - 1, y + dy + 1); 812 } 813 g.setColor(fill); 814 g.drawLine(x, y + 1, x, y + dy); 815 if (x > 2) { 816 g.drawLine(x - 1, y, x - 1, y + dy + 1); 817 } 818 g.setColor(trail); 819 g.drawLine(x, y + dy + 1, x, y + dy + 1); 820 821 dy += 2; 822 y -= 1; 823 } 824 break; 825 826 case WEST: 827 g.setColor(trail); 828 g.drawLine(0, cy, 0, cy); 829 for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { 830 g.setColor(lead); 831 g.drawLine(x, y, x, y); 832 if (x >= (s - 2)) { 833 g.drawLine(x + 1, y, x + 1, y); 834 } 835 g.setColor(fill); 836 g.drawLine(x, y + 1, x, y + dy); 837 if (x < (s - 2)) { 838 g.drawLine(x + 1, y, x + 1, y + dy + 1); 839 } 840 g.setColor(trail); 841 g.drawLine(x, y + dy + 1, x, y + dy + 1); 842 if (x >= (s - 2)) { 843 g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); 844 } 845 dy += 2; 846 y -= 1; 847 } 848 break; 849 } 850 } 851 } 852 853 854 class XAWTScrollBarUI extends BasicScrollBarUI 855 { 856 public XAWTScrollBarUI() { 857 super(); 858 } 859 860 protected void installDefaults() 861 { 862 super.installDefaults(); 863 scrollbar.setBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 864 } 865 866 protected void configureScrollBarColors() { 867 UIDefaults uidefaults = XToolkit.getUIDefaults(); 868 Color bg = scrollbar.getBackground(); 869 if (bg == null || bg instanceof UIResource) { 870 scrollbar.setBackground(uidefaults.getColor("ScrollBar.background")); 871 } 872 873 Color fg = scrollbar.getForeground(); 874 if (fg == null || fg instanceof UIResource) { 875 scrollbar.setForeground(uidefaults.getColor("ScrollBar.foreground")); 876 } 877 878 thumbHighlightColor = uidefaults.getColor("ScrollBar.thumbHighlight"); 879 thumbLightShadowColor = uidefaults.getColor("ScrollBar.thumbShadow"); 880 thumbDarkShadowColor = uidefaults.getColor("ScrollBar.thumbDarkShadow"); 881 thumbColor = uidefaults.getColor("ScrollBar.thumb"); 882 trackColor = uidefaults.getColor("ScrollBar.track"); 883 884 trackHighlightColor = uidefaults.getColor("ScrollBar.trackHighlight"); 885 886 } 887 888 protected JButton createDecreaseButton(int orientation) { 889 JButton b = new XAWTScrollBarButton(orientation); 890 return b; 891 892 } 893 894 protected JButton createIncreaseButton(int orientation) { 895 JButton b = new XAWTScrollBarButton(orientation); 896 return b; 897 } 898 899 public JButton getDecreaseButton(){ 900 return decrButton; 901 } 902 903 public JButton getIncreaseButton(){ 904 return incrButton; 905 } 906 907 public void paint(Graphics g, JComponent c) { 908 paintTrack(g, c, getTrackBounds()); 909 Rectangle thumbBounds = getThumbBounds(); 910 paintThumb(g, c, thumbBounds); 911 } 912 913 public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) 914 { 915 if(!scrollbar.isEnabled()) { 916 return; 917 } 918 919 if (thumbBounds.isEmpty()) 920 thumbBounds = getTrackBounds(); 921 922 int w = thumbBounds.width; 923 int h = thumbBounds.height; 924 925 g.translate(thumbBounds.x, thumbBounds.y); 926 g.setColor(thumbColor); 927 g.fillRect(0, 0, w-1, h-1); 928 929 g.setColor(thumbHighlightColor); 930 g.drawLine(0, 0, 0, h-1); 931 g.drawLine(1, 0, w-1, 0); 932 933 g.setColor(thumbLightShadowColor); 934 g.drawLine(1, h-1, w-1, h-1); 935 g.drawLine(w-1, 1, w-1, h-2); 936 937 g.translate(-thumbBounds.x, -thumbBounds.y); 938 } 939 } 940 941 942 class AWTTextArea extends JTextArea implements DocumentListener { 943 boolean isFocused = false; 944 XTextAreaPeer peer; 945 946 public AWTTextArea(String text, XTextAreaPeer peer) { 947 super(text); 948 setFocusable(false); 949 this.peer = peer; 950 } 951 952 public void insertUpdate(DocumentEvent e) { 953 if (peer != null) { 954 peer.postEvent(new TextEvent(peer.target, 955 TextEvent.TEXT_VALUE_CHANGED)); 956 } 957 } 958 959 public void removeUpdate(DocumentEvent e) { 960 if (peer != null) { 961 peer.postEvent(new TextEvent(peer.target, 962 TextEvent.TEXT_VALUE_CHANGED)); 963 } 964 } 965 966 public void changedUpdate(DocumentEvent e) { 967 if (peer != null) { 968 peer.postEvent(new TextEvent(peer.target, 969 TextEvent.TEXT_VALUE_CHANGED)); 970 } 971 } 972 973 void forwardFocusGained( FocusEvent e) { 974 isFocused = true; 975 FocusEvent fe = CausedFocusEvent.retarget(e, this); 976 super.processFocusEvent(fe); 977 } 978 979 980 void forwardFocusLost( FocusEvent e) { 981 isFocused = false; 982 FocusEvent fe = CausedFocusEvent.retarget(e, this); 983 super.processFocusEvent(fe); 984 } 985 986 public boolean hasFocus() { 987 return isFocused; 988 } 989 990 public void repaintNow() { 991 paintImmediately(getBounds()); 992 } 993 994 public void processMouseEventPublic(MouseEvent e) { 995 processMouseEvent(e); 996 } 997 998 public void processMouseMotionEventPublic(MouseEvent e) { 999 processMouseMotionEvent(e); 1000 } 1001 1002 public void processInputMethodEventPublic(InputMethodEvent e) { 1003 processInputMethodEvent(e); 1004 } 1005 1006 public void updateUI() { 1007 ComponentUI ui = new AWTTextAreaUI(); 1008 setUI(ui); 1009 } 1010 1011 // Fix for 4915454 - override the default implementation to avoid 1012 // loading SystemFlavorMap and associated classes. 1013 public void setTransferHandler(TransferHandler newHandler) { 1014 TransferHandler oldHandler = (TransferHandler) 1015 getClientProperty(XTextTransferHelper.getTransferHandlerKey()); 1016 putClientProperty(XTextTransferHelper.getTransferHandlerKey(), 1017 newHandler); 1018 1019 firePropertyChange("transferHandler", oldHandler, newHandler); 1020 } 1021 } 1022 1023 1024 class XAWTScrollPaneUI extends BasicScrollPaneUI 1025 { 1026 private final Border vsbMarginBorderR = new EmptyBorder(0, 2, 0, 0); 1027 private final Border vsbMarginBorderL = new EmptyBorder(0, 0, 0, 2); 1028 private final Border hsbMarginBorder = new EmptyBorder(2, 0, 0, 0); 1029 1030 private Border vsbBorder; 1031 private Border hsbBorder; 1032 1033 private PropertyChangeListener propertyChangeHandler; 1034 1035 protected void installListeners(JScrollPane scrollPane) { 1036 super.installListeners(scrollPane); 1037 propertyChangeHandler = createPropertyChangeHandler(); 1038 scrollPane.addPropertyChangeListener(propertyChangeHandler); 1039 } 1040 1041 public void paint(Graphics g, JComponent c) { 1042 Border vpBorder = scrollpane.getViewportBorder(); 1043 if (vpBorder != null) { 1044 Rectangle r = scrollpane.getViewportBorderBounds(); 1045 vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); 1046 } 1047 } 1048 1049 protected void uninstallListeners(JScrollPane scrollPane) { 1050 super.uninstallListeners(scrollPane); 1051 scrollPane.removePropertyChangeListener(propertyChangeHandler); 1052 } 1053 1054 private PropertyChangeListener createPropertyChangeHandler() { 1055 return new PropertyChangeListener() { 1056 public void propertyChange(PropertyChangeEvent e) { 1057 String propertyName = e.getPropertyName(); 1058 1059 if (propertyName.equals("componentOrientation")) { 1060 JScrollPane pane = (JScrollPane)e.getSource(); 1061 JScrollBar vsb = pane.getVerticalScrollBar(); 1062 if (vsb != null) { 1063 if (isLeftToRight(pane)) { 1064 vsbBorder = new CompoundBorder(new EmptyBorder(0, 4, 0, -4), 1065 vsb.getBorder()); 1066 } else { 1067 vsbBorder = new CompoundBorder(new EmptyBorder(0, -4, 0, 4), 1068 vsb.getBorder()); 1069 } 1070 vsb.setBorder(vsbBorder); 1071 } 1072 } 1073 }}; 1074 } 1075 1076 boolean isLeftToRight( Component c ) { 1077 return c.getComponentOrientation().isLeftToRight(); 1078 } 1079 1080 1081 protected void installDefaults(JScrollPane scrollpane) { 1082 Border b = scrollpane.getBorder(); 1083 UIDefaults uidefaults = XToolkit.getUIDefaults(); 1084 scrollpane.setBorder(uidefaults.getBorder("ScrollPane.border")); 1085 scrollpane.setBackground(uidefaults.getColor("ScrollPane.background")); 1086 scrollpane.setViewportBorder(uidefaults.getBorder("TextField.border")); 1087 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1088 if (vsb != null) { 1089 if (isLeftToRight(scrollpane)) { 1090 vsbBorder = new CompoundBorder(vsbMarginBorderR, 1091 vsb.getBorder()); 1092 } 1093 else { 1094 vsbBorder = new CompoundBorder(vsbMarginBorderL, 1095 vsb.getBorder()); 1096 } 1097 vsb.setBorder(vsbBorder); 1098 } 1099 1100 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1101 if (hsb != null) { 1102 hsbBorder = new CompoundBorder(hsbMarginBorder, hsb.getBorder()); 1103 hsb.setBorder(hsbBorder); 1104 } 1105 } 1106 1107 protected void uninstallDefaults(JScrollPane c) { 1108 super.uninstallDefaults(c); 1109 1110 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1111 if (vsb != null) { 1112 if (vsb.getBorder() == vsbBorder) { 1113 vsb.setBorder(null); 1114 } 1115 vsbBorder = null; 1116 } 1117 1118 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1119 if (hsb != null) { 1120 if (hsb.getBorder() == hsbBorder) { 1121 hsb.setBorder(null); 1122 } 1123 hsbBorder = null; 1124 } 1125 } 1126 } 1127 1128 1129 private class AWTTextPane extends JScrollPane implements FocusListener { 1130 JTextArea jtext; 1131 XWindow xwin; 1132 1133 Color control = SystemColor.control; 1134 Color focus = SystemColor.activeCaptionBorder; 1135 1136 public AWTTextPane(JTextArea jt, XWindow xwin, Container parent) { 1137 super(jt); 1138 this.xwin = xwin; 1139 setDoubleBuffered(true); 1140 jt.addFocusListener(this); 1141 AWTAccessor.getComponentAccessor().setParent(this,parent); 1142 setViewportBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 1143 this.jtext = jt; 1144 setFocusable(false); 1145 addNotify(); 1146 } 1147 1148 public void focusGained(FocusEvent e) { 1149 Graphics g = getGraphics(); 1150 Rectangle r = getViewportBorderBounds(); 1151 g.setColor(focus); 1152 g.drawRect(r.x,r.y,r.width,r.height); 1153 g.dispose(); 1154 } 1155 1156 public void focusLost(FocusEvent e) { 1157 Graphics g = getGraphics(); 1158 Rectangle r = getViewportBorderBounds(); 1159 g.setColor(control); 1160 g.drawRect(r.x,r.y,r.width,r.height); 1161 g.dispose(); 1162 } 1163 1164 public Window getRealParent() { 1165 return (Window) xwin.target; 1166 } 1167 1168 public ComponentPeer getPeer() { 1169 return (ComponentPeer) (xwin); 1170 } 1171 1172 public void updateUI() { 1173 ComponentUI ui = new XAWTScrollPaneUI(); 1174 setUI(ui); 1175 } 1176 1177 public JScrollBar createVerticalScrollBar() { 1178 return new XAWTScrollBar(JScrollBar.VERTICAL); 1179 } 1180 1181 public JScrollBar createHorizontalScrollBar() { 1182 return new XAWTScrollBar(JScrollBar.HORIZONTAL); 1183 } 1184 1185 public JTextArea getTextArea () { 1186 return this.jtext; 1187 } 1188 1189 public Graphics getGraphics() { 1190 return xwin.getGraphics(); 1191 } 1192 1193 1194 class XAWTScrollBar extends ScrollBar { 1195 1196 public XAWTScrollBar(int i) { 1197 super(i); 1198 setFocusable(false); 1199 } 1200 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 public BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) { 1215 this.isRaised = isRaised; 1216 this.darkShadow = darkShadow; 1217 this.lightShadow = lightShadow; 1218 } 1219 1220 public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { 1221 g.setColor((isRaised) ? lightShadow : darkShadow); 1222 g.drawLine(x, y, x+w-1, y); // top 1223 g.drawLine(x, y+h-1, x, y+1); // left 1224 1225 g.setColor(control); 1226 g.drawLine(x+1, y+1, x+w-2, y+1); // top 1227 g.drawLine(x+1, y+h-1, x+1, y+1); // left 1228 1229 g.setColor((isRaised) ? darkShadow : lightShadow); 1230 g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom 1231 g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right 1232 1233 g.setColor(control); 1234 g.drawLine(x+1, y+h-2, x+w-2, y+h-2); // bottom 1235 g.drawLine(x+w-2, y+h-2, x+w-2, y+1); // right 1236 } 1237 1238 public Insets getBorderInsets(Component c) { 1239 return getBorderInsets(c, new Insets(0,0,0,0)); 1240 } 1241 1242 public Insets getBorderInsets(Component c, Insets insets) { 1243 insets.top = insets.left = insets.bottom = insets.right = 2; 1244 return insets; 1245 } 1246 1247 public boolean isOpaque(Component c) { 1248 return true; 1249 } 1250 } 1251 1252 1253 // This class dispatches 'MouseEvent's to 'XTextAreaPeer''s (hidden) 1254 // subcomponents, and overrides mouse cursor, e.g. for scrollbars. 1255 // 1256 // However, current dispatching is a kind of fake, and is tuned to do only 1257 // what is necessary/possible. E.g. no additional mouse-exited/entered 1258 // events are generated, when mouse exits scrollbar and enters viewport 1259 // with JTextArea inside. Actually, no events are ever generated here (for 1260 // now). They are only dispatched as correctly as possible/neccessary. 1261 // 1262 // In future, it would be better to replace fake-emulation of grab-detection 1263 // and event-dispatching here, by reusing some common implementation of this 1264 // functionality. Mouse-cursor setting should also be freed of hacked 1265 // overloading here. 1266 1267 private static final class JavaMouseEventHandler { 1268 private final XTextAreaPeer outer; 1269 private final Pointer current = new Pointer(); 1270 private boolean grabbed = false; 1271 1272 JavaMouseEventHandler( XTextAreaPeer outer ) { 1273 this.outer = outer; 1274 } 1275 1276 1277 // 1. We can make grab-tracking emulation here more robust to variations in 1278 // in mouse-events order and consistence. E.g. by using such code: 1279 // if( grabbed && event.getID()==MouseEvent.MOUSE_MOVED ) grabbed = false; 1280 // Or we can also use 'assert'ions. 1281 // 2. WARNING: Currently, while grab-detection mechanism _here_ says, that 1282 // grab is in progress, we do not update 'current'. In case 'current' 1283 // is set to a scrollbar or to a scroll-button, then references to their 1284 // 'Component'-instances are "remembered". And events are dispatched to 1285 // these remembered components, without checking, if XTextAreaPeer has 1286 // replaced these instances with another ones. This also aplies to 1287 // mouse-drags-from-outside (see comment in 'grabbed_update' method). 1288 1289 void handle( MouseEvent event ) { 1290 if ( ! grabbed ) { 1291 // dispatch() needs up-to-date pointer in ungrabbed case. 1292 setPointerToUnderPoint( event.getPoint() ); 1293 } 1294 dispatch( event ); 1295 boolean wasGrabbed = grabbed; 1296 grabbed_update( event ); 1297 if ( wasGrabbed && ! grabbed ) { 1298 setPointerToUnderPoint( event.getPoint() ); 1299 } 1300 setCursor(); 1301 } 1302 1303 // Following is internally private: 1304 1305 // Here dispatching is performed, of 'MouseEvent's to (some) 1306 // 'XTextAreaPeer''s (hidden) subcomponents. 1307 private void dispatch( MouseEvent event ) { 1308 switch( current.getType() ) 1309 { 1310 case TEXT: 1311 Point point = toViewportChildLocalSpace( 1312 outer.textPane.getViewport(), event.getPoint() ); 1313 XTextAreaPeer.AWTTextArea jtext = outer.jtext; 1314 MouseEvent newEvent = newMouseEvent( jtext, point, event ); 1315 int id = newEvent.getID(); 1316 if ( id==MouseEvent.MOUSE_MOVED || id==MouseEvent.MOUSE_DRAGGED ) { 1317 jtext.processMouseMotionEventPublic( newEvent ); 1318 } else { 1319 jtext.processMouseEventPublic( newEvent ); 1320 } 1321 break; 1322 1323 // We perform (additional) dispatching of events to buttons of 1324 // scrollbar, instead of leaving it to JScrollbar. This is 1325 // required, because of different listeners in Swing and AWT, 1326 // which trigger scrolling (ArrowButtonListener vs. TrackListener, 1327 // accordingly). So we dispatch events to scroll-buttons, to 1328 // invoke a correct Swing button listener. 1329 // See CR 6175401 for more information. 1330 case BAR: 1331 case BUTTON: 1332 Component c = current.getBar(); 1333 Point p = toLocalSpace( c, event.getPoint() ); 1334 if ( current.getType()==Pointer.Type.BUTTON ) { 1335 c = current.getButton(); 1336 p = toLocalSpace( c, p ); 1337 } 1338 AWTAccessor.getComponentAccessor().processEvent( c, newMouseEvent( c, p, event ) ); 1339 break; 1340 } 1341 } 1342 1343 private static MouseEvent newMouseEvent( 1344 Component source, Point point, MouseEvent template ) 1345 { 1346 MouseEvent e = template; 1347 MouseEvent nme = new MouseEvent( 1348 source, 1349 e.getID(), e.getWhen(), 1350 e.getModifiersEx() | e.getModifiers(), 1351 point.x, point.y, 1352 e.getXOnScreen(), e.getYOnScreen(), 1353 e.getClickCount(), e.isPopupTrigger(), e.getButton() ); 1354 // Because these MouseEvents are dispatched directly to 1355 // their target, we need to mark them as being 1356 // system-generated here 1357 SunToolkit.setSystemGenerated(nme); 1358 return nme; 1359 } 1360 1361 private void setCursor() { 1362 if ( current.getType()==Pointer.Type.TEXT ) { 1363 // 'target.getCursor()' is also applied from elsewhere 1364 // (at least now), but only when mouse "entered", and 1365 // before 'XTextAreaPeer.handleJavaMouseEvent' is invoked. 1366 outer.pSetCursor( outer.target.getCursor(), true ); 1367 } 1368 else { 1369 // We can write here a more intelligent cursor selection 1370 // mechanism, like getting cursor from 'current' component. 1371 // However, I see no point in doing so now. But if you feel 1372 // like implementing it, you'll probably need to introduce 1373 // 'Pointer.Type.PANEL'. 1374 outer.pSetCursor( outer.textPane.getCursor(), true ); 1375 } 1376 } 1377 1378 1379 // Current way of grab-detection causes interesting (but harmless) 1380 // side-effect. If mouse is draged from outside to inside of TextArea, 1381 // we will then (in some cases) be asked to dispatch mouse-entered/exited 1382 // events. But, as at least one mouse-button is down, we will detect 1383 // grab-mode is on (though the grab isn't ours). 1384 // 1385 // Thus, we will not update 'current' (see 'handle' method), and will 1386 // dispatch events to the last subcomponent, the 'current' was set to. 1387 // As always, we set cursor in this case also. But, all this seems 1388 // harmless, because mouse entered/exited events seem to have no effect 1389 // here, and cursor setting is ignored in case of drags from outside. 1390 // 1391 // Grab-detection can be further improved, e.g. by taking into account 1392 // current event-ID, but I see not point in doing it now. 1393 1394 private void grabbed_update( MouseEvent event ) { 1395 final int allButtonsMask 1396 = MouseEvent.BUTTON1_DOWN_MASK 1397 | MouseEvent.BUTTON2_DOWN_MASK 1398 | MouseEvent.BUTTON3_DOWN_MASK; 1399 grabbed = ( (event.getModifiersEx() & allButtonsMask) != 0 ); 1400 } 1401 1402 // 'toLocalSpace' and 'toViewportChildLocalSpace' can be "optimized" to 1403 // 'return' 'void' and use 'Point' input-argument also as output. 1404 private static Point toLocalSpace( Component local, Point inParentSpace ) 1405 { 1406 Point p = inParentSpace; 1407 Point l = local.getLocation(); 1408 return new Point( p.x - l.x, p.y - l.y ); 1409 } 1410 private static Point toViewportChildLocalSpace( JViewport v, Point inViewportParentSpace ) 1411 { 1412 Point l = toLocalSpace(v, inViewportParentSpace); 1413 Point p = v.getViewPosition(); 1414 l.x += p.x; 1415 l.y += p.y; 1416 return l; 1417 } 1418 1419 private void setPointerToUnderPoint( Point point ) { 1420 if ( outer.textPane.getViewport().getBounds().contains( point ) ) { 1421 current.setText(); 1422 } 1423 else if ( ! setPointerIfPointOverScrollbar( 1424 outer.textPane.getVerticalScrollBar(), point ) ) 1425 { 1426 if ( ! setPointerIfPointOverScrollbar( 1427 outer.textPane.getHorizontalScrollBar(), point ) ) 1428 { 1429 current.setNone(); 1430 } 1431 } 1432 } 1433 1434 private boolean setPointerIfPointOverScrollbar( JScrollBar bar, Point point ) { 1435 if ( ! bar.getBounds().contains( point ) ) { 1436 return false; 1437 } 1438 current.setBar( bar ); 1439 Point local = toLocalSpace( bar, point ); 1440 1441 XTextAreaPeer.XAWTScrollBarUI ui = 1442 (XTextAreaPeer.XAWTScrollBarUI) bar.getUI(); 1443 1444 if ( ! setPointerIfPointOverButton( ui.getIncreaseButton(), local ) ) { 1445 setPointerIfPointOverButton( ui.getDecreaseButton(), local ); 1446 } 1447 1448 return true; 1449 } 1450 1451 private boolean setPointerIfPointOverButton( JButton button, Point point ) { 1452 if ( ! button.getBounds().contains( point ) ) { 1453 return false; 1454 } 1455 current.setButton( button ); 1456 return true; 1457 } 1458 1459 private static final class Pointer { 1460 static enum Type { 1461 NONE, TEXT, BAR, BUTTON // , PANEL 1462 } 1463 Type getType() { 1464 return type; 1465 } 1466 boolean isNone() { 1467 return type==Type.NONE; 1468 } 1469 JScrollBar getBar() { 1470 boolean ok = type==Type.BAR || type==Type.BUTTON; 1471 assert ok; 1472 return ok ? bar : null; 1473 } 1474 JButton getButton() { 1475 boolean ok = type==Type.BUTTON; 1476 assert ok; 1477 return ok ? button : null; 1478 } 1479 void setNone() { 1480 type = Type.NONE; 1481 } 1482 void setText() { 1483 type = Type.TEXT; 1484 } 1485 void setBar( JScrollBar bar ) { 1486 this.bar=bar; 1487 type=Type.BAR; 1488 } 1489 void setButton( JButton button ) { 1490 this.button=button; 1491 type=Type.BUTTON; 1492 } 1493 1494 private Type type; 1495 private JScrollBar bar; 1496 private JButton button; 1497 } 1498 } 1499 }