/* class JTextField
*
* Copyright (C) 2001 R M Pitman
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package charvax.swing;
import java.util.Enumeration;
import java.util.Vector;
import charva.awt.Dimension;
import charva.awt.Font;
import charva.awt.Insets;
import charva.awt.Point;
import charva.awt.Toolkit;
import charva.awt.event.AWTEvent;
import charva.awt.event.ActionEvent;
import charva.awt.event.ActionListener;
import charva.awt.event.KeyEvent;
import charva.awt.event.MouseEvent;
import charvax.swing.text.JTextComponent;
/**
* JTextField is a component that allows the display and editing of a
* single line of text.
* The JTextField class, being a subclass of JComponent, has a setBorder()
* method which allows an optional Border to be set.
*/
public class JTextField
extends JTextComponent
{
/** Construct a text field. The initial string is empty and the
* number of columns is 10.
*/
public JTextField()
{
this("", 10);
}
/** Use this constructor when you want to initialize the value.
*/
public JTextField(String text_) {
this(text_, text_.length());
}
/**
* Use this constructor when you want to leave the text field empty
* but set its length.
*/
public JTextField(int length_) {
this("", length_);
}
/**
* Use this constructor when you want to set both the initial value and the
* length.
*/
public JTextField(String text_, int length_) {
super.setText(text_);
setColumns(length_);
super._caretPosition = super._document.length();
if (super._document.length() > _columns)
_offset = super._document.length() - _columns;
else
_offset = 0;
}
/** Sets the number of columns in this Textfield, and then invalidates
* the layout.
*/
public void setColumns(int columns_) {
_columns = columns_;
StringBuffer padbuf = new StringBuffer();
for (int i=0; i<_columns; i++)
padbuf.append(' ');
_padding = new String(padbuf);
super.invalidate();
}
/** Return the number of columns in the text field.
*/
public int getColumns() { return _columns; }
public void setFont(Font font_)
{
_bold = ((font_.getStyle() & Font.BOLD) != 0);
}
/** Set the action command
*/
public void setActionCommand(String cmd_) { _actionCommand = cmd_; }
/** Get the action command
*/
public String getActionCommand() { return _actionCommand; }
/**
* Return the size of the text field. Overrides the method in the
* Component superclass.
*/
public Dimension getSize() {
Insets insets = super.getInsets();
return new Dimension(_columns + insets.left + insets.right,
1 + insets.top + insets.bottom);
}
public int getWidth() {
Insets insets = super.getInsets();
return _columns + insets.left + insets.right;
}
public int getHeight() {
Insets insets = super.getInsets();
return 1 + insets.top + insets.bottom;
}
/** Called by the LayoutManager.
*/
public Dimension minimumSize() {
return getSize();
}
/** Sets whether this textfield can be edited.
*/
public void setEditable(boolean editable_)
{
super.setEnabled(editable_);
}
public boolean isEditable() { return isEnabled(); }
/**
* Called by this JTextField's parent container.
* @param toolkit
*/
public void draw(Toolkit toolkit) {
/* Draw the border inherited from JComponent, if it exists.
*/
super.draw(toolkit);
/* If the field is enabled, it is drawn with the UNDERLINE
* attribute. If it is disabled, it is drawn without the
* UNDERLINE attribute.
*/
int attrib = 0;
if (super._enabled)
attrib |= Toolkit.A_UNDERLINE;
if (_bold)
attrib |= Toolkit.A_BOLD;
/* Get the absolute origin of this component.
*/
Point origin = getLocationOnScreen();
Insets insets = super.getInsets();
origin.translate(insets.left, insets.top);
int colorpair = getCursesColor();
toolkit.setCursor(origin);
toolkit.addString(_padding, attrib, colorpair);
toolkit.setCursor(origin);
// Get the displayable portion of the string
int end;
if (super.getText().length() > (_offset + _columns))
end = _offset + _columns;
else
end = super.getText().length();
toolkit.addString(
super.getText().substring(_offset, end).toString(),
attrib, colorpair);
toolkit.setCursor(origin.addOffset(super._caretPosition - _offset, 0));
}
/**
* Process KeyEvents that have been generated by this JTextField.
*/
public void processKeyEvent(KeyEvent ke_) {
/* First call all KeyListener objects that may have been registered
* for this component.
*/
super.processKeyEvent(ke_);
/* Check if any of the KeyListeners consumed the KeyEvent.
*/
if (ke_.isConsumed())
return;
int key = ke_.getKeyCode();
if (key == '\t') {
getParent().nextFocus();
return;
}
else if (key == KeyEvent.VK_BACK_TAB) {
getParent().previousFocus();
return;
}
/*
*/
if (ke_.isActionKey() == false) {
/* If it is a control character, ignore it.
* @todo Do something more useful with control chars.
*/
if (key >= ' ') {
super._document.insert(super._caretPosition, (char ) key);
super._caretPosition++;
if (super._caretPosition - _offset > _columns)
_offset++;
}
}
else {
/* It is an action key.
*/
if (key == KeyEvent.VK_LEFT && super._caretPosition > 0) {
super._caretPosition--;
if (super._caretPosition < _offset)
_offset--;
}
else if (key == KeyEvent.VK_RIGHT && super._caretPosition < super._document.length()) {
super._caretPosition++;
if (super._caretPosition - _offset > _columns)
_offset++;
}
else if (key == KeyEvent.VK_BACK_SPACE && super._caretPosition > 0) {
super._caretPosition--;
super._document.deleteCharAt(super._caretPosition);
if (super._caretPosition < _offset)
_offset--;
}
else if (key == KeyEvent.VK_DELETE &&
super._caretPosition >= 0 && super._caretPosition < super._document.length()) {
super._document.deleteCharAt(super._caretPosition);
}
else if (key == KeyEvent.VK_HOME) {
super._caretPosition = 0;
_offset = 0;
}
else if (key == KeyEvent.VK_END) {
super._caretPosition = super._document.length();
if (super._document.length() > _columns)
_offset = super._document.length() - _columns;
else
_offset = 0;
}
/* Post an action event if ENTER was pressed.
*/
else if (key == KeyEvent.VK_ENTER) {
ActionEvent ae = new ActionEvent(this, _actionCommand);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(ae);
}
}
draw(Toolkit.getDefaultToolkit());
super.requestSync();
}
/** Process a MouseEvent that was generated by clicking the mouse
* somewhere inside this JTextField.
* Clicking the mouse inside the JTextField moves the caret position
* to where the mouse was clicked.
*/
public void processMouseEvent(MouseEvent e_) {
super.processMouseEvent(e_);
if (e_.getButton() == MouseEvent.BUTTON1 &&
e_.getModifiers() == MouseEvent.MOUSE_CLICKED &&
this.isFocusTraversable()) {
int x = e_.getX();
/* Get the absolute origin of this component.
*/
Point origin = getLocationOnScreen();
Insets insets = super.getInsets();
origin.translate(insets.left, insets.top);
int new_caret = _offset + (x - origin.x);
super._caretPosition =
(new_caret < super._document.length()) ?
new_caret : super._document.length();
repaint();
}
}
/**
* Set the text that is presented by this JTextField.
* This method is thread-safe, although most Charva methods are not.
*/
public synchronized void setText(String text_) {
super.setText(text_);
super._caretPosition = super._document.length();
if (super._document.length() > _columns)
_offset = super._document.length() - _columns;
else
_offset = 0;
/* If this component is already displayed, generate a PaintEvent
* and post it onto the queue.
*/
super.repaint();
}
/**
* Process events.
*/
protected void processEvent(AWTEvent evt_) {
super.processEvent(evt_);
if (evt_ instanceof ActionEvent)
postActionEvent((ActionEvent) evt_);
}
/** Invoke all the ActionListener callbacks that may have been registered
* for this component.
*/
public void postActionEvent(ActionEvent ae_) {
if (_actionListeners != null) {
for (Enumeration<ActionListener> e = _actionListeners.elements();
e.hasMoreElements(); ) {
ActionListener al = (ActionListener) e.nextElement();
al.actionPerformed(ae_);
}
}
}
/**
* Register an ActionListener object for this component.
*/
public void addActionListener(ActionListener al_) {
if (_actionListeners == null)
_actionListeners = new Vector<ActionListener>();
_actionListeners.add(al_);
}
public void requestFocus() {
/* Generate the FOCUS_GAINED event.
*/
super.requestFocus();
/* Get the absolute origin of this component.
*/
Point origin = getLocationOnScreen();
Insets insets = super.getInsets();
origin.translate(insets.left, insets.top);
Toolkit.getDefaultToolkit().setCursor(
origin.addOffset(super._caretPosition - _offset, 0));
}
/** Returns a String representation of this component.
*/
public String toString() {
return "JTextField location=" + getLocation() +
" text=\"" + super._document + "\"" +
" actionCommand=\"" + _actionCommand + "\"";
}
public void debug(int level_) {
for (int i=0; i<level_; i++)
System.err.print(" ");
System.err.println("JTextField origin=" + _origin +
" size=" + getSize() + " text=" + super._document);
}
//====================================================================
// INSTANCE VARIABLES
protected boolean _bold = false;
protected int _columns;
/**
* Index (from the start of the string) of the character displayed
* in the left corner of the field. This is always 0 if the string
* is shorter than the field.
*/
protected int _offset = 0;
/** A blank-filled string the same length as the JTextField.
*/
protected String _padding;
/** The string that is sent inside an ActionEvent when ENTER is pressed.
*/
private String _actionCommand = new String("");
/**
* A list of ActionListeners registered for this component.
*/
protected Vector<ActionListener> _actionListeners = null;
}