package logEnabledComponents;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.List;
import java.util.Observable;
import java.util.Observer;
import javax.swing.JRadioButtonMenuItem;
import parser.Value;
import valueTypes.DecimalValue;
import variables.Variable;
import actionScript.ActionScriptFlags;
import expressionConsole.ExpressionConsoleModel;
/**
* A JButton which has all of it's actions logged for later replay.
*
* @author Curran Kelleher
*
*/
public class LogEnabledJRadioButtonMenuItem extends JRadioButtonMenuItem implements Observer,
ActionListener {
private static final long serialVersionUID = -8162310483610735221L;
/**
* A list of all names which have been used. It is checked against for every
* new name to ensure uniqueness.
*/
private static List<String> allUniqueNames = new LinkedList<String>();
/**
* the Variable which will be used to keep track of this object's
* parameters.
*/
Variable thisObjectsParameterVariable;
/**
* A reference to the console model so getInstance() only needs to be called
* once.
*/
ExpressionConsoleModel console = ExpressionConsoleModel.getInstance();
/**
* A flag which is set to false when the update is self-generated (to
* prevent an infinite loop)
*/
boolean respondToUpdates = true;
/**
* If this is false, logging is disabled for this object. It is here for
* constructors and methods to use, so events generated programmatically by
* code in the subclass don't get logged as user-generated events would. The
* code should set this to false, do the action, then set this to true
* again.
*/
private boolean logEventsForThisObject = true;
/**
* The number of times this button has been clicked.
*/
private int clickCount = 0;
/**
* Constructs a LogEnabledJButton whose click actions will be logged into
* the Variable with the specified name in the for of click count. If the
* number is set to 0, then no click occurs. Setting the variable to any
* number except 0 would cause a click event to occur.
* @param text the text of the <code>JRadioButtonMenuItem</code>
* @param uniqueName
* the name of the Variable which will be used to keep track of
* the click count. It must be unique, something long is
* recommended.
*/
public LogEnabledJRadioButtonMenuItem(String text, String uniqueName) {
super(text);
if (allUniqueNames.contains(uniqueName))
console
.enterErrorMessage("There already exists a button with the name "
+ uniqueName
+ "! After this, logging and replay may not work correctly.");
else
allUniqueNames.add(uniqueName);
Variable.getVariable(uniqueName).addObserver(
this,
"Used by a radio button (" + uniqueName
+ ") for logging it's clicks.");
// this is called in this manner because the act of adding the observer
// replaces the existing Variable with an ObservableVariable in the
// symbol table.
thisObjectsParameterVariable = Variable.getVariable(uniqueName);
addActionListener(this);
}
/**
* Called when the button is clicked.
*/
public void actionPerformed(ActionEvent e) {
if (ActionScriptFlags.LOGGING_ENABLED && logEventsForThisObject) {
// don't respond to self-generated updates.
respondToUpdates = false;
// increment the click count
clickCount++;
// log the click
console.enterExpression(thisObjectsParameterVariable.toString()
+ " = " + clickCount);
// do respond to other updates.
respondToUpdates = true;
}
}
/**
* Gets updates whenever the parameter variable changes, and clicks the
* button. If the variable is 0, then the button is not clicked, and it is unbound from it's variable.
*
* @param o
* @param arg
*/
public void update(Observable o, Object arg) {
if (respondToUpdates)
if (arg == thisObjectsParameterVariable) {
boolean invalidValue = false;
Value currentValue = thisObjectsParameterVariable.evaluate();
if (currentValue instanceof DecimalValue) {
if (((DecimalValue) currentValue).value != 0)
this.doClick(0);
else
{
allUniqueNames.remove(thisObjectsParameterVariable.toString());
o.deleteObserver(this);
}
} else
invalidValue = true;
if (invalidValue) {
respondToUpdates = false;
thisObjectsParameterVariable.set(new DecimalValue(
clickCount));
respondToUpdates = true;
console
.enterErrorMessage(thisObjectsParameterVariable
.toString()
+ " is being used by a button and has been set to an invalid value, "
+ currentValue
+ ". It has been reset to it's previous value.");
}
}
}
}