1 /*
   2  * Copyright (c) 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 
  27 package sun.lwawt;
  28 
  29 import java.awt.Component;
  30 import java.awt.Dimension;
  31 import java.awt.Point;
  32 import java.awt.TextArea;
  33 import java.awt.event.TextEvent;
  34 import java.awt.peer.TextAreaPeer;
  35 
  36 import javax.swing.JScrollBar;
  37 import javax.swing.JScrollPane;
  38 import javax.swing.JTextArea;
  39 import javax.swing.ScrollPaneConstants;
  40 import javax.swing.text.Document;
  41 import javax.swing.text.JTextComponent;
  42 
  43 final class LWTextAreaPeer
  44         extends LWTextComponentPeer<TextArea, LWTextAreaPeer.ScrollableJTextArea>
  45         implements TextAreaPeer {
  46 
  47     private static final int DEFAULT_COLUMNS = 60;
  48     private static final int DEFAULT_ROWS = 10;
  49 
  50     LWTextAreaPeer(final TextArea target,
  51                    final PlatformComponent platformComponent) {
  52         super(target, platformComponent);
  53     }
  54 
  55     @Override
  56     protected ScrollableJTextArea createDelegate() {
  57         return new ScrollableJTextArea();
  58     }
  59 
  60     @Override
  61     public void initialize() {
  62         super.initialize();
  63         final int visibility = getTarget().getScrollbarVisibility();
  64         synchronized (getDelegateLock()) {
  65             setScrollBarVisibility(visibility);
  66         }
  67     }
  68 
  69     @Override
  70     JTextComponent getTextComponent() {
  71         return getDelegate().getView();
  72     }
  73 
  74     @Override
  75     protected Component getDelegateFocusOwner() {
  76         return getTextComponent();
  77     }
  78 
  79     @Override
  80     public Dimension getMinimumSize() {
  81         return getMinimumSize(DEFAULT_ROWS, DEFAULT_COLUMNS);
  82     }
  83 
  84     @Override
  85     public Dimension getMinimumSize(final int rows, final int columns) {
  86         return getPreferredSize(rows, columns);
  87     }
  88 
  89     @Override
  90     public Dimension getPreferredSize(final int rows, final int columns) {
  91         final Dimension size = super.getPreferredSize(rows, columns);
  92         synchronized (getDelegateLock()) {
  93             final JScrollBar vbar = getDelegate().getVerticalScrollBar();
  94             final JScrollBar hbar = getDelegate().getHorizontalScrollBar();
  95             final int scrollbarW = vbar != null ? vbar.getWidth() : 0;
  96             final int scrollbarH = hbar != null ? hbar.getHeight() : 0;
  97             return new Dimension(size.width + scrollbarW,
  98                                  size.height + scrollbarH);
  99         }
 100     }
 101 
 102     @Override
 103     public void insert(final String text, final int pos) {
 104         final ScrollableJTextArea pane = getDelegate();
 105         synchronized (getDelegateLock()) {
 106             final JTextArea area = pane.getView();
 107             final boolean doScroll = pos >= area.getDocument().getLength()
 108                                      && area.getDocument().getLength() != 0;
 109             area.insert(text, pos);
 110             revalidate();
 111             if (doScroll) {
 112                 final JScrollBar vbar = pane.getVerticalScrollBar();
 113                 if (vbar != null) {
 114                     vbar.setValue(vbar.getMaximum() - vbar.getVisibleAmount());
 115                 }
 116             }
 117         }
 118         repaintPeer();
 119     }
 120 
 121     @Override
 122     public void setText(final String l) {
 123         // Please note that we do not want to post an event
 124         // if TextArea.setText() replaces an empty text by an empty text,
 125         // that is, if component's text remains unchanged.
 126         if (!l.isEmpty() || getTextComponent().getDocument().getLength() != 0) {
 127             super.setText(l);
 128         }
 129     }
 130 
 131     @Override
 132     public void replaceRange(final String text, final int start,
 133                              final int end) {
 134         synchronized (getDelegateLock()) {
 135             // JTextArea.replaceRange() posts two different events.
 136             // Since we make no differences between text events,
 137             // the document listener has to be disabled while
 138             // JTextArea.replaceRange() is called.
 139             final Document document = getTextComponent().getDocument();
 140             document.removeDocumentListener(this);
 141             getDelegate().getView().replaceRange(text, start, end);
 142             revalidate();
 143             postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED));
 144             document.addDocumentListener(this);
 145         }
 146         repaintPeer();
 147     }
 148 
 149     private void setScrollBarVisibility(final int visibility) {
 150         final ScrollableJTextArea pane = getDelegate();
 151         final JTextArea view = pane.getView();
 152         view.setLineWrap(false);
 153 
 154         switch (visibility) {
 155             case TextArea.SCROLLBARS_NONE:
 156                 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 157                 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
 158                 view.setLineWrap(true);
 159                 break;
 160             case TextArea.SCROLLBARS_VERTICAL_ONLY:
 161                 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);
 162                 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 163                 view.setLineWrap(true);
 164                 break;
 165             case TextArea.SCROLLBARS_HORIZONTAL_ONLY:
 166                 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER);
 167                 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
 168                 break;
 169             default:
 170                 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS);
 171                 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS);
 172                 break;
 173         }
 174     }
 175 
 176     @SuppressWarnings("serial")
 177     final class ScrollableJTextArea extends JScrollPane {
 178 
 179         ScrollableJTextArea() {
 180             super();
 181             getViewport().setView(new JTextAreaDelegate());
 182         }
 183 
 184         public JTextArea getView() {
 185             return (JTextArea) getViewport().getView();
 186         }
 187 
 188         @Override
 189         public void setEnabled(final boolean enabled) {
 190             getViewport().getView().setEnabled(enabled);
 191             super.setEnabled(enabled);
 192         }
 193 
 194         @SuppressWarnings("serial")
 195         private final class JTextAreaDelegate extends JTextArea {
 196 
 197             // Empty non private constructor was added because access to this
 198             // class shouldn't be emulated by a synthetic accessor method.
 199             JTextAreaDelegate() {
 200                 super();
 201             }
 202 
 203             @Override
 204             public boolean hasFocus() {
 205                 return getTarget().hasFocus();
 206             }
 207 
 208             @Override
 209             public Point getLocationOnScreen() {
 210                 return LWTextAreaPeer.this.getLocationOnScreen();
 211             }
 212         }
 213     }
 214 }