1/* 2 * Copyright (c) 2011, 2015, 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 26package sun.lwawt; 27 28import java.awt.Component; 29import java.awt.Cursor; 30import java.awt.Dimension; 31import java.awt.Insets; 32import java.awt.Point; 33import java.awt.TextArea; 34import java.awt.event.TextEvent; 35import java.awt.peer.TextAreaPeer; 36 37import javax.swing.JScrollBar; 38import javax.swing.JScrollPane; 39import javax.swing.JTextArea; 40import javax.swing.ScrollPaneConstants; 41import javax.swing.text.Document; 42 43/** 44 * Lightweight implementation of {@link TextAreaPeer}. Delegates most of the 45 * work to the {@link JTextArea} inside {@link JScrollPane}. 46 */ 47final class LWTextAreaPeer 48 extends LWTextComponentPeer<TextArea, LWTextAreaPeer.ScrollableJTextArea> 49 implements TextAreaPeer { 50 51 /** 52 * The default number of visible columns. 53 */ 54 private static final int DEFAULT_COLUMNS = 60; 55 56 /** 57 * The default number of visible rows. 58 */ 59 private static final int DEFAULT_ROWS = 10; 60 61 LWTextAreaPeer(final TextArea target, 62 final PlatformComponent platformComponent) { 63 super(target, platformComponent); 64 } 65 66 @Override 67 ScrollableJTextArea createDelegate() { 68 return new ScrollableJTextArea(); 69 } 70 71 @Override 72 void initializeImpl() { 73 super.initializeImpl(); 74 final int visibility = getTarget().getScrollbarVisibility(); 75 synchronized (getDelegateLock()) { 76 getTextComponent().setWrapStyleWord(true); 77 setScrollBarVisibility(visibility); 78 } 79 } 80 81 @Override 82 JTextArea getTextComponent() { 83 return getDelegate().getView(); 84 } 85 86 @Override 87 Cursor getCursor(final Point p) { 88 final boolean isContains; 89 synchronized (getDelegateLock()) { 90 isContains = getDelegate().getViewport().getBounds().contains(p); 91 } 92 return isContains ? super.getCursor(p) : null; 93 } 94 95 @Override 96 Component getDelegateFocusOwner() { 97 return getTextComponent(); 98 } 99 100 @Override 101 public Dimension getPreferredSize() { 102 return getMinimumSize(); 103 } 104 105 @Override 106 public Dimension getMinimumSize() { 107 return getMinimumSize(DEFAULT_ROWS, DEFAULT_COLUMNS); 108 } 109 110 @Override 111 public Dimension getPreferredSize(final int rows, final int columns) { 112 return getMinimumSize(rows, columns); 113 } 114 115 @Override 116 public Dimension getMinimumSize(final int rows, final int columns) { 117 final Dimension size = super.getMinimumSize(rows, columns); 118 synchronized (getDelegateLock()) { 119 // JScrollPane insets 120 final Insets pi = getDelegate().getInsets(); 121 size.width += pi.left + pi.right; 122 size.height += pi.top + pi.bottom; 123 // Take scrollbars into account. 124 final int vsbPolicy = getDelegate().getVerticalScrollBarPolicy(); 125 if (vsbPolicy == ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS) { 126 final JScrollBar vbar = getDelegate().getVerticalScrollBar(); 127 size.width += vbar != null ? vbar.getMinimumSize().width : 0; 128 } 129 final int hsbPolicy = getDelegate().getHorizontalScrollBarPolicy(); 130 if (hsbPolicy == ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS) { 131 final JScrollBar hbar = getDelegate().getHorizontalScrollBar(); 132 size.height += hbar != null ? hbar.getMinimumSize().height : 0; 133 } 134 } 135 return size; 136 } 137 138 @Override 139 public void insert(final String text, final int pos) { 140 final ScrollableJTextArea pane = getDelegate(); 141 synchronized (getDelegateLock()) { 142 final JTextArea area = pane.getView(); 143 final boolean doScroll = pos >= area.getDocument().getLength() 144 && area.getDocument().getLength() != 0; 145 area.insert(text, pos); 146 revalidate(); 147 if (doScroll) { 148 final JScrollBar vbar = pane.getVerticalScrollBar(); 149 if (vbar != null) { 150 vbar.setValue(vbar.getMaximum() - vbar.getVisibleAmount()); 151 } 152 } 153 } 154 repaintPeer(); 155 } 156 157 @Override 158 public void replaceRange(final String text, final int start, 159 final int end) { 160 synchronized (getDelegateLock()) { 161 // JTextArea.replaceRange() posts two different events. 162 // Since we make no differences between text events, 163 // the document listener has to be disabled while 164 // JTextArea.replaceRange() is called. 165 final Document document = getTextComponent().getDocument(); 166 document.removeDocumentListener(this); 167 getTextComponent().replaceRange(text, start, end); 168 revalidate(); 169 postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED)); 170 document.addDocumentListener(this); 171 } 172 repaintPeer(); 173 } 174 175 private void setScrollBarVisibility(final int visibility) { 176 final ScrollableJTextArea pane = getDelegate(); 177 final JTextArea view = pane.getView(); 178 view.setLineWrap(false); 179 180 switch (visibility) { 181 case TextArea.SCROLLBARS_NONE: 182 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 183 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 184 view.setLineWrap(true); 185 break; 186 case TextArea.SCROLLBARS_VERTICAL_ONLY: 187 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER); 188 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 189 view.setLineWrap(true); 190 break; 191 case TextArea.SCROLLBARS_HORIZONTAL_ONLY: 192 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_NEVER); 193 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 194 break; 195 default: 196 pane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_ALWAYS); 197 pane.setVerticalScrollBarPolicy(ScrollPaneConstants.VERTICAL_SCROLLBAR_ALWAYS); 198 break; 199 } 200 } 201 202 @SuppressWarnings("serial")// Safe: outer class is non-serializable. 203 final class ScrollableJTextArea extends JScrollPane { 204 205 ScrollableJTextArea() { 206 super(); 207 getViewport().setView(new JTextAreaDelegate()); 208 } 209 210 public JTextArea getView() { 211 return (JTextArea) getViewport().getView(); 212 } 213 214 @Override 215 public void setEnabled(final boolean enabled) { 216 getViewport().getView().setEnabled(enabled); 217 super.setEnabled(enabled); 218 } 219 220 private final class JTextAreaDelegate extends JTextArea { 221 222 // Empty non private constructor was added because access to this 223 // class shouldn't be emulated by a synthetic accessor method. 224 JTextAreaDelegate() { 225 super(); 226 } 227 228 @Override 229 public void replaceSelection(String content) { 230 getDocument().removeDocumentListener(LWTextAreaPeer.this); 231 super.replaceSelection(content); 232 // post only one text event in this case 233 postTextEvent(); 234 getDocument().addDocumentListener(LWTextAreaPeer.this); 235 } 236 237 @Override 238 public boolean hasFocus() { 239 return getTarget().hasFocus(); 240 } 241 242 @Override 243 public Point getLocationOnScreen() { 244 return LWTextAreaPeer.this.getLocationOnScreen(); 245 } 246 } 247 } 248} 249