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