1 /* 2 * Copyright (c) 2003, 2014, 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 final class XTextAreaPeer extends XComponentPeer implements TextAreaPeer { 67 68 private final AWTTextPane textPane; 69 private final AWTTextArea jtext; 70 private final boolean firstChangeSkipped; 71 72 private final JavaMouseEventHandler javaMouseEventHandler = 73 new JavaMouseEventHandler(this); 74 75 /** 76 * Create a Text area. 77 */ 78 XTextAreaPeer(TextArea target) { 79 super(target); 80 81 // some initializations require that target be set even 82 // though init(target) has not been called 83 this.target = target; 84 85 //ComponentAccessor.enableEvents(target,AWTEvent.MOUSE_WHEEL_EVENT_MASK); 86 87 String text = target.getText(); 88 jtext = new AWTTextArea(text, this); 89 jtext.setWrapStyleWord(true); 90 jtext.getDocument().addDocumentListener(jtext); 91 XToolkit.specialPeerMap.put(jtext,this); 92 textPane = new AWTTextPane(jtext,this, target.getParent()); 93 94 setBounds(x, y, width, height, SET_BOUNDS); 95 textPane.setVisible(true); 96 textPane.validate(); 97 98 AWTAccessor.ComponentAccessor compAccessor = AWTAccessor.getComponentAccessor(); 99 foreground = compAccessor.getForeground(target); 100 if (foreground == null) { 101 foreground = SystemColor.textText; 102 } 103 setForeground(foreground); 104 105 background = compAccessor.getBackground(target); 106 if (background == null) { 107 if (target.isEditable()) background = SystemColor.text; 108 else background = SystemColor.control; 109 } 110 setBackground(background); 111 112 if (!target.isBackgroundSet()) { 113 // This is a way to set the background color of the TextArea 114 // without calling setBackground - go through accessor 115 compAccessor.setBackground(target, background); 116 } 117 if (!target.isForegroundSet()) { 118 target.setForeground(SystemColor.textText); 119 } 120 121 setFont(font); 122 123 // set the text of this object to the text of its target 124 setTextImpl(target.getText()); //?? should this be setText 125 126 int start = target.getSelectionStart(); 127 int end = target.getSelectionEnd(); 128 // Fix for 5100200 129 // Restoring Motif behaviour 130 // Since the end position of the selected text can be greater then the length of the text, 131 // so we should set caret to max position of the text 132 setCaretPosition(Math.min(end, text.length())); 133 if (end > start) { 134 // Should be called after setText() and setCaretPosition() 135 select(start, end); 136 } 137 setEditable(target.isEditable()); 138 setScrollBarVisibility(); 139 // After this line we should not change the component's text 140 firstChangeSkipped = true; 141 } 142 143 @Override 144 public void dispose() { 145 XToolkit.specialPeerMap.remove(jtext); 146 // visible caret has a timer thread which must be stopped 147 jtext.getCaret().setVisible(false); 148 jtext.removeNotify(); 149 textPane.removeNotify(); 150 super.dispose(); 151 } 152 153 /* 154 * The method overrides one from XComponentPeer 155 * If ignoreSubComponents=={@code true} it calls super. 156 * If ignoreSubComponents=={@code false} it uses the XTextArea machinery 157 * to change cursor appropriately. In particular it changes the cursor to 158 * default if over scrollbars. 159 */ 160 @Override 161 public void pSetCursor(Cursor cursor, boolean ignoreSubComponents) { 162 if (ignoreSubComponents || 163 javaMouseEventHandler == null) { 164 super.pSetCursor(cursor, true); 165 return; 166 } 167 168 Point cursorPos = new Point(); 169 ((XGlobalCursorManager)XGlobalCursorManager.getCursorManager()).getCursorPos(cursorPos); 170 171 final Point onScreen = getLocationOnScreen(); 172 Point localPoint = new Point(cursorPos.x - onScreen.x, cursorPos.y - onScreen.y ); 173 174 javaMouseEventHandler.setPointerToUnderPoint(localPoint); 175 javaMouseEventHandler.setCursor(); 176 } 177 178 private void setScrollBarVisibility() { 179 int visibility = ((TextArea)target).getScrollbarVisibility(); 180 jtext.setLineWrap(false); 181 182 if (visibility == TextArea.SCROLLBARS_NONE) { 183 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 184 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 185 jtext.setLineWrap(true); 186 } 187 else if (visibility == TextArea.SCROLLBARS_BOTH) { 188 189 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 190 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 191 } 192 else if (visibility == TextArea.SCROLLBARS_VERTICAL_ONLY) { 193 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_NEVER); 194 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS); 195 jtext.setLineWrap(true); 196 } 197 else if (visibility == TextArea.SCROLLBARS_HORIZONTAL_ONLY) { 198 textPane.setVerticalScrollBarPolicy(JScrollPane.VERTICAL_SCROLLBAR_NEVER); 199 textPane.setHorizontalScrollBarPolicy(JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS); 200 } 201 } 202 203 /** 204 * Compute minimum size. 205 */ 206 @Override 207 public Dimension getMinimumSize() { 208 return getMinimumSize(10, 60); 209 } 210 211 @Override 212 public Dimension getPreferredSize(int rows, int cols) { 213 return getMinimumSize(rows, cols); 214 } 215 216 /** 217 * @see java.awt.peer.TextAreaPeer 218 */ 219 @Override 220 public Dimension getMinimumSize(int rows, int cols) { 221 /* Dimension d = null; 222 if (jtext != null) { 223 d = jtext.getMinimumSize(rows,cols); 224 } 225 return d; 226 */ 227 228 int vsbwidth=0; 229 int hsbheight=0; 230 231 JScrollBar vsb = textPane.getVerticalScrollBar(); 232 if (vsb != null) { 233 vsbwidth = vsb.getMinimumSize().width; 234 } 235 236 JScrollBar hsb = textPane.getHorizontalScrollBar(); 237 if (hsb != null) { 238 hsbheight = hsb.getMinimumSize().height; 239 } 240 241 Font f = jtext.getFont(); 242 FontMetrics fm = jtext.getFontMetrics(f); 243 244 return new Dimension(fm.charWidth('0') * cols + /*2*XMARGIN +*/ vsbwidth, 245 fm.getHeight() * rows + /*2*YMARGIN +*/ hsbheight); 246 } 247 248 @Override 249 public boolean isFocusable() { 250 return true; 251 } 252 253 @Override 254 public void setVisible(boolean b) { 255 super.setVisible(b); 256 if (textPane != null) 257 textPane.setVisible(b); 258 } 259 260 void repaintText() { 261 jtext.repaintNow(); 262 } 263 264 @Override 265 public void focusGained(FocusEvent e) { 266 super.focusGained(e); 267 jtext.forwardFocusGained(e); 268 } 269 270 @Override 271 public void focusLost(FocusEvent e) { 272 super.focusLost(e); 273 jtext.forwardFocusLost(e); 274 } 275 276 /** 277 * Paint the component 278 * this method is called when the repaint instruction has been used 279 */ 280 @Override 281 public void repaint() { 282 if (textPane != null) { 283 //textPane.validate(); 284 textPane.repaint(); 285 } 286 } 287 288 @Override 289 void paintPeer(final Graphics g) { 290 if (textPane != null) { 291 textPane.paint(g); 292 } 293 } 294 295 @Override 296 public void setBounds(int x, int y, int width, int height, int op) { 297 super.setBounds(x, y, width, height, op); 298 if (textPane != null) { 299 /* 300 * Fixed 6277332, 6198290: 301 * the coordinates is coming (to peer): relatively to closest HW parent 302 * the coordinates is setting (to textPane): relatively to closest ANY parent 303 * the parent of peer is target.getParent() 304 * the parent of textPane is the same 305 * see 6277332, 6198290 for more information 306 */ 307 int childX = x; 308 int childY = y; 309 Component parent = target.getParent(); 310 // we up to heavyweight parent in order to be sure 311 // that the coordinates of the text pane is relatively to closest parent 312 while (parent.isLightweight()){ 313 childX -= parent.getX(); 314 childY -= parent.getY(); 315 parent = parent.getParent(); 316 } 317 textPane.setBounds(childX,childY,width,height); 318 textPane.validate(); 319 } 320 } 321 322 @Override 323 void handleJavaKeyEvent(KeyEvent e) { 324 AWTAccessor.getComponentAccessor().processEvent(jtext,e); 325 } 326 327 @Override 328 public boolean handlesWheelScrolling() { return true; } 329 330 @Override 331 void handleJavaMouseWheelEvent(MouseWheelEvent e) { 332 AWTAccessor.getComponentAccessor().processEvent(textPane, e); 333 } 334 335 @Override 336 public void handleJavaMouseEvent( MouseEvent e ) { 337 super.handleJavaMouseEvent( e ); 338 javaMouseEventHandler.handle( e ); 339 } 340 341 @Override 342 void handleJavaInputMethodEvent(InputMethodEvent e) { 343 if (jtext != null) 344 jtext.processInputMethodEventPublic(e); 345 } 346 347 /** 348 * @see java.awt.peer.TextComponentPeer 349 */ 350 @Override 351 public void select(int s, int e) { 352 jtext.select(s, e); 353 // Fixed 5100806 354 // We must take care that Swing components repainted correctly 355 jtext.repaint(); 356 } 357 358 @Override 359 public void setBackground(Color c) { 360 super.setBackground(c); 361 // synchronized (getStateLock()) { 362 // background = c; 363 // } 364 if (jtext != null) { 365 jtext.setBackground(c); 366 jtext.setSelectedTextColor(c); 367 } 368 // repaintText(); 369 } 370 371 @Override 372 public void setForeground(Color c) { 373 super.setForeground(c); 374 // synchronized (getStateLock()) { 375 // foreground = c; 376 // } 377 if (jtext != null) { 378 jtext.setForeground(foreground); 379 jtext.setSelectionColor(foreground); 380 jtext.setCaretColor(foreground); 381 } 382 // repaintText(); 383 } 384 385 @Override 386 public void setFont(Font f) { 387 super.setFont(f); 388 // synchronized (getStateLock()) { 389 // font = f; 390 // } 391 if (jtext != null) { 392 jtext.setFont(font); 393 } 394 textPane.validate(); 395 } 396 397 /** 398 * @see java.awt.peer.TextComponentPeer 399 */ 400 @Override 401 public void setEditable(boolean editable) { 402 if (jtext != null) jtext.setEditable(editable); 403 repaintText(); 404 } 405 406 /** 407 * @see java.awt.peer.ComponentPeer 408 */ 409 @Override 410 public void setEnabled(boolean enabled) { 411 super.setEnabled(enabled); 412 if (jtext != null) { 413 jtext.setEnabled(enabled); 414 jtext.repaint(); 415 } 416 } 417 418 /** 419 * @see java.awt.peer.TextComponentPeer 420 */ 421 @Override 422 public InputMethodRequests getInputMethodRequests() { 423 if (jtext != null) return jtext.getInputMethodRequests(); 424 else return null; 425 } 426 427 /** 428 * @see java.awt.peer.TextComponentPeer 429 */ 430 @Override 431 public int getSelectionStart() { 432 return jtext.getSelectionStart(); 433 } 434 435 /** 436 * @see java.awt.peer.TextComponentPeer 437 */ 438 @Override 439 public int getSelectionEnd() { 440 return jtext.getSelectionEnd(); 441 } 442 443 /** 444 * @see java.awt.peer.TextComponentPeer 445 */ 446 @Override 447 public String getText() { 448 return jtext.getText(); 449 } 450 451 /** 452 * @see java.awt.peer.TextComponentPeer 453 */ 454 @Override 455 public void setText(String text) { 456 setTextImpl(text); 457 repaintText(); 458 } 459 460 private void setTextImpl(String txt) { 461 if (jtext != null) { 462 // JTextArea.setText() posts two different events (remove & insert). 463 // Since we make no differences between text events, 464 // the document listener has to be disabled while 465 // JTextArea.setText() is called. 466 jtext.getDocument().removeDocumentListener(jtext); 467 jtext.setText(txt); 468 if (firstChangeSkipped) { 469 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 470 } 471 jtext.getDocument().addDocumentListener(jtext); 472 } 473 } 474 475 /** 476 * insert the text "txt on position "pos" in the array lines 477 * @see java.awt.peer.TextAreaPeer 478 */ 479 @Override 480 public void insert(String txt, int p) { 481 if (jtext != null) { 482 boolean doScroll = (p >= jtext.getDocument().getLength() && jtext.getDocument().getLength() != 0); 483 jtext.insert(txt,p); 484 textPane.validate(); 485 if (doScroll) { 486 JScrollBar bar = textPane.getVerticalScrollBar(); 487 if (bar != null) { 488 bar.setValue(bar.getMaximum()-bar.getVisibleAmount()); 489 } 490 } 491 } 492 } 493 494 /** 495 * replace the text between the position "s" and "e" with "txt" 496 * @see java.awt.peer.TextAreaPeer 497 */ 498 @Override 499 public void replaceRange(String txt, int s, int e) { 500 if (jtext != null) { 501 // JTextArea.replaceRange() posts two different events. 502 // Since we make no differences between text events, 503 // the document listener has to be disabled while 504 // JTextArea.replaceRange() is called. 505 jtext.getDocument().removeDocumentListener(jtext); 506 jtext.replaceRange(txt, s, e); 507 postEvent(new TextEvent(target, TextEvent.TEXT_VALUE_CHANGED)); 508 jtext.getDocument().addDocumentListener(jtext); 509 } 510 } 511 512 /** 513 * to be implemented. 514 * @see java.awt.peer.TextComponentPeer 515 */ 516 @Override 517 public void setCaretPosition(int position) { 518 jtext.setCaretPosition(position); 519 } 520 521 /** 522 * to be implemented. 523 * @see java.awt.peer.TextComponentPeer 524 */ 525 @Override 526 public int getCaretPosition() { 527 return jtext.getCaretPosition(); 528 } 529 530 final class AWTTextAreaUI extends MotifTextAreaUI { 531 532 private JTextArea jta; 533 534 @Override 535 protected String getPropertyPrefix() { return "TextArea"; } 536 537 @Override 538 public void installUI(JComponent c) { 539 super.installUI(c); 540 541 jta = (JTextArea) c; 542 543 JTextArea editor = jta; 544 545 UIDefaults uidefaults = XToolkit.getUIDefaults(); 546 547 String prefix = getPropertyPrefix(); 548 Font f = editor.getFont(); 549 if ((f == null) || (f instanceof UIResource)) { 550 editor.setFont(uidefaults.getFont(prefix + ".font")); 551 } 552 553 Color bg = editor.getBackground(); 554 if ((bg == null) || (bg instanceof UIResource)) { 555 editor.setBackground(uidefaults.getColor(prefix + ".background")); 556 } 557 558 Color fg = editor.getForeground(); 559 if ((fg == null) || (fg instanceof UIResource)) { 560 editor.setForeground(uidefaults.getColor(prefix + ".foreground")); 561 } 562 563 Color color = editor.getCaretColor(); 564 if ((color == null) || (color instanceof UIResource)) { 565 editor.setCaretColor(uidefaults.getColor(prefix + ".caretForeground")); 566 } 567 568 Color s = editor.getSelectionColor(); 569 if ((s == null) || (s instanceof UIResource)) { 570 editor.setSelectionColor(uidefaults.getColor(prefix + ".selectionBackground")); 571 } 572 573 Color sfg = editor.getSelectedTextColor(); 574 if ((sfg == null) || (sfg instanceof UIResource)) { 575 editor.setSelectedTextColor(uidefaults.getColor(prefix + ".selectionForeground")); 576 } 577 578 Color dfg = editor.getDisabledTextColor(); 579 if ((dfg == null) || (dfg instanceof UIResource)) { 580 editor.setDisabledTextColor(uidefaults.getColor(prefix + ".inactiveForeground")); 581 } 582 583 Border b = new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight); 584 editor.setBorder(new BorderUIResource.CompoundBorderUIResource( 585 b,new EmptyBorder(2, 2, 2, 2))); 586 587 Insets margin = editor.getMargin(); 588 if (margin == null || margin instanceof UIResource) { 589 editor.setMargin(uidefaults.getInsets(prefix + ".margin")); 590 } 591 } 592 593 @Override 594 protected void installKeyboardActions() { 595 super.installKeyboardActions(); 596 597 JTextComponent comp = getComponent(); 598 599 UIDefaults uidefaults = XToolkit.getUIDefaults(); 600 601 String prefix = getPropertyPrefix(); 602 603 InputMap map = (InputMap)uidefaults.get(prefix + ".focusInputMap"); 604 605 if (map != null) { 606 SwingUtilities.replaceUIInputMap(comp, JComponent.WHEN_FOCUSED, 607 map); 608 } 609 } 610 611 @Override 612 protected Caret createCaret() { 613 return new XAWTCaret(); 614 } 615 } 616 617 @SuppressWarnings("serial") // JDK-implementation class 618 static final class XAWTCaret extends DefaultCaret { 619 @Override 620 public void focusGained(FocusEvent e) { 621 super.focusGained(e); 622 if (getComponent().isEnabled()){ 623 // Make sure the cursor is visible in case of non-editable TextArea 624 super.setVisible(true); 625 } 626 getComponent().repaint(); 627 } 628 629 @Override 630 public void focusLost(FocusEvent e) { 631 super.focusLost(e); 632 getComponent().repaint(); 633 } 634 635 // Fix for 5100950: textarea.getSelectedText() returns the de-selected text, on XToolkit 636 // Restoring Motif behaviour 637 // If the text is unhighlighted then we should sets the selection range to zero 638 @Override 639 public void setSelectionVisible(boolean vis) { 640 if (vis){ 641 super.setSelectionVisible(vis); 642 }else{ 643 // In order to de-select the selection 644 setDot(getDot()); 645 } 646 } 647 } 648 649 @SuppressWarnings("serial") // JDK-implementation class 650 final class XAWTScrollBarButton extends BasicArrowButton { 651 652 private UIDefaults uidefaults = XToolkit.getUIDefaults(); 653 private Color darkShadow = SystemColor.controlShadow; 654 private Color lightShadow = SystemColor.controlLtHighlight; 655 private Color buttonBack = uidefaults.getColor("ScrollBar.track"); 656 657 XAWTScrollBarButton(int direction) { 658 super(direction); 659 660 switch (direction) { 661 case NORTH: 662 case SOUTH: 663 case EAST: 664 case WEST: 665 this.direction = direction; 666 break; 667 default: 668 throw new IllegalArgumentException("invalid direction"); 669 } 670 671 setRequestFocusEnabled(false); 672 setOpaque(true); 673 setBackground(uidefaults.getColor("ScrollBar.thumb")); 674 setForeground(uidefaults.getColor("ScrollBar.foreground")); 675 } 676 677 @Override 678 public Dimension getPreferredSize() { 679 switch (direction) { 680 case NORTH: 681 case SOUTH: 682 return new Dimension(11, 12); 683 case EAST: 684 case WEST: 685 default: 686 return new Dimension(12, 11); 687 } 688 } 689 690 @Override 691 public Dimension getMinimumSize() { 692 return getPreferredSize(); 693 } 694 695 @Override 696 public Dimension getMaximumSize() { 697 return getPreferredSize(); 698 } 699 700 @Override 701 public boolean isFocusTraversable() { 702 return false; 703 } 704 705 @Override 706 public void paint(Graphics g) 707 { 708 int w = getWidth(); 709 int h = getHeight(); 710 711 if (isOpaque()) { 712 g.setColor(buttonBack); 713 g.fillRect(0, 0, w, h); 714 } 715 716 boolean isPressed = getModel().isPressed(); 717 Color lead = (isPressed) ? darkShadow : lightShadow; 718 Color trail = (isPressed) ? lightShadow : darkShadow; 719 Color fill = getBackground(); 720 721 int cx = w / 2; 722 int cy = h / 2; 723 int s = Math.min(w, h); 724 725 switch (direction) { 726 case NORTH: 727 g.setColor(lead); 728 g.drawLine(cx, 0, cx, 0); 729 for (int x = cx - 1, y = 1, dx = 1; y <= s - 2; y += 2) { 730 g.setColor(lead); 731 g.drawLine(x, y, x, y); 732 if (y >= (s - 2)) { 733 g.drawLine(x, y + 1, x, y + 1); 734 } 735 g.setColor(fill); 736 g.drawLine(x + 1, y, x + dx, y); 737 if (y < (s - 2)) { 738 g.drawLine(x, y + 1, x + dx + 1, y + 1); 739 } 740 g.setColor(trail); 741 g.drawLine(x + dx + 1, y, x + dx + 1, y); 742 if (y >= (s - 2)) { 743 g.drawLine(x + 1, y + 1, x + dx + 1, y + 1); 744 } 745 dx += 2; 746 x -= 1; 747 } 748 break; 749 750 case SOUTH: 751 g.setColor(trail); 752 g.drawLine(cx, s, cx, s); 753 for (int x = cx - 1, y = s - 1, dx = 1; y >= 1; y -= 2) { 754 g.setColor(lead); 755 g.drawLine(x, y, x, y); 756 if (y <= 2) { 757 g.drawLine(x, y - 1, x + dx + 1, y - 1); 758 } 759 g.setColor(fill); 760 g.drawLine(x + 1, y, x + dx, y); 761 if (y > 2) { 762 g.drawLine(x, y - 1, x + dx + 1, y - 1); 763 } 764 g.setColor(trail); 765 g.drawLine(x + dx + 1, y, x + dx + 1, y); 766 767 dx += 2; 768 x -= 1; 769 } 770 break; 771 772 case EAST: 773 g.setColor(lead); 774 g.drawLine(s, cy, s, cy); 775 for (int y = cy - 1, x = s - 1, dy = 1; x >= 1; x -= 2) { 776 g.setColor(lead); 777 g.drawLine(x, y, x, y); 778 if (x <= 2) { 779 g.drawLine(x - 1, y, x - 1, y + dy + 1); 780 } 781 g.setColor(fill); 782 g.drawLine(x, y + 1, x, y + dy); 783 if (x > 2) { 784 g.drawLine(x - 1, y, x - 1, y + dy + 1); 785 } 786 g.setColor(trail); 787 g.drawLine(x, y + dy + 1, x, y + dy + 1); 788 789 dy += 2; 790 y -= 1; 791 } 792 break; 793 794 case WEST: 795 g.setColor(trail); 796 g.drawLine(0, cy, 0, cy); 797 for (int y = cy - 1, x = 1, dy = 1; x <= s - 2; x += 2) { 798 g.setColor(lead); 799 g.drawLine(x, y, x, y); 800 if (x >= (s - 2)) { 801 g.drawLine(x + 1, y, x + 1, y); 802 } 803 g.setColor(fill); 804 g.drawLine(x, y + 1, x, y + dy); 805 if (x < (s - 2)) { 806 g.drawLine(x + 1, y, x + 1, y + dy + 1); 807 } 808 g.setColor(trail); 809 g.drawLine(x, y + dy + 1, x, y + dy + 1); 810 if (x >= (s - 2)) { 811 g.drawLine(x + 1, y + 1, x + 1, y + dy + 1); 812 } 813 dy += 2; 814 y -= 1; 815 } 816 break; 817 } 818 } 819 } 820 821 final class XAWTScrollBarUI extends BasicScrollBarUI { 822 823 @Override 824 protected void installDefaults() 825 { 826 super.installDefaults(); 827 scrollbar.setBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 828 } 829 830 @Override 831 protected void configureScrollBarColors() { 832 UIDefaults uidefaults = XToolkit.getUIDefaults(); 833 Color bg = scrollbar.getBackground(); 834 if (bg == null || bg instanceof UIResource) { 835 scrollbar.setBackground(uidefaults.getColor("ScrollBar.background")); 836 } 837 838 Color fg = scrollbar.getForeground(); 839 if (fg == null || fg instanceof UIResource) { 840 scrollbar.setForeground(uidefaults.getColor("ScrollBar.foreground")); 841 } 842 843 thumbHighlightColor = uidefaults.getColor("ScrollBar.thumbHighlight"); 844 thumbLightShadowColor = uidefaults.getColor("ScrollBar.thumbShadow"); 845 thumbDarkShadowColor = uidefaults.getColor("ScrollBar.thumbDarkShadow"); 846 thumbColor = uidefaults.getColor("ScrollBar.thumb"); 847 trackColor = uidefaults.getColor("ScrollBar.track"); 848 849 trackHighlightColor = uidefaults.getColor("ScrollBar.trackHighlight"); 850 851 } 852 853 @Override 854 protected JButton createDecreaseButton(int orientation) { 855 JButton b = new XAWTScrollBarButton(orientation); 856 return b; 857 858 } 859 860 @Override 861 protected JButton createIncreaseButton(int orientation) { 862 JButton b = new XAWTScrollBarButton(orientation); 863 return b; 864 } 865 866 public JButton getDecreaseButton(){ 867 return decrButton; 868 } 869 870 public JButton getIncreaseButton(){ 871 return incrButton; 872 } 873 874 @Override 875 public void paint(Graphics g, JComponent c) { 876 paintTrack(g, c, getTrackBounds()); 877 Rectangle thumbBounds = getThumbBounds(); 878 paintThumb(g, c, thumbBounds); 879 } 880 881 @Override 882 public void paintThumb(Graphics g, JComponent c, Rectangle thumbBounds) 883 { 884 if(!scrollbar.isEnabled()) { 885 return; 886 } 887 888 if (thumbBounds.isEmpty()) 889 thumbBounds = getTrackBounds(); 890 891 int w = thumbBounds.width; 892 int h = thumbBounds.height; 893 894 g.translate(thumbBounds.x, thumbBounds.y); 895 g.setColor(thumbColor); 896 g.fillRect(0, 0, w-1, h-1); 897 898 g.setColor(thumbHighlightColor); 899 g.drawLine(0, 0, 0, h-1); 900 g.drawLine(1, 0, w-1, 0); 901 902 g.setColor(thumbLightShadowColor); 903 g.drawLine(1, h-1, w-1, h-1); 904 g.drawLine(w-1, 1, w-1, h-2); 905 906 g.translate(-thumbBounds.x, -thumbBounds.y); 907 } 908 } 909 910 @SuppressWarnings("serial") // JDK-implementation class 911 final class AWTTextArea extends JTextArea implements DocumentListener { 912 913 private boolean isFocused = false; 914 private final XTextAreaPeer peer; 915 916 AWTTextArea(String text, XTextAreaPeer peer) { 917 super(text); 918 setFocusable(false); 919 this.peer = peer; 920 } 921 922 @Override 923 public void insertUpdate(DocumentEvent e) { 924 if (peer != null) { 925 peer.postEvent(new TextEvent(peer.target, 926 TextEvent.TEXT_VALUE_CHANGED)); 927 } 928 } 929 930 @Override 931 public void removeUpdate(DocumentEvent e) { 932 if (peer != null) { 933 peer.postEvent(new TextEvent(peer.target, 934 TextEvent.TEXT_VALUE_CHANGED)); 935 } 936 } 937 938 @Override 939 public void changedUpdate(DocumentEvent e) { 940 if (peer != null) { 941 peer.postEvent(new TextEvent(peer.target, 942 TextEvent.TEXT_VALUE_CHANGED)); 943 } 944 } 945 946 void forwardFocusGained( FocusEvent e) { 947 isFocused = true; 948 FocusEvent fe = CausedFocusEvent.retarget(e, this); 949 super.processFocusEvent(fe); 950 } 951 952 953 void forwardFocusLost( FocusEvent e) { 954 isFocused = false; 955 FocusEvent fe = CausedFocusEvent.retarget(e, this); 956 super.processFocusEvent(fe); 957 } 958 959 @Override 960 public boolean hasFocus() { 961 return isFocused; 962 } 963 964 public void repaintNow() { 965 paintImmediately(getBounds()); 966 } 967 968 public void processMouseEventPublic(MouseEvent e) { 969 processMouseEvent(e); 970 } 971 972 public void processMouseMotionEventPublic(MouseEvent e) { 973 processMouseMotionEvent(e); 974 } 975 976 public void processInputMethodEventPublic(InputMethodEvent e) { 977 processInputMethodEvent(e); 978 } 979 980 @Override 981 public void updateUI() { 982 ComponentUI ui = new AWTTextAreaUI(); 983 setUI(ui); 984 } 985 986 // Fix for 4915454 - override the default implementation to avoid 987 // loading SystemFlavorMap and associated classes. 988 @Override 989 public void setTransferHandler(TransferHandler newHandler) { 990 TransferHandler oldHandler = (TransferHandler) 991 getClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 992 .getJComponent_TRANSFER_HANDLER()); 993 putClientProperty(AWTAccessor.getClientPropertyKeyAccessor() 994 .getJComponent_TRANSFER_HANDLER(), 995 newHandler); 996 997 firePropertyChange("transferHandler", oldHandler, newHandler); 998 } 999 } 1000 1001 final class XAWTScrollPaneUI extends BasicScrollPaneUI { 1002 1003 private final Border vsbMarginBorderR = new EmptyBorder(0, 2, 0, 0); 1004 private final Border vsbMarginBorderL = new EmptyBorder(0, 0, 0, 2); 1005 private final Border hsbMarginBorder = new EmptyBorder(2, 0, 0, 0); 1006 1007 private Border vsbBorder; 1008 private Border hsbBorder; 1009 1010 private PropertyChangeListener propertyChangeHandler; 1011 1012 @Override 1013 protected void installListeners(JScrollPane scrollPane) { 1014 super.installListeners(scrollPane); 1015 propertyChangeHandler = createPropertyChangeHandler(); 1016 scrollPane.addPropertyChangeListener(propertyChangeHandler); 1017 } 1018 1019 @Override 1020 public void paint(Graphics g, JComponent c) { 1021 Border vpBorder = scrollpane.getViewportBorder(); 1022 if (vpBorder != null) { 1023 Rectangle r = scrollpane.getViewportBorderBounds(); 1024 vpBorder.paintBorder(scrollpane, g, r.x, r.y, r.width, r.height); 1025 } 1026 } 1027 1028 @Override 1029 protected void uninstallListeners(JComponent scrollPane) { 1030 super.uninstallListeners(scrollPane); 1031 scrollPane.removePropertyChangeListener(propertyChangeHandler); 1032 } 1033 1034 private PropertyChangeListener createPropertyChangeHandler() { 1035 return new PropertyChangeListener() { 1036 @Override 1037 public void propertyChange(PropertyChangeEvent e) { 1038 String propertyName = e.getPropertyName(); 1039 1040 if (propertyName.equals("componentOrientation")) { 1041 JScrollPane pane = (JScrollPane)e.getSource(); 1042 JScrollBar vsb = pane.getVerticalScrollBar(); 1043 if (vsb != null) { 1044 if (isLeftToRight(pane)) { 1045 vsbBorder = new CompoundBorder(new EmptyBorder(0, 4, 0, -4), 1046 vsb.getBorder()); 1047 } else { 1048 vsbBorder = new CompoundBorder(new EmptyBorder(0, -4, 0, 4), 1049 vsb.getBorder()); 1050 } 1051 vsb.setBorder(vsbBorder); 1052 } 1053 } 1054 }}; 1055 } 1056 1057 boolean isLeftToRight( Component c ) { 1058 return c.getComponentOrientation().isLeftToRight(); 1059 } 1060 1061 @Override 1062 protected void installDefaults(JScrollPane scrollpane) { 1063 Border b = scrollpane.getBorder(); 1064 UIDefaults uidefaults = XToolkit.getUIDefaults(); 1065 scrollpane.setBorder(uidefaults.getBorder("ScrollPane.border")); 1066 scrollpane.setBackground(uidefaults.getColor("ScrollPane.background")); 1067 scrollpane.setViewportBorder(uidefaults.getBorder("TextField.border")); 1068 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1069 if (vsb != null) { 1070 if (isLeftToRight(scrollpane)) { 1071 vsbBorder = new CompoundBorder(vsbMarginBorderR, 1072 vsb.getBorder()); 1073 } 1074 else { 1075 vsbBorder = new CompoundBorder(vsbMarginBorderL, 1076 vsb.getBorder()); 1077 } 1078 vsb.setBorder(vsbBorder); 1079 } 1080 1081 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1082 if (hsb != null) { 1083 hsbBorder = new CompoundBorder(hsbMarginBorder, hsb.getBorder()); 1084 hsb.setBorder(hsbBorder); 1085 } 1086 } 1087 1088 @Override 1089 protected void uninstallDefaults(JScrollPane c) { 1090 super.uninstallDefaults(c); 1091 1092 JScrollBar vsb = scrollpane.getVerticalScrollBar(); 1093 if (vsb != null) { 1094 if (vsb.getBorder() == vsbBorder) { 1095 vsb.setBorder(null); 1096 } 1097 vsbBorder = null; 1098 } 1099 1100 JScrollBar hsb = scrollpane.getHorizontalScrollBar(); 1101 if (hsb != null) { 1102 if (hsb.getBorder() == hsbBorder) { 1103 hsb.setBorder(null); 1104 } 1105 hsbBorder = null; 1106 } 1107 } 1108 } 1109 1110 @SuppressWarnings("serial") // JDK-implementation class 1111 private class AWTTextPane extends JScrollPane implements FocusListener { 1112 1113 private final JTextArea jtext; 1114 private final XWindow xwin; 1115 1116 private final Color control = SystemColor.control; 1117 private final Color focus = SystemColor.activeCaptionBorder; 1118 1119 AWTTextPane(JTextArea jt, XWindow xwin, Container parent) { 1120 super(jt); 1121 this.xwin = xwin; 1122 setDoubleBuffered(true); 1123 jt.addFocusListener(this); 1124 AWTAccessor.getComponentAccessor().setParent(this,parent); 1125 setViewportBorder(new BevelBorder(false,SystemColor.controlDkShadow,SystemColor.controlLtHighlight) ); 1126 this.jtext = jt; 1127 setFocusable(false); 1128 addNotify(); 1129 } 1130 1131 @Override 1132 public void invalidate() { 1133 synchronized (getTreeLock()) { 1134 final Container parent = getParent(); 1135 AWTAccessor.getComponentAccessor().setParent(this, null); 1136 try { 1137 super.invalidate(); 1138 } finally { 1139 AWTAccessor.getComponentAccessor().setParent(this, parent); 1140 } 1141 } 1142 } 1143 1144 @Override 1145 public void focusGained(FocusEvent e) { 1146 Graphics g = getGraphics(); 1147 Rectangle r = getViewportBorderBounds(); 1148 g.setColor(focus); 1149 g.drawRect(r.x,r.y,r.width,r.height); 1150 g.dispose(); 1151 } 1152 1153 @Override 1154 public void focusLost(FocusEvent e) { 1155 Graphics g = getGraphics(); 1156 Rectangle r = getViewportBorderBounds(); 1157 g.setColor(control); 1158 g.drawRect(r.x,r.y,r.width,r.height); 1159 g.dispose(); 1160 } 1161 1162 public Window getRealParent() { 1163 return (Window) xwin.target; 1164 } 1165 1166 @Override 1167 public void updateUI() { 1168 ComponentUI ui = new XAWTScrollPaneUI(); 1169 setUI(ui); 1170 } 1171 1172 @Override 1173 public JScrollBar createVerticalScrollBar() { 1174 return new XAWTScrollBar(JScrollBar.VERTICAL); 1175 } 1176 1177 @Override 1178 public JScrollBar createHorizontalScrollBar() { 1179 return new XAWTScrollBar(JScrollBar.HORIZONTAL); 1180 } 1181 1182 public JTextArea getTextArea () { 1183 return this.jtext; 1184 } 1185 1186 @Override 1187 public Graphics getGraphics() { 1188 return xwin.getGraphics(); 1189 } 1190 1191 @SuppressWarnings("serial") // JDK-implementation class 1192 final class XAWTScrollBar extends ScrollBar { 1193 1194 XAWTScrollBar(int i) { 1195 super(i); 1196 setFocusable(false); 1197 } 1198 1199 @Override 1200 public void updateUI() { 1201 ComponentUI ui = new XAWTScrollBarUI(); 1202 setUI(ui); 1203 } 1204 } 1205 } 1206 1207 @SuppressWarnings("serial") // JDK-implementation class 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 BevelBorder(boolean isRaised, Color darkShadow, Color lightShadow) { 1215 this.isRaised = isRaised; 1216 this.darkShadow = darkShadow; 1217 this.lightShadow = lightShadow; 1218 } 1219 1220 @Override 1221 public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) { 1222 g.setColor((isRaised) ? lightShadow : darkShadow); 1223 g.drawLine(x, y, x+w-1, y); // top 1224 g.drawLine(x, y+h-1, x, y+1); // left 1225 1226 g.setColor(control); 1227 g.drawLine(x+1, y+1, x+w-2, y+1); // top 1228 g.drawLine(x+1, y+h-1, x+1, y+1); // left 1229 1230 g.setColor((isRaised) ? darkShadow : lightShadow); 1231 g.drawLine(x+1, y+h-1, x+w-1, y+h-1); // bottom 1232 g.drawLine(x+w-1, y+h-1, x+w-1, y+1); // right 1233 1234 g.setColor(control); 1235 g.drawLine(x+1, y+h-2, x+w-2, y+h-2); // bottom 1236 g.drawLine(x+w-2, y+h-2, x+w-2, y+1); // right 1237 } 1238 1239 @Override 1240 public Insets getBorderInsets(Component c) { 1241 return getBorderInsets(c, new Insets(0,0,0,0)); 1242 } 1243 1244 @Override 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 }