package abbot.editor.editors;
import java.awt.event.*;
import java.lang.reflect.*;
import java.util.*;
import javax.swing.*;
import abbot.Log;
import abbot.i18n.Strings;
import abbot.script.*;
import abbot.editor.widgets.*;
/**
Provide an editor for call steps.
@author Blake Christensen <bchristen@users.sourceforge.net>
@author twall@users.sourceforge.net
*/
// TODO: add a help button for the selected method
public class CallEditor extends StepEditor {
private Call call;
protected JTextField target;
protected JComboBox method;
protected ArrayEditor arguments;
private String[] names = new String[0];
private boolean fieldChanging;
public CallEditor(Call call) {
super(call);
this.call = call;
target = addTextField(Strings.get("TargetClass"),
call.getTargetClassName());
target.setName(TAG_CLASS);
method = addComboBox(Strings.get("Method"),
call.getMethodName(),
getMethodNames());
method.setName(TAG_METHOD);
arguments = addArrayEditor(Strings.get("Arguments"),
call.getArguments());
arguments.setName(TAG_ARGS);
}
protected Call getCall() { return call; }
/** Provide a list of method names corresponding to the current target
class. Be careful overloading this method, since it is called from
the Constructor.
*/
protected String[] getMethodNames() {
try {
Class cls = call.getTargetClass();
String[] names = getMethodNames(getMethods(cls, Modifier.PUBLIC));
Arrays.sort(names);
return names;
}
catch(ClassNotFoundException e) {
return new String[0];
}
}
protected Class getTargetClass() throws ClassNotFoundException {
try {
return call.getTargetClass();
}
catch(NoClassDefFoundError e) {
throw new ClassNotFoundException(e.getMessage());
}
}
/** Return all public member and static methods. */
protected Map getMethods(Class cls, int mask) {
HashMap processed = new HashMap();
while (cls != null) {
Method[] methods = cls.getDeclaredMethods();
for (int i=0;i < methods.length;i++) {
if ((methods[i].getModifiers() & mask) == mask) {
processed.put(methods[i].getName(), methods[i]);
}
}
cls = cls.getSuperclass();
}
return processed;
}
/** Convert the given array of methods into an array of strings.
Subclasses can do additional filtering here.
*/
protected String[] getMethodNames(Map methods) {
return (String[])methods.keySet().toArray(new String[methods.size()]);
}
protected void validateTargetClass() {
try {
call.getTargetClass();
target.setForeground(DEFAULT_FOREGROUND);
}
catch(ClassNotFoundException e) {
target.setForeground(ERROR_FOREGROUND);
}
catch(NoClassDefFoundError e) {
target.setForeground(ERROR_FOREGROUND);
}
}
protected void validateMethod() {
try {
call.getMethod();
method.setForeground(DEFAULT_FOREGROUND);
}
catch(IllegalArgumentException e) {
method.setForeground(ERROR_FOREGROUND);
}
catch(NoSuchMethodException e) {
method.setForeground(ERROR_FOREGROUND);
}
catch(ClassNotFoundException e) {
method.setForeground(ERROR_FOREGROUND);
}
catch(NoClassDefFoundError e) {
target.setForeground(ERROR_FOREGROUND);
}
}
/** Sychronize the UI with the Call data. */
private void availableMethodsChanged() {
fieldChanging = true;
String[] newNames = getMethodNames();
boolean changed = newNames.length != names.length;
for (int i=0;i < newNames.length && !changed;i++) {
changed = !newNames[i].equals(names[i]);
}
if (changed) {
method.setModel(new DefaultComboBoxModel(newNames));
String name = call.getMethodName();
if (!name.equals(method.getSelectedItem()))
method.setSelectedItem(name);
names = newNames;
}
fieldChanging = false;
}
/** Sychronize the UI with the Call data. */
protected void targetClassChanged() {
fieldChanging = true;
target.setText(call.getTargetClassName());
fieldChanging = false;
availableMethodsChanged();
validateTargetClass();
validateMethod();
}
/** Sychronize the UI with the Call data. */
protected void methodChanged() {
if (!call.getMethodName().equals(method.getSelectedItem()))
method.setSelectedItem(call.getMethodName());
validateMethod();
}
/** Sychronize the UI with the Call data. */
protected void argumentsChanged() {
arguments.setValues(call.getArguments());
validateMethod();
}
public void actionPerformed(ActionEvent ev) {
if (fieldChanging)
return;
Object src = ev.getSource();
if (src == target) {
String cname = target.getText().trim();
if (!cname.equals(call.getTargetClassName())) {
call.setTargetClassName(cname);
availableMethodsChanged();
validateTargetClass();
validateMethod();
fireStepChanged();
}
}
else if (src == method) {
String name = (String)method.getSelectedItem();
if (!name.equals(call.getMethodName())) {
call.setMethodName(name);
validateMethod();
fireStepChanged();
}
}
else if (src == arguments) {
// FIXME check method signature and do component field if the
// first arg is a component, do popup from available refs
// FIXME check arguments against method signature
Object[] values = arguments.getValues();
String[] svalues = new String[values.length];
System.arraycopy(values, 0, svalues, 0, values.length);
call.setArguments(svalues);
validateMethod();
fireStepChanged();
}
else {
super.actionPerformed(ev);
}
}
}