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