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