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