package com.hackerdude.swing.widgets;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import javax.swing.Action;
import javax.swing.Icon;
import javax.swing.JComponent;
import javax.swing.JMenuItem;
import javax.swing.KeyStroke;
/**
* An extension to JMenuItem that follows changes to accelerator keys.
*
* Use this instead of JMenuItem if you intend to change the accelerator keys
* for an action attached to the JMEnuItem.
*
* @author David Martinez
* @version 1.0
*/
public class JMenuItemWithSugar extends JMenuItem {
public JMenuItemWithSugar() { super(); }
public JMenuItemWithSugar(Action act) {
this();
setAction(act);
}
public JMenuItemWithSugar(Icon icon) { super(icon); }
public JMenuItemWithSugar(String text) { super(text); }
public JMenuItemWithSugar(String text, Icon icon) { super(text, icon); }
public JMenuItemWithSugar(String text, int mnemonic) {
super(text, mnemonic);
}
public void configurePropertiesFromAction(Action myAction) {
super.configurePropertiesFromAction(myAction);
if (myAction != null) {
KeyStroke keyStroke = (KeyStroke)myAction.getValue(Action.ACCELERATOR_KEY);
if (keyStroke != null) setAccelerator(keyStroke);
}
}
/**
* This is a copy of the JMenuItem's method witht the same name. The only
* thing that was added is a check for the accelerator key.
*/
protected PropertyChangeListener createActionPropertyChangeListener(Action a) {
return
new AbstractActionPropertyChangeListener(this, a){
public void propertyChange(PropertyChangeEvent e) {
String propertyName = e.getPropertyName();
JMenuItem mi = (JMenuItem)getTarget();
if (mi == null) { //WeakRef GC'ed in 1.2
Action action = (Action)e.getSource();
action.removePropertyChangeListener(this);
} else {
if (e.getPropertyName().equals(Action.NAME)) {
String text = (String) e.getNewValue();
mi.setText(text);
mi.repaint();
} else if (propertyName.equals("enabled")) {
Boolean enabledState = (Boolean) e.getNewValue();
mi.setEnabled(enabledState.booleanValue());
mi.repaint();
} else if (e.getPropertyName().equals(Action.SMALL_ICON)) {
Icon icon = (Icon) e.getNewValue();
mi.setIcon(icon);
mi.invalidate();
mi.repaint();
} else if (e.getPropertyName().equals(Action.MNEMONIC_KEY)) {
Integer mn = (Integer) e.getNewValue();
mi.setMnemonic(mn.intValue());
mi.invalidate();
mi.repaint();
} else if ( e.getPropertyName().equals(Action.ACCELERATOR_KEY)) {
KeyStroke keyStroke = (KeyStroke)e.getNewValue();
mi.setAccelerator(keyStroke);
mi.invalidate();
mi.repaint();
}
}
}
};
}
}
abstract class AbstractActionPropertyChangeListener implements PropertyChangeListener {
private static ReferenceQueue queue;
private WeakReference target;
private Action action;
AbstractActionPropertyChangeListener(JComponent c, Action a) {
super();
setTarget(c);
this.action = a;
}
public void setTarget(JComponent c) {
if (queue==null) {
queue = new ReferenceQueue();
}
// Check to see whether any old buttons have
// been enqueued for GC. If so, look up their
// PCL instance and remove it from its Action.
OwnedWeakReference r;
while ( (r = (OwnedWeakReference)queue.poll()) != null) {
AbstractActionPropertyChangeListener oldPCL =
(AbstractActionPropertyChangeListener)r.getOwner();
Action oldAction = oldPCL.getAction();
if (oldAction!=null) {
oldAction.removePropertyChangeListener(oldPCL);
}
}
this.target = new OwnedWeakReference(c, queue, this);
}
public JComponent getTarget() {
return (JComponent)this.target.get();
}
public Action getAction() {
return action;
}
private static class OwnedWeakReference extends WeakReference {
private Object owner;
OwnedWeakReference(Object target, ReferenceQueue queue, Object owner) {
super(target, queue);
this.owner = owner;
}
public Object getOwner() {
return owner;
}
}
}