package sunw.demo.buttons;
import java.awt.*;
import java.awt.event.*;
import java.beans.*;
import java.io.Serializable;
import java.util.Vector;
import csgsys.java.util.*;
/**
* A simple Java Beans button. OurButton is a "from-scratch"
* GUI component that's derived from Canvas. It's a good example of
* how to implement bound properties and support for event listeners.
*
* Parts of the source are derived from sun.awt.tint.TinyButtonPeer.
*/
public class OurButton extends Canvas implements Serializable {
/**
* Constructs a Button with the a default label.
*/
public OurButton() {
this("press");
}
/**
* Constructs a Button with the specified label.
* @param label the label of the button
*/
public OurButton(String label) {
super();
this.label = label;
setFont(new Font("Dialog", Font.PLAIN, 12));
setBackground(Color.lightGray);
}
//----------------------------------------------------------------------
/**
* Paint the button: the label is centered in both dimensions.
*
*/
public synchronized void paint(Graphics g) {
int width = size().width;
int height = size().height;
g.setColor(getBackground());
g.fillRect(1, 1, width - 2, height - 2);
g.draw3DRect(0, 0, width - 1, height - 1, !down);
g.setColor(getForeground());
g.setFont(getFont());
g.drawRect(2, 2, width - 4, height - 4);
FontMetrics fm = g.getFontMetrics();
g.drawString(label, (width - fm.stringWidth(label)) / 2,
(height + fm.getMaxAscent() - fm.getMaxDescent()) / 2);
}
/**
* Handle mouse and keyboard events. Note: at the moment the OurButton
* implementation uses JDK1.0.2 style event handling. New GUI components
* should use JavaBeans style event handling.
*/
public boolean handleEvent(Event evt) {
if (! isEnabled()) {
return false;
}
int width = size().width;
int height = size().height;
switch (evt.id) {
case Event.MOUSE_DOWN:
down = true;
repaint();
return true;
case Event.MOUSE_DRAG:
if ((evt.x < 0) || (evt.x > width) ||
(evt.y < 0) || (evt.y > height)) {
if (down) {
down = false;
repaint();
}
} else if (!down) {
down = true;
repaint();
}
return true;
case Event.MOUSE_UP:
if (down) {
fireAction();
down = false;
repaint();
}
return true;
case Event.KEY_PRESS:
if (evt.key == '\n' || evt.key == '\r') {
down = true;
repaint();
fireAction();
down = false;
repaint();
return true;
} else if (evt.key == '\t') {
return true;
}
case Event.GOT_FOCUS:
hasFocus = true;
repaint();
return true;
case Event.LOST_FOCUS:
hasFocus = false;
repaint();
return true;
}
return false;
}
//----------------------------------------------------------------------
// Methods for registering/deregistering event listeners
/**
* The specified ActionListeners actionPerformed method will
* be called each time the button is clicked. The ActionListener
* object is added to a list of ActionListeners managed by
* this button, it can be removed with removeActionListener.
* Note: the JavaBeans specification does not require ActionListeners
* to run in any particular order.
*
* @see #removeActionListener
* @param l the ActionListener
*/
//6-27-97 kls Here is the new add...Listener function
public synchronized void addActionListener(Listener l) {
pushListeners.addElement(l);
}
public synchronized void addActionListener(ActionListener l) {
pushListeners.addElement(l);
}
/**
* Remove this ActionListener from the buttons internal list. If the
* ActionListener isn't on the list, silently do nothing.
*
* @see #addActionListener
* @param l the ActionListener
*/
public synchronized void removeActionListener(ActionListener l) {
pushListeners.removeElement(l);
}
/**
* The specified PropertyChangeListeners propertyChange method will
* be called each time the value of any bound property is changed.
* The PropertyListener object is addded to a list of PropertyChangeListeners
* managed by this button, it can be removed with removePropertyChangeListener.
* Note: the JavaBeans specification does not require PropertyChangeListeners
* to run in any particular order.
*
* @see #removePropertyChangeListener
* @param l the PropertyChangeListener
*/
public void addPropertyChangeListener(PropertyChangeListener l) {
changes.addPropertyChangeListener(l);
}
/**
* Remove this PropertyChangeListener from the buttons internal list.
* If the PropertyChangeListener isn't on the list, silently do nothing.
*
* @see #addPropertyChangeListener
* @param l the PropertyChangeListener
*/
public void removePropertyChangeListener(PropertyChangeListener l) {
changes.removePropertyChangeListener(l);
}
//----------------------------------------------------------------------
/**
* This method has the same effect as pressing the button.
*
* @see #addActionListener
*/
public void fireAction() {
if (debug) {
System.err.println("Button " + getLabel() + " pressed.");
}
Vector targets;
synchronized (this) {
targets = (Vector) pushListeners.clone();
}
ActionEvent actionEvt = new ActionEvent(this, 0, null);
Object o; //6-27-97 kls added
for (int i = 0; i < targets.size(); i++) {
/** 6-27-97 Since I choice to add the new Listener object to the
same Vector as already existed, we must now see which type of
object we have so that we can use the appropriate event invocation
**/
o = targets.elementAt(i);
if (o instanceof ActionListener) {
ActionListener target = (ActionListener)o;
target.actionPerformed(actionEvt);
}
else if (o instanceof Listener) {
((Listener)o).triggerListener();
}
}
Component parent = getParent();
if (parent != null) {
parent.postEvent(new Event(this, Event.MOUSE_DOWN, null));
}
}
/**
* Enable debugging output. Currently a message is printed each time
* the button is clicked. This is a bound property.
*
* @see #getDebug
* @see #addPropertyChangeListener
*/
public void setDebug(boolean x) {
boolean old = debug;
debug = x;
changes.firePropertyChange("debug", new Boolean(old), new Boolean(x));
}
/**
* Returns true if debugging output is enabled.
*
* @see #setDebug
*/
public boolean getDebug() {
return debug;
}
/**
* Set the font size to 18 if true, 12 otherwise. This property overrides
* the value specified with setFontSize. This is a bound property.
*
* @see #isLargeFont
* @see #addPropertyChangeListener
*/
public void setLargeFont(boolean b) {
if (isLargeFont() == b) {
return;
}
int size = 12;
if (b) {
size = 18;
}
Font old = getFont();
setFont(new Font(old.getName(), old.getStyle(), size));
changes.firePropertyChange("largeFont", new Boolean(!b), new Boolean(b));
}
/**
* Returns true if the font is "large" in the sense defined by setLargeFont.
*
* @see #setLargeFont
* @see #setFont
*/
public boolean isLargeFont() {
if (getFont().getSize() >= 18) {
return true;
} else {
return false;
}
}
/**
* Set the point size of the current font. This is a bound property.
*
* @see #getFontSize
* @see #setFont
* @see #setLargeFont
* @see #addPropertyChangeListener
*/
public void setFontSize(int x) {
Font old = getFont();
setFont(new Font(old.getName(), old.getStyle(), x));
changes.firePropertyChange("fontSize", new Integer(old.getSize()), new Integer(x));
}
/**
* Return the current font point size.
*
* @see #setFontSize
*/
public int getFontSize() {
return getFont().getSize();
}
/**
* Set the current font and change its size to fit. This is a
* bound property.
*
* @see #setFontSize
* @see #setLargeFont
*/
public void setFont(Font f) {
Font old = getFont();
super.setFont(f);
sizeToFit();
changes.firePropertyChange("font", old, f);
}
/**
* Set the buttons label and change it's size to fit. This is a
* bound property.
*
* @see #getLabel
*/
public void setLabel(String newLabel) {
String oldLabel = label;
label = newLabel;
sizeToFit();
changes.firePropertyChange("label", oldLabel, newLabel);
}
/**
* Returns the buttons label.
*
* @see #setLabel
*/
public String getLabel() {
return label;
}
public Dimension getPreferredSize() {
FontMetrics fm = getFontMetrics(getFont());
return new Dimension(fm.stringWidth(label) + TEXT_XPAD,
fm.getMaxAscent() + fm.getMaxDescent() + TEXT_YPAD);
}
public Dimension getMinimumSize() {
return getPreferredSize();
}
private void sizeToFit() {
Dimension d = getPreferredSize();
resize(d.width, d.height);
Component p = getParent();
if (p != null) {
p.invalidate();
p.layout();
}
}
/**
* Set the color the buttons label is drawn with. This is a bound property.
*/
public void setForeground(Color c) {
Color old = getForeground();
super.setForeground(c);
changes.firePropertyChange("foreground", old, c);
}
/**
* Set the color the buttons background is drawn with. This is a bound property.
*/
public void setBackground(Color c) {
Color old = getBackground();
super.setBackground(c);
changes.firePropertyChange("background", old, c);
}
private boolean debug;
private PropertyChangeSupport changes = new PropertyChangeSupport(this);
private Vector pushListeners = new Vector();
private String label;
private boolean down;
private boolean hasFocus;
private boolean sized;
static final int TEXT_XPAD = 12;
static final int TEXT_YPAD = 8;
}