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