/*
* Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package sun.lwawt;
import java.awt.Dimension;
import java.awt.FontMetrics;
import java.awt.Insets;
import java.awt.SystemColor;
import java.awt.TextComponent;
import java.awt.event.TextEvent;
import java.awt.event.InputMethodListener;
import java.awt.event.InputMethodEvent;
import java.awt.im.InputMethodRequests;
import java.awt.peer.TextComponentPeer;
import sun.awt.AWTAccessor;
import javax.swing.JComponent;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.text.Document;
import javax.swing.text.JTextComponent;
abstract class LWTextComponentPeer<T extends TextComponent, D extends JComponent>
extends LWComponentPeer<T, D>
implements DocumentListener, TextComponentPeer, InputMethodListener {
/**
* Character with reasonable value between the minimum width and maximum.
*/
protected static final char WIDE_CHAR = 'w';
private volatile boolean firstChangeSkipped;
LWTextComponentPeer(final T target,
final PlatformComponent platformComponent) {
super(target, platformComponent);
if (!getTarget().isBackgroundSet()) {
getTarget().setBackground(SystemColor.text);
}
}
@Override
void initializeImpl() {
super.initializeImpl();
synchronized (getDelegateLock()) {
// This listener should be added before setText().
getTextComponent().getDocument().addDocumentListener(this);
}
setEditable(getTarget().isEditable());
setText(getTarget().getText());
getTarget().addInputMethodListener(this);
final int start = getTarget().getSelectionStart();
final int end = getTarget().getSelectionEnd();
if (end > start) {
select(start, end);
}
setCaretPosition(getTarget().getCaretPosition());
firstChangeSkipped = true;
}
@Override
protected final void disposeImpl() {
synchronized (getDelegateLock()) {
// visible caret has a timer thread which must be stopped
getTextComponent().getCaret().setVisible(false);
}
super.disposeImpl();
}
/**
* This method should be called under getDelegateLock().
*/
abstract JTextComponent getTextComponent();
public Dimension getPreferredSize(final int rows, final int columns) {
final Insets insets;
synchronized (getDelegateLock()) {
insets = getDelegate().getInsets();
}
final int borderHeight = insets.top + insets.bottom;
final int borderWidth = insets.left + insets.right;
final FontMetrics fm = getFontMetrics(getFont());
final int charWidth = (fm != null) ? fm.charWidth(WIDE_CHAR) : 10;
final int itemHeight = (fm != null) ? fm.getHeight() : 10;
return new Dimension(columns * charWidth + borderWidth,
rows * itemHeight + borderHeight);
}
@Override
public final void setEditable(final boolean editable) {
synchronized (getDelegateLock()) {
getTextComponent().setEditable(editable);
}
}
@Override
public final String getText() {
synchronized (getDelegateLock()) {
return getTextComponent().getText();
}
}
@Override
public final void setText(final String l) {
synchronized (getDelegateLock()) {
// JTextArea.setText() posts two different events (remove & insert).
// Since we make no differences between text events,
// the document listener has to be disabled while
// JTextArea.setText() is called.
final Document document = getTextComponent().getDocument();
document.removeDocumentListener(this);
getTextComponent().setText(l);
revalidate();
if (firstChangeSkipped) {
postEvent(new TextEvent(getTarget(),
TextEvent.TEXT_VALUE_CHANGED));
}
document.addDocumentListener(this);
}
repaintPeer();
}
@Override
public final int getSelectionStart() {
synchronized (getDelegateLock()) {
return getTextComponent().getSelectionStart();
}
}
@Override
public final int getSelectionEnd() {
synchronized (getDelegateLock()) {
return getTextComponent().getSelectionEnd();
}
}
@Override
public final void select(final int selStart, final int selEnd) {
synchronized (getDelegateLock()) {
getTextComponent().select(selStart, selEnd);
}
repaintPeer();
}
@Override
public final void setCaretPosition(final int pos) {
synchronized (getDelegateLock()) {
getTextComponent().setCaretPosition(pos);
}
repaintPeer();
}
@Override
public final int getCaretPosition() {
synchronized (getDelegateLock()) {
return getTextComponent().getCaretPosition();
}
}
@Override
public final InputMethodRequests getInputMethodRequests() {
synchronized (getDelegateLock()) {
return getTextComponent().getInputMethodRequests();
}
}
@Override
public final boolean isFocusable() {
return getTarget().isFocusable();
}
protected final void revalidate() {
synchronized (getDelegateLock()) {
getTextComponent().invalidate();
getDelegate().validate();
}
}
protected final void postTextEvent() {
postEvent(new TextEvent(getTarget(), TextEvent.TEXT_VALUE_CHANGED));
synchronized (getDelegateLock()) {
revalidate();
}
}
@Override
public final void changedUpdate(final DocumentEvent e) {
postTextEvent();
}
@Override
public final void insertUpdate(final DocumentEvent e) {
postTextEvent();
}
@Override
public final void removeUpdate(final DocumentEvent e) {
postTextEvent();
}
@Override
public void inputMethodTextChanged(InputMethodEvent event) {
synchronized (getDelegateLock()) {
AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event);
}
}
@Override
public void caretPositionChanged(InputMethodEvent event) {
synchronized (getDelegateLock()) {
AWTAccessor.getComponentAccessor().processEvent(getTextComponent(), event);
}
}
}