001: package abbot.editor.editors;
002:
003: import java.awt.event.*;
004: import java.lang.reflect.*;
005: import java.util.*;
006:
007: import javax.swing.*;
008:
009: import abbot.i18n.Strings;
010: import abbot.script.*;
011: import abbot.editor.widgets.*;
012:
013: /**
014: Provide an editor for call steps.
015: @author Blake Christensen <bchristen@users.sourceforge.net>
016: @author twall@users.sourceforge.net
017: */
018: // TODO: add a help button for the selected method
019: public class CallEditor extends StepEditor {
020:
021: private Call call;
022: protected JTextField target;
023: protected JComboBox method;
024: protected ArrayEditor arguments;
025: private String[] names = new String[0];
026: private boolean fieldChanging;
027:
028: public CallEditor(Call call) {
029: super (call);
030: this .call = call;
031:
032: target = addTextField(Strings.get("TargetClass"), call
033: .getTargetClassName());
034: target.setName(TAG_CLASS);
035:
036: method = addComboBox(Strings.get("Method"), call
037: .getMethodName(), getMethodNames());
038: method.setName(TAG_METHOD);
039:
040: arguments = addArrayEditor(Strings.get("Arguments"), call
041: .getArguments());
042: arguments.setName(TAG_ARGS);
043: }
044:
045: protected Call getCall() {
046: return call;
047: }
048:
049: /** Provide a list of method names corresponding to the current target
050: class. Be careful overloading this method, since it is called from
051: the Constructor.
052: */
053: protected String[] getMethodNames() {
054: try {
055: Class cls = call.getTargetClass();
056: String[] names = getMethodNames(getMethods(cls,
057: Modifier.PUBLIC));
058: Arrays.sort(names);
059: return names;
060: } catch (ClassNotFoundException e) {
061: return new String[0];
062: }
063: }
064:
065: protected Class getTargetClass() throws ClassNotFoundException {
066: try {
067: return call.getTargetClass();
068: } catch (NoClassDefFoundError e) {
069: throw new ClassNotFoundException(e.getMessage());
070: }
071: }
072:
073: /** Return all public member and static methods. */
074: protected Map getMethods(Class cls, int mask) {
075: HashMap processed = new HashMap();
076: while (cls != null) {
077: Method[] methods = cls.getDeclaredMethods();
078: for (int i = 0; i < methods.length; i++) {
079: if ((methods[i].getModifiers() & mask) == mask) {
080: processed.put(methods[i].getName(), methods[i]);
081: }
082: }
083: cls = cls.getSuperclass();
084: }
085: return processed;
086: }
087:
088: /** Convert the given array of methods into an array of strings.
089: Subclasses can do additional filtering here.
090: */
091: protected String[] getMethodNames(Map methods) {
092: return (String[]) methods.keySet().toArray(
093: new String[methods.size()]);
094: }
095:
096: protected void validateTargetClass() {
097: try {
098: call.getTargetClass();
099: target.setForeground(DEFAULT_FOREGROUND);
100: } catch (ClassNotFoundException e) {
101: target.setForeground(ERROR_FOREGROUND);
102: } catch (NoClassDefFoundError e) {
103: target.setForeground(ERROR_FOREGROUND);
104: }
105: }
106:
107: protected void validateMethod() {
108: try {
109: call.getMethod();
110: method.setForeground(DEFAULT_FOREGROUND);
111: } catch (IllegalArgumentException e) {
112: method.setForeground(ERROR_FOREGROUND);
113: } catch (NoSuchMethodException e) {
114: method.setForeground(ERROR_FOREGROUND);
115: } catch (ClassNotFoundException e) {
116: method.setForeground(ERROR_FOREGROUND);
117: } catch (NoClassDefFoundError e) {
118: target.setForeground(ERROR_FOREGROUND);
119: }
120: }
121:
122: /** Sychronize the UI with the Call data. */
123: private void availableMethodsChanged() {
124: fieldChanging = true;
125: String[] newNames = getMethodNames();
126: // Ensure there's a selected item
127: Object current = method.getSelectedItem();
128: if (current == null)
129: current = call.getMethodName();
130: boolean changed = newNames.length != names.length;
131: for (int i = 0; i < newNames.length && !changed; i++) {
132: changed = !newNames[i].equals(names[i]);
133: }
134: if (changed) {
135: method.setModel(new DefaultComboBoxModel(newNames));
136: String name = call.getMethodName();
137: if (!name.equals(current))
138: method.setSelectedItem(name);
139: names = newNames;
140: }
141: fieldChanging = false;
142: }
143:
144: /** Sychronize the UI with the Call data. */
145: protected void targetClassChanged() {
146: fieldChanging = true;
147: target.setText(call.getTargetClassName());
148: fieldChanging = false;
149: availableMethodsChanged();
150: validateTargetClass();
151: validateMethod();
152: }
153:
154: /** Sychronize the UI with the Call data. */
155: protected void methodChanged() {
156: if (!call.getMethodName().equals(method.getSelectedItem()))
157: method.setSelectedItem(call.getMethodName());
158: validateMethod();
159: }
160:
161: /** Sychronize the UI with the Call data. */
162: protected void argumentsChanged() {
163: arguments.setValues(call.getArguments());
164: validateMethod();
165: }
166:
167: public void actionPerformed(ActionEvent ev) {
168: if (fieldChanging)
169: return;
170:
171: Object src = ev.getSource();
172: if (src == target) {
173: String cname = target.getText().trim();
174: if (!cname.equals(call.getTargetClassName())) {
175: call.setTargetClassName(cname);
176: availableMethodsChanged();
177: validateTargetClass();
178: validateMethod();
179: fireStepChanged();
180: }
181: } else if (src == method) {
182: String name = (String) method.getSelectedItem();
183: if (!call.getMethodName().equals(name) && name != null) {
184: call.setMethodName(name);
185: validateMethod();
186: fireStepChanged();
187: }
188: } else if (src == arguments) {
189: // FIXME check method signature and do component field if the
190: // first arg is a component, do popup from available refs
191: // FIXME check arguments against method signature
192: Object[] values = arguments.getValues();
193: String[] svalues = new String[values.length];
194: System.arraycopy(values, 0, svalues, 0, values.length);
195: call.setArguments(svalues);
196: validateMethod();
197: fireStepChanged();
198: } else {
199: super.actionPerformed(ev);
200: }
201: }
202: }
|