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