/* class AbstractButton
*
* 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.EventQueue;
import charva.awt.ItemSelectable;
import charva.awt.Toolkit;
import charva.awt.Window;
import charva.awt.event.AWTEvent;
import charva.awt.event.ActionEvent;
import charva.awt.event.ActionListener;
import charva.awt.event.ItemEvent;
import charva.awt.event.ItemListener;
import charva.awt.event.KeyEvent;
import charva.awt.event.KeyListener;
import charva.awt.event.MouseEvent;
/**
* This forms the base class for components that exhibit button-like
* behavior.
*/
public abstract class AbstractButton
extends JComponent
implements ItemSelectable, KeyListener
{
/** @deprecated Replaced by setText().
*/
public void setLabel(String label_) {
setText(label_);
}
/** Sets the button's label text.
*/
public void setText(String label_) {
_label = label_;
}
/** Set the button's mnemonic character.
* The mnemonic is the key which will activate this button if focus
* is contained somewhere within this button's ancestor window.<p>
*
* A mnemonic must correspond to a single key on the keyboard and should be
* specified using one of the VK_XXX keycodes defined in
* java.awt.event.KeyEvent. Mnemonics are case-insensitive, therefore a key
* event with the corresponding keycode would cause the button to be
* activated whether or not the Shift modifier was pressed.<p>
*
* If the character defined by the mnemonic is found within the button's
* label string, the first occurrence of it will be underlined to
* indicate the mnemonic to the user. If the corresponding character
* is not contained within the button's label, then it will be displayed
* to the right, surrounded by parentheses.<p>
*
* In the case of a JButton, JCheckBox or JRadioButton, this method
* should only be called <em>after</em> the button has been added
* to a Window, otherwise pressing the corresponding key will have
* no effect.
*
* @param mnemonic_ the keycode of the mnemonic key.
*/
public void setMnemonic(int mnemonic_) {
_mnemonic = mnemonic_;
Window ancestor = super.getAncestorWindow();
if (ancestor != null) {
ancestor.addKeyListener(this);
}
}
/** @deprecated Replaced by getText().
*/
public String getLabel() { return getText(); }
/** Returns the button's label text.
*/
public String getText() { return _label; }
/** Returns the button's mnemonic character.
*/
public int getMnemonic() {
return _mnemonic;
}
/** Sets the action command for this button.
*/
public void setActionCommand(String text_) { _actionCommand = text_; }
/** Returns the action command for this button.
*/
public String getActionCommand() { return _actionCommand; }
/** Process a MouseEvent that was generated by clicking the mouse
* somewhere inside this component.
*/
public void processMouseEvent(MouseEvent e) {
// Request focus if this is a MOUSE_PRESSED
super.processMouseEvent(e);
if (e.getButton() == MouseEvent.BUTTON1 &&
e.getModifiers() == MouseEvent.MOUSE_CLICKED &&
this.isFocusTraversable()) {
this.doClick();
}
}
/** Programmatically performs a "click" of this button.
*/
public void doClick() {
// This is required because our parent window will send the KeyEvent
// to the Container containing the component with the current focus.
// super.requestFocus();
getParent().setFocus(this); // Mustn't generate FocusEvents (?)
Toolkit.getDefaultToolkit().fireKeystroke(KeyEvent.VK_ENTER, this);
}
/**
* Sets the state of the button. Note that this method does not post
* an ActionEvent.
*/
public void setSelected(boolean state_) {
// Post an ItemEvent if the state has changed.
if (_selected != state_) {
int statechange = state_ ? ItemEvent.SELECTED : ItemEvent.DESELECTED;
ItemEvent evt = new ItemEvent(this, this, statechange);
Toolkit.getDefaultToolkit().getSystemEventQueue().postEvent(evt);
}
_selected = state_;
if (isDisplayed())
super.repaint();
}
/** Returns the state of the button.
*/
public boolean isSelected() { return _selected; }
/**
* Process events.
*/
protected void processEvent(AWTEvent evt_) {
super.processEvent(evt_);
if (evt_ instanceof KeyEvent) {
KeyEvent key_event = (KeyEvent) evt_;
if (( ! key_event.isConsumed()) &&
key_event.getKeyCode() == KeyEvent.VK_ENTER &&
super.isEnabled()) {
EventQueue queue = Toolkit.getDefaultToolkit().getSystemEventQueue();
queue.postEvent(new ActionEvent(this, getActionCommand()));
key_event.consume();
}
}
else if (evt_ instanceof ActionEvent)
fireActionPerformed((ActionEvent) evt_);
else if (evt_ instanceof ItemEvent)
fireItemStateChanged((ItemEvent) evt_);
}
/**
* Register an ActionListener object for this button.
*/
public void addActionListener(ActionListener al_) {
if (_actionListeners == null)
_actionListeners = new Vector<ActionListener>();
_actionListeners.add(al_);
}
/** Invoke all the ActionListener callbacks that may have been registered
* for this button.
*/
protected void fireActionPerformed(ActionEvent ae_) {
if (_actionListeners != null) {
for (Enumeration<ActionListener> e = _actionListeners.elements();
e.hasMoreElements(); ) {
ActionListener al = (ActionListener) e.nextElement();
al.actionPerformed(ae_);
}
}
}
/**
* Register an ItemListener object for this component.
*/
public void addItemListener(ItemListener il_) {
if (_itemListeners == null)
_itemListeners = new Vector<ItemListener>();
_itemListeners.add(il_);
}
public void removeItemListener(ItemListener listener_) {
if (_itemListeners == null)
return;
_itemListeners.remove(listener_);
}
/** Implements the KeyListener interface; this is called if a control
* character or a function key or cursor key was typed.
*/
public void keyPressed(KeyEvent ke_) {
if (ke_.getKeyCode() == getMnemonic()) {
doClick();
ke_.consume();
}
}
/** Implements the KeyListener interface; this is called if a printable
* (ASCII or ISO8859-1) character was typed.
*/
public void keyTyped(KeyEvent ke_) {
// We must accept either uppercase or lowercase mnemonic characters.
char keyLower = Character.toLowerCase(ke_.getKeyChar());
char mnemonicLower = Character.toLowerCase((char) getMnemonic());
if (keyLower == mnemonicLower) {
doClick();
ke_.consume();
}
}
/** Implements the KeyListener interface but is never invoked. */
public void keyReleased(KeyEvent ke_) {}
/**
* Invoke all the ItemListener callbacks that may have been registered
* for this component.
*/
protected void fireItemStateChanged(ItemEvent ie_) {
if (_itemListeners != null) {
for (Enumeration<ItemListener> e = _itemListeners.elements();
e.hasMoreElements(); ) {
ItemListener il = (ItemListener) e.nextElement();
il.itemStateChanged(ie_);
}
}
}
/** Returns the complete label string, including the mnemonic key
* surrounded by parentheses (if there is a mnemonic key and the
* mnemonic key does not appear within the label).
*/
protected String getLabelString() {
String label = getText();
if (_mnemonic == 0)
return label; // no mnemonic is set
if (_mnemonic >= ' ' &&
_mnemonic < 0xff &&
label.indexOf((char) _mnemonic) != -1) {
return label; // the mnemonic char appears within the label
}
StringBuffer buf = new StringBuffer(label);
if (_mnemonic < ' ') {
char c = (char) (_mnemonic + '@');
return buf.append(" (^").append(c).append(")").toString();
}
else if (_mnemonic >= KeyEvent.VK_F1 && _mnemonic <= KeyEvent.VK_F20) {
int offset = _mnemonic - KeyEvent.VK_F1 + 1;
return buf.append(" (F").append(offset).append(")").toString();
}
else
return label; // At this stage we don't handle other chars
}
//====================================================================
// INSTANCE VARIABLES
private String _label;
/** The string that is sent in an ActionEvent when ENTER is pressed.
*/
private String _actionCommand;
private int _mnemonic = 0;
/**
* The state of the button. This is package-private because ButtonGroup
* needs to be able to change the state of the button without calling
* setSelected().
*/
boolean _selected = false;
/**
* A list of ActionListeners registered for this component.
*/
protected Vector<ActionListener> _actionListeners = null;
/**
* A list of ItemListeners registered for this component.
*/
protected Vector<ItemListener> _itemListeners = null;
}