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