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.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 /** 48 * Lightweight implementation of {@link TextComponentPeer}. Provides useful 49 * methods for {@link LWTextAreaPeer} and {@link LWTextFieldPeer} 50 */ 51 abstract class LWTextComponentPeer<T extends TextComponent, D extends JComponent> 52 extends LWComponentPeer<T, D> 53 implements DocumentListener, TextComponentPeer, InputMethodListener { 54 55 private volatile boolean firstChangeSkipped; 56 LWTextComponentPeer(final T target, final PlatformComponent platformComponent)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 initializeImpl()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 setCaretPosition(getTarget().getCaretPosition()); 75 getTarget().addInputMethodListener(this); 76 final int start = getTarget().getSelectionStart(); 77 final int end = getTarget().getSelectionEnd(); 78 if (end > start) { 79 // Should be called after setText() and setCaretPosition() 80 select(start, end); 81 } 82 firstChangeSkipped = true; 83 } 84 85 @Override disposeImpl()86 protected final void disposeImpl() { 87 synchronized (getDelegateLock()) { 88 // visible caret has a timer thread which must be stopped 89 getTextComponent().getCaret().setVisible(false); 90 } 91 super.disposeImpl(); 92 } 93 94 /** 95 * This method should be called under getDelegateLock(). 96 */ getTextComponent()97 abstract JTextComponent getTextComponent(); 98 getMinimumSize(final int rows, final int columns)99 public Dimension getMinimumSize(final int rows, final int columns) { 100 final Insets insets; 101 synchronized (getDelegateLock()) { 102 insets = getTextComponent().getInsets(); 103 } 104 final int borderHeight = insets.top + insets.bottom; 105 final int borderWidth = insets.left + insets.right; 106 final FontMetrics fm = getFontMetrics(getFont()); 107 return new Dimension(fm.charWidth(WIDE_CHAR) * columns + borderWidth, 108 fm.getHeight() * rows + borderHeight); 109 } 110 111 @Override setEditable(final boolean editable)112 public final void setEditable(final boolean editable) { 113 synchronized (getDelegateLock()) { 114 getTextComponent().setEditable(editable); 115 } 116 } 117 118 @Override getText()119 public final String getText() { 120 synchronized (getDelegateLock()) { 121 return getTextComponent().getText(); 122 } 123 } 124 125 @Override setText(final String text)126 public final void setText(final String text) { 127 synchronized (getDelegateLock()) { 128 // JTextArea.setText() posts two different events (remove & insert). 129 // Since we make no differences between text events, 130 // the document listener has to be disabled while 131 // JTextArea.setText() is called. 132 final Document document = getTextComponent().getDocument(); 133 document.removeDocumentListener(this); 134 getTextComponent().setText(text); 135 revalidate(); 136 if (firstChangeSkipped) { 137 postEvent(new TextEvent(getTarget(), 138 TextEvent.TEXT_VALUE_CHANGED)); 139 } 140 document.addDocumentListener(this); 141 } 142 repaintPeer(); 143 } 144 145 @Override getSelectionStart()146 public final int getSelectionStart() { 147 synchronized (getDelegateLock()) { 148 return getTextComponent().getSelectionStart(); 149 } 150 } 151 152 @Override getSelectionEnd()153 public final int getSelectionEnd() { 154 synchronized (getDelegateLock()) { 155 return getTextComponent().getSelectionEnd(); 156 } 157 } 158 159 @Override select(final int selStart, final int selEnd)160 public final void select(final int selStart, final int selEnd) { 161 synchronized (getDelegateLock()) { 162 getTextComponent().select(selStart, selEnd); 163 } 164 repaintPeer(); 165 } 166 167 @Override setCaretPosition(final int pos)168 public final void setCaretPosition(final int pos) { 169 synchronized (getDelegateLock()) { 170 getTextComponent().setCaretPosition(pos); 171 } 172 repaintPeer(); 173 } 174 175 @Override getCaretPosition()176 public final int getCaretPosition() { 177 synchronized (getDelegateLock()) { 178 return getTextComponent().getCaretPosition(); 179 } 180 } 181 182 @Override getInputMethodRequests()183 public final InputMethodRequests getInputMethodRequests() { 184 synchronized (getDelegateLock()) { 185 return getTextComponent().getInputMethodRequests(); 186 } 187 } 188 189 //TODO IN XAWT we just return true.. 190 @Override isFocusable()191 public final boolean isFocusable() { 192 return getTarget().isFocusable(); 193 } 194 revalidate()195 protected final void revalidate() { 196 synchronized (getDelegateLock()) { 197 getTextComponent().invalidate(); 198 getDelegate().validate(); 199 } 200 } 201 postTextEvent()202 protected final void postTextEvent() { 203 postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED)); 204 synchronized (getDelegateLock()) { 205 revalidate(); 206 } 207 } 208 209 @Override changedUpdate(final DocumentEvent e)210 public final void changedUpdate(final DocumentEvent e) { 211 postTextEvent(); 212 } 213 214 @Override insertUpdate(final DocumentEvent e)215 public final void insertUpdate(final DocumentEvent e) { 216 postTextEvent(); 217 } 218 219 @Override removeUpdate(final DocumentEvent e)220 public final void removeUpdate(final DocumentEvent e) { 221 postTextEvent(); 222 } 223 224 @Override inputMethodTextChanged(final InputMethodEvent event)225 public void inputMethodTextChanged(final InputMethodEvent event) { 226 synchronized (getDelegateLock()) { 227 AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event); 228 } 229 } 230 231 @Override caretPositionChanged(final InputMethodEvent event)232 public void caretPositionChanged(final InputMethodEvent event) { 233 synchronized (getDelegateLock()) { 234 AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event); 235 } 236 } 237 } 238