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