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