APCS/02 Recursion/06 NQueens/edu/kzoo/grid/gui/GeneratedButtonList.java
Rushil Umaretiya 3fc3554899 initial commit
2020-12-04 22:00:49 -05:00

394 lines
18 KiB
Java

// Class: GeneratedButtonList
//
// Author: Alyce Brady
//
// License Information:
// This class is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation.
//
// This class 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 General Public License for more details.
package edu.kzoo.grid.gui;
import javax.swing.JButton;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Grid GUI Support Package:<br>
*
* A <code>GeneratedButtonList</code> object creates a group of
* control buttons based on the methods of another class. When the
* <code>GeneratedButtonList</code> object is constructed, the
* client code must specify a target object (the object whose methods
* are to be associated with control buttons) and a set of arguments
* to be passed to those methods. The <code>GeneratedButtonList</code>
* object will generate control buttons for all of the target object's
* methods that could be passed the given set of arguments and have a
* <code>void</code> return type.
*
* @author Alyce Brady
* @version 29 July 2004
**/
public class GeneratedButtonList extends ArrayList
{
// Define pattern for on...ButtonClick methods.
public static final String prefix = "on";
public static final String suffix = "ButtonClick";
public static final String methNameRegExpr = prefix + ".+" + suffix;
public static final Pattern methNamePattern =
Pattern.compile(methNameRegExpr);
// Instance Variables: Encapsulated data for each GeneratedButtonList object
protected GridAppFrame gui;
protected Object targetObj;
protected boolean includeOnButtonClickMethodsOnly;
protected List targetMethods;
protected Object[] methodArguments;
protected Map buttonLabelToMethodObjMap = new HashMap();
protected boolean displayGridAfterButtonActions;
// constructors and their helper methods
/** Constructs a list of control buttons based on methods associated
* with the given target object. Will only include methods that take
* 0 arguments and have a <code>void</code> return type. The text on
* each control button will be the associated method name or, if the
* name matches the on...ButtonClick format, the middle part of the
* method name. For example, the control button for a doX method
* would have the label "doX", while the control button for an
* onDoYButtonClick method would have the label "DoY". When each
* resulting control button is pressed, it will send the associated
* message to the target object. It may also display the contents
* of the grid afterward, depending on the value of
* <code>displayAfterButtonPresses</code>.
* @param gui graphical user interface that will contain these
* buttons
* @param targetObj an object of the class whose methods should become
* control buttons; the buttons will forward
* messages to targetObj in response to button presses
* @param displayAfterButtonPresses true if the user interface should
* display the contents of the grid after executing
* the behaviors associated with control button
* presses; false otherwise
**/
public GeneratedButtonList(GridAppFrame gui, Object targetObj,
boolean displayAfterButtonPresses)
{
this(gui, targetObj, null, false, displayAfterButtonPresses);
}
/** Constructs a list of control buttons based on methods associated
* with the given target object. Will only include methods that
* take 0 arguments, have a <code>void</code> return type, and, if
* <code>onButtonClickMethodsOnly</code> is true, whose names match
* the on...ButtonClick format (e.g., onXYZButtonClick). The text on
* each control button will be the associated method name or, if the
* name matches the on...ButtonClick format, the middle part of the
* method name. For example, the control button for a doX method
* would have the label "doX", while the control button for an
* onDoYButtonClick method would have the label "DoY". When each
* resulting control button is pressed, it will send the associated
* message to the target object. It may also display the contents
* of the grid afterward, depending on the value of
* <code>displayAfterButtonPresses</code>.
* @param gui graphical user interface that will contain these
* buttons
* @param targetObj an object of the class whose methods should become
* control buttons; the buttons will forward
* messages to targetObj in response to button presses
* @param onButtonClickMethodsOnly true if only on...ButtonClick
* methods should be included; false otherwise
* @param displayAfterButtonPresses true if the user interface should
* display the contents of the grid after executing
* the behaviors associated with control button
* presses; false otherwise
**/
public GeneratedButtonList(GridAppFrame gui, Object targetObj,
boolean onButtonClickMethodsOnly,
boolean displayAfterButtonPresses)
{
this(gui, targetObj, null, onButtonClickMethodsOnly,
displayAfterButtonPresses);
}
/** Constructs a list of control buttons based on methods associated
* with the given target object. Will only include methods that
* could be passed the given set of arguments and that have a
* <code>void</code> return type. The text on each control button
* will be the associated method name or, if the name matches the
* on...ButtonClick format, the middle part of the method name. For
* example, the control button for a doX method would have the label
* "doX", while the control button for an onDoYButtonClick method
* would have the label "DoY". When each resulting control button
* is pressed, it will send the associated message to the target object,
* passing as arguments the objects provided to this constructor.
* It may also display the contents of the grid afterward, depending
* on the value of <code>displayAfterButtonPresses</code>.
* @param gui graphical user interface that will contain these
* buttons
* @param targetObj an object of the class whose methods should become
* control buttons; the buttons will forward
* messages to targetObj in response to button presses
* @param arguments the arguments to pass to methods associated with
* control buttons
* @param displayAfterButtonPresses true if the user interface should
* display the contents of the grid after executing
* the behaviors associated with control button
* presses; false otherwise
**/
public GeneratedButtonList(GridAppFrame gui,
Object targetObj, Object[] arguments,
boolean displayAfterButtonPresses)
{
this(gui, targetObj, arguments, false, displayAfterButtonPresses);
}
/** Constructs a list of control buttons based on methods associated
* with the given target object. Will only include methods that
* could be passed the given set of arguments, that have a
* <code>void</code> return type, and, if
* <code>onButtonClickMethodsOnly</code> is true, whose names match
* the on...ButtonClick format (e.g., onXYZButtonClick). The text on
* each control button will be the associated method name or, if the
* name matches the on...ButtonClick format, the middle part of the
* method name. For example, the control button for a doX method
* would have the label "doX", while the control button for an
* onDoYButtonClick method would have the label "DoY". When each
* resulting control button is pressed, it will send the associated
* message to the target object, passing as arguments the objects
* provided to this constructor. It may also display the contents
* of the grid afterward, depending on the value of
* <code>displayAfterButtonPresses</code>.
* @param gui graphical user interface that will contain these
* buttons
* @param targetObj an object of the class whose methods should become
* control buttons; the buttons will forward
* messages to targetObj in response to button presses
* @param arguments the arguments to pass to methods associated with
* control buttons
* @param onButtonClickMethodsOnly true if only on...ButtonClick
* methods should be included; false otherwise
* @param displayAfterButtonPresses true if the user interface should
* display the contents of the grid after executing
* the behaviors associated with control button
* presses; false otherwise
**/
public GeneratedButtonList(GridAppFrame gui,
Object targetObj, Object[] arguments,
boolean onClickButtonMethodsOnly,
boolean displayAfterButtonPresses)
{
this.gui = gui;
this.targetObj = targetObj;
if ( arguments == null )
this.methodArguments = new Object[0];
else
this.methodArguments = arguments;
this.includeOnButtonClickMethodsOnly = onClickButtonMethodsOnly;
this.displayGridAfterButtonActions = displayAfterButtonPresses;
// Identify the target object's methods that will have control buttons.
identifyButtonMethods();
// Create the control buttons.
createButtons();
}
/** Identifies the target object's methods for which control buttons
* should be created.
**/
protected void identifyButtonMethods()
{
// Get all the methods from the targetObj class, look through
// them, and save all the control button methods in a list.
// (The control button methods are all the void methods that
// take parameters corresponding to those provided in the
// GeneratedButtonList constructor.)
Class targetClass = targetObj.getClass();
targetMethods = new ArrayList();
Method[] allMethods = targetClass.getMethods();
for ( int i = 0; i < allMethods.length; i++ )
{
Method meth = allMethods[i];
if ( meetsControlMethodCriteria(meth, targetClass) )
{
targetMethods.add(meth);
buttonLabelToMethodObjMap.put(buttonLabelFor(meth), meth);
}
}
}
/** Returns <code>true</code> if the given method was declared in
* the specified class (not in one of its superclasses) and has
* the right return type and parameters to be turned into a
* control button; <code>false</code> otherwise.
**/
protected boolean meetsControlMethodCriteria(Method methodToCheck,
Class targetClass)
{
Class retType = methodToCheck.getReturnType();
Class[] paramTypes = methodToCheck.getParameterTypes();
// Check whether method was declared in the target class.
if ( ! (methodToCheck.getDeclaringClass().equals(targetClass)) )
return false;
// Check whether method has the right return type & number of
// parameters.
if ( ! ( retType.equals(void.class) &&
paramTypes.length == methodArguments.length ) )
return false;
// Check whether all its parameters are of the right type.
for ( int j = 0; j < paramTypes.length; j++ )
{
if ( ! paramTypes[j].isInstance(methodArguments[j]) )
{
// This parameter type is not as expected.
return false;
}
}
// Check whether the button name has the right format.
if ( includeOnButtonClickMethodsOnly )
return meetsMethodNameFormatCriteria(methodToCheck.getName());
// This method meets all the criteria for a target method.
return true;
}
/** Returns <code>true</code> if the given method was declared in
* the specified class (not in one of its superclasses) and has
* the right return type and parameters to be turned into a
* control button; <code>false</code> otherwise.
**/
protected boolean meetsMethodNameFormatCriteria(String methodName)
{
Matcher patternMatcher = methNamePattern.matcher(methodName);
return patternMatcher.matches();
}
/** Returns the appropriate button label for the given method. **/
protected String buttonLabelFor(Method method)
{
String methodName = method.getName();
if ( meetsMethodNameFormatCriteria(methodName) )
{
int endIndex = methodName.length() - suffix.length();
return methodName.substring(prefix.length(), endIndex);
}
else
return methodName;
}
/** Creates control buttons that, when pressed, will pass a message to
* the appropriate method in the target object.
* @param targetMethods the methods for which to create control buttons
**/
protected void createButtons()
{
Iterator iter = targetMethods.iterator();
while ( iter.hasNext() )
{
Method meth = (Method) iter.next();
add(new GeneratedThreadedControlButton(gui, buttonLabelFor(meth),
displayGridAfterButtonActions));
}
}
// public method to customize button labels
/** Resets the specified button label associated with a method in
* the target object. The <code>prevButtonLabel</code> parameter
* should be the previous button label. (The default button label
* is the name of the associated method or, if the method name
* matches the onXYZButtonClick format, is the name of the method
* without the on...ButtonClick prefix and suffix, e.g., XYZ). This
* method should be called before the <code>constructWindowContents</code>
* method of the graphical user interface. This method does nothing
* if the list of generated control buttons does not include a button
* whose current label is <code>prevButtonLabel</code>.
* @param prevButtonLabel previous button label
* @param buttonLabel label to place on button
**/
public void resetButtonLabel(String prevButtonLabel, String buttonLabel)
{
// Change the label on the button.
Iterator iter = iterator();
while ( iter.hasNext() )
{
JButton button = (JButton) iter.next();
if ( button.getText().equals(prevButtonLabel) )
{
button.setText(buttonLabel);
// Update the button label to method object map.
Method meth =
(Method) buttonLabelToMethodObjMap.get(prevButtonLabel);
buttonLabelToMethodObjMap.remove(prevButtonLabel);
buttonLabelToMethodObjMap.put(buttonLabel, meth);
}
}
}
// Nested class for generated ThreadedControlButton objects
/** GeneratedThreadedControlButton objects represent buttons whose
* button action is to reflectively invoke the appropriate method
* in the target object.
**/
protected class GeneratedThreadedControlButton
extends ThreadedControlButton
{
/** Constructs a button that will run in its own thread.
* @param gui graphical user interface containing this button
* @param label label to place on button
* @param displayAtEnd true if grid should be displayed when
* button behavior is complete; false otherwise
**/
protected GeneratedThreadedControlButton(GridAppFrame gui,
String label,
boolean displayAtEnd)
{
super(gui, label, displayAtEnd);
}
/** Performs the button action associated with this button;
* actually delegates the button action to the method in the
* target object associated with this button.
**/
public void act()
{
// Get method associated with button label and try to invoke it.
Method meth = (Method) buttonLabelToMethodObjMap.get(getText());
try
{ meth.invoke(targetObj, methodArguments); }
catch (InvocationTargetException e)
{ throw new IllegalArgumentException("Can't invoke " +
meth.getName() + ": " + e);
}
catch (IllegalAccessException e)
{ throw new IllegalArgumentException("Can't invoke " +
meth.getName() + ": " + e);
}
}
}
}