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