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.Dimension; 30 import java.awt.FontMetrics; 31 import java.awt.Insets; 32 import java.awt.SystemColor; 33 import java.awt.TextComponent; 34 import java.awt.event.TextEvent; 35 import java.awt.event.InputMethodListener; 36 import java.awt.event.InputMethodEvent; 37 import java.awt.im.InputMethodRequests; 38 import java.awt.peer.TextComponentPeer; 39 import sun.awt.AWTAccessor; 40 41 import javax.swing.JComponent; 42 import javax.swing.event.DocumentEvent; 43 import javax.swing.event.DocumentListener; 44 import javax.swing.text.Document; 45 import javax.swing.text.JTextComponent; 46 47 abstract class LWTextComponentPeer<T extends TextComponent, D extends JComponent> 48 extends LWComponentPeer<T, D> 49 implements DocumentListener, TextComponentPeer, InputMethodListener { 50 51 /** 52 * Character with reasonable value between the minimum width and maximum. 53 */ 54 protected static final char WIDE_CHAR = 'w'; 55 private volatile boolean firstChangeSkipped; 56 57 LWTextComponentPeer(final T target, 58 final PlatformComponent platformComponent) { 59 super(target, platformComponent); 60 if (!getTarget().isBackgroundSet()) { 61 getTarget().setBackground(SystemColor.text); 62 } 63 } 64 65 @Override 66 void initializeImpl() { 67 super.initializeImpl(); 68 synchronized (getDelegateLock()) { 69 // This listener should be added before setText(). 70 getTextComponent().getDocument().addDocumentListener(this); 71 } 72 setEditable(getTarget().isEditable()); 73 setText(getTarget().getText()); 74 getTarget().addInputMethodListener(this); 75 final int start = getTarget().getSelectionStart(); 76 final int end = getTarget().getSelectionEnd(); 77 if (end > start) { 78 select(start, end); 79 } 80 setCaretPosition(getTarget().getCaretPosition()); 81 firstChangeSkipped = true; 82 } 83 84 @Override 85 protected final void disposeImpl() { 86 synchronized (getDelegateLock()) { 87 // visible caret has a timer thread which must be stopped 88 getTextComponent().getCaret().setVisible(false); 89 } 90 super.disposeImpl(); 91 } 92 93 /** 94 * This method should be called under getDelegateLock(). 95 */ 96 abstract JTextComponent getTextComponent(); 97 98 public Dimension getPreferredSize(final int rows, final int columns) { 99 final Insets insets; 100 synchronized (getDelegateLock()) { 101 insets = getDelegate().getInsets(); 102 } 103 final int borderHeight = insets.top + insets.bottom; 104 final int borderWidth = insets.left + insets.right; 105 final FontMetrics fm = getFontMetrics(getFont()); 106 final int charWidth = (fm != null) ? fm.charWidth(WIDE_CHAR) : 10; 107 final int itemHeight = (fm != null) ? fm.getHeight() : 10; 108 return new Dimension(columns * charWidth + borderWidth, 109 rows * itemHeight + borderHeight); 110 } 111 112 @Override 113 public final void setEditable(final boolean editable) { 114 synchronized (getDelegateLock()) { 115 getTextComponent().setEditable(editable); 116 } 117 } 118 119 @Override 120 public final String getText() { 121 synchronized (getDelegateLock()) { 122 return getTextComponent().getText(); 123 } 124 } 125 126 @Override 127 public void setText(final String l) { 128 synchronized (getDelegateLock()) { 129 // JTextArea.setText() posts two different events (remove & insert). 130 // Since we make no differences between text events, 131 // the document listener has to be disabled while 132 // JTextArea.setText() is called. 133 final Document document = getTextComponent().getDocument(); 134 document.removeDocumentListener(this); 135 getTextComponent().setText(l); 136 revalidate(); 137 if (firstChangeSkipped) { 138 postEvent(new TextEvent(getTarget(), 139 TextEvent.TEXT_VALUE_CHANGED)); 140 } 141 document.addDocumentListener(this); 142 } 143 repaintPeer(); 144 } 145 146 @Override 147 public final int getSelectionStart() { 148 synchronized (getDelegateLock()) { 149 return getTextComponent().getSelectionStart(); 150 } 151 } 152 153 @Override 154 public final int getSelectionEnd() { 155 synchronized (getDelegateLock()) { 156 return getTextComponent().getSelectionEnd(); 157 } 158 } 159 160 @Override 161 public final void select(final int selStart, final int selEnd) { 162 synchronized (getDelegateLock()) { 163 getTextComponent().select(selStart, selEnd); 164 } 165 repaintPeer(); 166 } 167 168 @Override 169 public final void setCaretPosition(final int pos) { 170 synchronized (getDelegateLock()) { 171 getTextComponent().setCaretPosition(pos); 172 } 173 repaintPeer(); 174 } 175 176 @Override 177 public final int getCaretPosition() { 178 synchronized (getDelegateLock()) { 179 return getTextComponent().getCaretPosition(); 180 } 181 } 182 183 @Override 184 public final InputMethodRequests getInputMethodRequests() { 185 synchronized (getDelegateLock()) { 186 return getTextComponent().getInputMethodRequests(); 187 } 188 } 189 190 @Override 191 public final boolean isFocusable() { 192 return getTarget().isFocusable(); 193 } 194 195 protected final void revalidate() { 196 synchronized (getDelegateLock()) { 197 getTextComponent().invalidate(); 198 getDelegate().validate(); 199 } 200 } 201 202 protected final void postTextEvent() { 203 postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED)); 204 synchronized (getDelegateLock()) { 205 revalidate(); 206 } 207 } 208 209 @Override 210 public final void changedUpdate(final DocumentEvent e) { 211 postTextEvent(); 212 } 213 214 @Override 215 public final void insertUpdate(final DocumentEvent e) { 216 postTextEvent(); 217 } 218 219 @Override 220 public final void removeUpdate(final DocumentEvent e) { 221 postTextEvent(); 222 } 223 224 @Override 225 public void inputMethodTextChanged(InputMethodEvent event) { 226 synchronized (getDelegateLock()) { 227 AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event); 228 } 229 } 230 231 @Override 232 public void caretPositionChanged(InputMethodEvent event) { 233 synchronized (getDelegateLock()) { 234 AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event); 235 } 236 } 237 }