Source Code Cross Referenced for ScriptEditor.java in  » Testing » abbot-1.0.1 » abbot » editor » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Testing » abbot 1.0.1 » abbot.editor 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package abbot.editor;
0002:
0003:        import java.awt.*;
0004:        import java.awt.event.*;
0005:        import java.io.*;
0006:        import java.lang.reflect.*;
0007:        import java.net.URL;
0008:        import java.util.*;
0009:        import java.util.List;
0010:
0011:        import javax.swing.*;
0012:        import javax.swing.filechooser.FileFilter;
0013:        import javax.swing.event.*;
0014:
0015:        import junit.extensions.abbot.*;
0016:        import abbot.BugReport;
0017:        import abbot.Log;
0018:        import abbot.ExitException;
0019:        import abbot.NoExitSecurityManager;
0020:        import abbot.AssertionFailedError;
0021:        import abbot.Platform;
0022:        import abbot.editor.actions.*;
0023:        import abbot.editor.editors.*;
0024:        import abbot.editor.recorder.*;
0025:        import abbot.editor.widgets.*;
0026:        import abbot.editor.widgets.TextField;
0027:        import abbot.finder.*;
0028:        import abbot.i18n.Strings;
0029:        import abbot.script.*;
0030:        import abbot.script.Action;
0031:        import abbot.script.Resolver;
0032:        import abbot.tester.*;
0033:        import abbot.tester.Robot;
0034:        import abbot.util.*;
0035:
0036:        /**
0037:         * This is the 'model' behind the script editor UI.<p>
0038:         *
0039:         * Acts as a resolver, using the currently in-context script as the component
0040:         * resolver. <p>
0041:         */
0042:
0043:        /* To add new actions, add the action to the list in initActions(),
0044:         * and optionally add it to the menu layout in initMenus.  Define a name for
0045:         * it in EditorConstants, and an inner Action class for it which uses that
0046:         * name. 
0047:         */
0048:        // Apologies for the extreme cruftiness and lack of proper factoring.  This
0049:        // was written at the same time as the underlying framework, and refactored
0050:        // (sort of) into model/view at the same time, so it's hardly a shining
0051:        // example of clean design.  Don't know if it would have been any better
0052:        // written TDD, though.
0053:        public class ScriptEditor implements  ActionListener, Resolver,
0054:                EditorConstants {
0055:
0056:            private static int selectKey;
0057:            private static int captureKey;
0058:            private static int captureImageKey;
0059:
0060:            static {
0061:                try {
0062:                    new EventExceptionHandler().install();
0063:                } catch (Exception e) {
0064:                    // Ignore for now
0065:                }
0066:                String key = System
0067:                        .getProperty("abbot.editor.select_key", "F1");
0068:                selectKey = KeyStroke.getKeyStroke(key).getKeyCode();
0069:                key = System.getProperty("abbot.editor.capture_key", "F2");
0070:                captureKey = KeyStroke.getKeyStroke(key).getKeyCode();
0071:                key = System
0072:                        .getProperty("abbot.editor.capture_image_key", "F3");
0073:                captureImageKey = KeyStroke.getKeyStroke(key).getKeyCode();
0074:            }
0075:
0076:            // if set, log all events, even those going to filtered components
0077:            private static final boolean LOG_ALL_EVENTS = Boolean
0078:                    .getBoolean("abbot.editor.log_all_events");
0079:
0080:            private static final long FIXTURE_EVENT_MASK = Long.getLong(
0081:                    "abbot.fixture.event_mask",
0082:                    EventRecorder.RECORDING_EVENT_MASK).longValue();
0083:
0084:            /** Key to use to invert an assertion/wait. */
0085:            public static final int KC_INVERT = KeyEvent.VK_SHIFT;
0086:            /** Key to use to insert a wait instead of an assertion.   Use option key
0087:                on mac, control key anywhere else. */
0088:            public static final int KC_WAIT = Platform.isMacintosh() ? KeyEvent.VK_ALT
0089:                    : KeyEvent.VK_CONTROL;
0090:            /** Flag for informational status. */
0091:            private static final int INFO = 0;
0092:            /** Flag to indicate a warning. */
0093:            private static final int WARN = 1;
0094:            /** Flag to indicate an error. */
0095:            private static final int ERROR = 2;
0096:            /** Flag to indicate a script failure. */
0097:            private static final int FAILURE = 3;
0098:            /** Prefixes for different types of status messages. */
0099:            private static final String[] statusFormat = { "Normal", "Warning",
0100:                    "Error", "Failure" };
0101:            private static final Color[] statusColor = { Color.black,
0102:                    Color.orange.darker(), Color.red, Color.red, };
0103:
0104:            private ArrayList insertActions = new ArrayList();
0105:            private ArrayList assertActions = new ArrayList();
0106:            private ArrayList waitActions = new ArrayList();
0107:            private ArrayList captureActions = new ArrayList();
0108:
0109:            /** Adapter for representing the script itself, providing access to
0110:             * individual script steps.
0111:             */
0112:            private ScriptModel scriptModel;
0113:            private ScriptTable scriptTable;
0114:            private SecurityManager securityManager;
0115:            private SecurityManager oldSecurityManager;
0116:
0117:            private int nonce;
0118:            /** Keep all application under test threads in the same group to make them
0119:             * easier to track. */
0120:            private ThreadGroup appGroup;
0121:            private TestHierarchy hierarchy;
0122:            private Hierarchy oldHierarchy;
0123:            private Recorder[] recorders;
0124:            private SpinningDialWaitIndicator waiter;
0125:            /** Allow exits from anywhere until the editor is fully initialized. */
0126:            private boolean rootIsExiting = true;
0127:            private boolean exiting;
0128:            private boolean hiding;
0129:            private boolean ignoreStepEvents;
0130:            /** Whether to ignore incoming AWT events. */
0131:            private boolean ignoreEvents;
0132:            /** Is there a script or launch step currently running? */
0133:            private boolean isScriptRunning;
0134:            /** When was some portion of the app exercised? */
0135:            private long lastLaunchTime;
0136:            /** Are we trying to capture an image? */
0137:            private boolean capturingImage;
0138:            /** What component is currently "selected" for capture? */
0139:            private Component captureComponent;
0140:            private Component innermostCaptureComponent;
0141:            private Highlighter highlighter;
0142:            /** Is this the first editor launched, or one under test? */
0143:            private boolean isRootEditor = true;
0144:            /** AWT input state. */
0145:            private static InputState state = Robot.getState();
0146:            /** Generic filter to select a test script. */
0147:            private ScriptFilter filter = new ScriptFilter();
0148:
0149:            /** Current test case class (should derive from AWTTestCase). */
0150:            private Class testClass;
0151:            /** Current test suite.  */
0152:            private ScriptTestSuite testSuite;
0153:            /** Current test script. */
0154:            private Script testScript;
0155:            /** Is the current script a temporary placeholder? */
0156:            private File tempFile;
0157:            /** Runner used to execute the script. */
0158:            private StepRunner runner;
0159:            /** Current set of scripts, based on the test suite (if any). */
0160:            private List testScriptList;
0161:            /** Currently selected component.  Note that this may be a dummy
0162:             * component.
0163:             */
0164:            private Component selectedComponent;
0165:            /** Currently selected reference, if any. */
0166:            private ComponentReference selectedReference;
0167:
0168:            /** Are we currently recording events? */
0169:            private boolean recording;
0170:            /** The current recorder to pass events for capture. */
0171:            private Recorder recorder;
0172:            /** Since recorder starts with a key release, and stops with a key press,
0173:                make sure we don't start immediately after stopping.
0174:             */
0175:            private boolean justStoppedRecording;
0176:            /** Need to be able to set the combo box selection w/o reacting to the
0177:             * resulting posted action.
0178:             */
0179:            private boolean ignoreComboBox;
0180:            /** Where to stop. */
0181:            private Step stopStep;
0182:
0183:            // GUI components
0184:            private JFileChooser chooser;
0185:            private ScriptEditorFrame view;
0186:            private ComboBoxModel model;
0187:
0188:            private boolean invertAssertions;
0189:            private boolean waitAssertions;
0190:            private ActionMap actionMap;
0191:            private String name;
0192:
0193:            /** The edtiro configuration */
0194:            private EditorContext editorConfiguration;
0195:
0196:            /**
0197:             * Constructs a ScriptEditor which handles script editing logic.
0198:             * ScriptEditorFrame provides the view/controller.
0199:             * @see ScriptEditorFrame
0200:             */
0201:            public ScriptEditor(EditorContext ec) {
0202:
0203:                editorConfiguration = ec;
0204:
0205:                //
0206:
0207:                if (ec.isEmbedded()) {
0208:                    name = "Script Editor (emdedded)";
0209:                } else if (Boolean.getBoolean("abbot.framework.launched")) {
0210:                    isRootEditor = false;
0211:                    name = "Script Editor (under test)";
0212:                } else {
0213:                    System.setProperty("abbot.framework.launched", "true");
0214:                    name = "Script Editor (root)";
0215:                }
0216:
0217:                // TODO: clean this up
0218:                actionMap = initActions();
0219:                hierarchy = initContext(isRootEditor);
0220:                recorders = initRecorders();
0221:                view = initFrame(isRootEditor);
0222:                hierarchy.setFiltered(view, true);
0223:                updateDynamicActions(view);
0224:
0225:                view.setComponentBrowser(createComponentBrowser());
0226:                addEventHandlers(view);
0227:
0228:                // Clear the status only if there were no errors
0229:                if (view.getStatus().equals(Strings.get("Initializing"))) {
0230:                    setStatus(Strings.get("Ready"));
0231:                }
0232:                rootIsExiting = false;
0233:            }
0234:
0235:            /** Provides a convenient menu setup definition.
0236:                Use a defined action name to indicate that action's place within the
0237:                menu.  Null values indicate menu separators.
0238:             */
0239:            private String[][] initMenus() {
0240:                ArrayList fileMenu = new ArrayList();
0241:                ArrayList helpMenu = new ArrayList();
0242:                fileMenu.addAll(Arrays.asList(new String[] { MENU_FILE,
0243:                        ACTION_SCRIPT_NEW, ACTION_SCRIPT_DUPLICATE,
0244:                        ACTION_SCRIPT_OPEN, null, ACTION_SCRIPT_SAVE,
0245:                        ACTION_SCRIPT_SAVE_AS, ACTION_SCRIPT_RENAME,
0246:                        ACTION_SCRIPT_CLOSE, null, ACTION_SCRIPT_DELETE, }));
0247:
0248:                helpMenu.add(MENU_HELP);
0249:                if (!Platform.isOSX()) {
0250:                    fileMenu.add(null);
0251:                    fileMenu.add(ACTION_EDITOR_QUIT);
0252:                    helpMenu.add(ACTION_EDITOR_ABOUT);
0253:                }
0254:                helpMenu.addAll(Arrays.asList(new String[] {
0255:                        ACTION_EDITOR_USERGUIDE, ACTION_EDITOR_WEBSITE,
0256:                        ACTION_EDITOR_EMAIL, ACTION_EDITOR_BUGREPORT, }));
0257:
0258:                return new String[][] {
0259:                        (String[]) fileMenu
0260:                                .toArray(new String[fileMenu.size()]),
0261:                        { MENU_EDIT, ACTION_STEP_CUT, null,
0262:                                ACTION_STEP_MOVE_UP, ACTION_STEP_MOVE_DOWN,
0263:                                ACTION_STEP_GROUP, null,
0264:                                ACTION_SELECT_COMPONENT, null,
0265:                                ACTION_SCRIPT_CLEAR, },
0266:                        { MENU_TEST, ACTION_RUN, ACTION_RUN_TO,
0267:                                ACTION_RUN_SELECTED, null,
0268:                                ACTION_EXPORT_HIERARCHY, null,
0269:                                ACTION_RUN_LAUNCH, ACTION_RUN_TERMINATE, null,
0270:                                ACTION_TOGGLE_STOP_ON_FAILURE,
0271:                                ACTION_TOGGLE_STOP_ON_ERROR,
0272:                                ACTION_TOGGLE_FORKED, ACTION_GET_VMARGS,
0273:                                ACTION_TOGGLE_SLOW_PLAYBACK,
0274:                                ACTION_TOGGLE_AWT_MODE, },
0275:                        { MENU_INSERT, ACTION_INSERT_ANNOTATION,
0276:                                ACTION_INSERT_APPLET, ACTION_INSERT_CALL,
0277:                                ACTION_INSERT_COMMENT,
0278:                                ACTION_INSERT_EXPRESSION, ACTION_INSERT_LAUNCH,
0279:                                ACTION_INSERT_FIXTURE, ACTION_INSERT_SAMPLE,
0280:                                ACTION_INSERT_SCRIPT, ACTION_INSERT_SEQUENCE,
0281:                                ACTION_INSERT_TERMINATE, },
0282:                        { MENU_CAPTURE, },
0283:                        (String[]) helpMenu
0284:                                .toArray(new String[helpMenu.size()]), };
0285:            }
0286:
0287:            // All editor actions should be defined here
0288:            private ActionMap initActions() {
0289:                javax.swing.Action[] actions = { new EditorAboutAction(),
0290:                        new EditorEmailAction(), new EditorBugReportAction(),
0291:                        new EditorWebsiteAction(), new EditorUserGuideAction(),
0292:                        new EditorQuitAction(), new ScriptOpenAction(),
0293:                        new ScriptNewAction(), new ScriptDuplicateAction(),
0294:                        new ScriptSaveAction(), new ScriptSaveAsAction(),
0295:                        new ScriptRenameAction(), new ScriptCloseAction(),
0296:                        new ScriptDeleteAction(), new ScriptClearAction(),
0297:                        new StepCutAction(), new StepMoveUpAction(),
0298:                        new StepMoveDownAction(), new StepGroupAction(),
0299:                        new RunAction(), new RunToAction(),
0300:                        new RunSelectedAction(), new RunLaunchAction(),
0301:                        new RunTerminateAction(), new GetVMArgsAction(),
0302:                        new SelectTestSuiteAction(),
0303:                        new ExportHierarchyAction(), new ToggleForkedAction(),
0304:                        new InsertLaunchAction(), new InsertFixtureAction(),
0305:                        new InsertAppletAction(), new InsertTerminateAction(),
0306:                        new InsertCallAction(), new InsertSampleAction(),
0307:                        new InsertSequenceAction(), new InsertScriptAction(),
0308:                        new InsertCommentAction(),
0309:                        new InsertExpressionAction(),
0310:                        new InsertAnnotationAction(),
0311:                        new ToggleStopOnFailureAction(),
0312:                        new ToggleStopOnErrorAction(),
0313:                        new ToggleSlowPlaybackAction(),
0314:                        new ToggleAWTModeAction(), new CaptureImageAction(),
0315:                        new CaptureComponentAction(),
0316:                        new SelectComponentAction(), };
0317:                ActionMap map = new ActionMap();
0318:                for (int i = 0; i < actions.length; i++) {
0319:                    Object key = actions[i].getValue(EditorAction.ACTION_KEY);
0320:                    map.put(key, actions[i]);
0321:                }
0322:                return map;
0323:            }
0324:
0325:            /**
0326:             *  Add event handlers to their respective components
0327:             */
0328:            private void addEventHandlers(final ScriptEditorFrame view) {
0329:                scriptTable.getSelectionModel().addListSelectionListener(
0330:                        new ScriptTableSelectionHandler());
0331:                scriptTable.addMouseListener(new MouseAdapter() {
0332:                    public void mouseClicked(MouseEvent me) {
0333:                        if ((me.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
0334:                            if (view.getEditor() == null)
0335:                                setStepEditor();
0336:                        }
0337:                    }
0338:                });
0339:                MouseListener ml = new MouseAdapter() {
0340:                    public void mouseClicked(MouseEvent me) {
0341:                        if ((me.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
0342:                            int size = scriptTable.getRowCount();
0343:                            scriptTable.clearSelection();
0344:                            scriptTable.setCursorLocation(size);
0345:                        }
0346:                    }
0347:                };
0348:                view.addMouseListener(ml);
0349:                view.getTestScriptSelector().addItemListener(
0350:                        new ScriptSelectorItemHandler());
0351:                view.addWindowListener(new WindowAdapter() {
0352:                    public void windowClosing(WindowEvent e) {
0353:                        quitApplication();
0354:                    }
0355:                });
0356:                if (Platform.isOSX()) {
0357:                    // Mac has it's own dedicated Quit/About menu items
0358:                    OSXAdapter.register(view,
0359:                            actionMap.get(ACTION_EDITOR_QUIT), actionMap
0360:                                    .get(ACTION_EDITOR_ABOUT), null);
0361:                }
0362:            }
0363:
0364:            /**
0365:             * Determines if the editor is testing itself and initializes the 
0366:             * security manager accordingly.  
0367:             */
0368:            private TestHierarchy initContext(boolean isRoot) {
0369:                TestHierarchy hierarchy = editorConfiguration
0370:                        .getTestHierarchy();
0371:                if (hierarchy == null) {
0372:                    hierarchy = new TestHierarchy() {
0373:                        private String desc = "Test hierarchy for " + name;
0374:
0375:                        public String toString() {
0376:                            return desc;
0377:                        }
0378:                    };
0379:                }
0380:
0381:                // eventually this should go away; all hierarchy usage should be
0382:                // explicit. 
0383:                oldHierarchy = AWTHierarchy.getDefault();
0384:                if (isRoot) {
0385:                    AWTHierarchy.setDefault(hierarchy);
0386:                    initSecurityManager();
0387:                    try {
0388:                        new EventExceptionHandler().install();
0389:                    } catch (Exception e) {
0390:                        Log.warn(e);
0391:                    }
0392:                }
0393:                return hierarchy;
0394:            }
0395:
0396:            private Recorder[] initRecorders() {
0397:                // Use the editor as the resolver, since the actual resolver will
0398:                // be the currently scoped script.
0399:                Recorder[] recorders = new Recorder[] {
0400:                        new EventRecorder(this , false),
0401:                        new EventRecorder(this , true), };
0402:
0403:                ActionListener recorderListener = new ActionListener() {
0404:                    public void actionPerformed(final ActionEvent event) {
0405:                        setStatus(event.getActionCommand());
0406:                    }
0407:                };
0408:                for (int i = 0; i < recorders.length; i++) {
0409:                    recorders[i].addActionListener(recorderListener);
0410:                }
0411:                return recorders;
0412:            }
0413:
0414:            /** Initialize the primary editor frame. */
0415:            private ScriptEditorFrame initFrame(final boolean isRoot) {
0416:
0417:                scriptModel = new ScriptModel() {
0418:                    public boolean isCellEditable(int row, int col) {
0419:                        return false;
0420:                    }
0421:                };
0422:                runner = new EditorStepRunner();
0423:                runner.setTerminateOnError(false);
0424:                runner.addStepListener(new StepListener() {
0425:                    public void stateChanged(StepEvent ev) {
0426:                        if (ignoreStepEvents)
0427:                            return;
0428:                        reflectScriptExecutionState(ev);
0429:                    }
0430:                });
0431:                // Customize the ScriptTable so we can vary the color of any given
0432:                // step based on our last run status (of which the table itself should
0433:                // be ignorant).
0434:                scriptTable = new ScriptTable(scriptModel) {
0435:                    public Color getStepColor(Step step, boolean selected) {
0436:                        Color color = super .getStepColor(step, selected);
0437:                        // Make the stop step appear a different color
0438:                        if (step == stopStep) {
0439:                            Color stopColor = getSelectionBackground().darker();
0440:                            color = stopColor;
0441:                        }
0442:                        Throwable thr = runner.getError(step);
0443:                        if (thr != null) {
0444:                            Color tint = (thr instanceof  AssertionFailedError) ? statusColor[ScriptEditor.FAILURE]
0445:                                    : statusColor[ScriptEditor.ERROR];
0446:                            if (step instanceof  Sequence) {
0447:                                color = color.brighter();
0448:                            }
0449:                            if (selected) {
0450:                                color = mixColors(color, tint);
0451:                            } else {
0452:                                color = tint;
0453:                            }
0454:                        }
0455:                        return color;
0456:                    }
0457:                };
0458:
0459:                // Override default "cut" action in table
0460:                ActionMap amap = scriptTable.getActionMap();
0461:                amap.put("cut", actionMap.get(ACTION_STEP_CUT));
0462:                InputMap imap = scriptTable.getInputMap();
0463:                imap
0464:                        .put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0),
0465:                                "toggle");
0466:
0467:                // Only allow the script editor to dispose of the frame
0468:                String prefFile = Preferences.PROPS_FILENAME;
0469:                if (!isRoot) {
0470:                    prefFile += ".tmp";
0471:                }
0472:                Preferences prefs = new Preferences(prefFile);
0473:                String title = Strings.get("ScriptEditor.title",
0474:                        new Object[] { "" });
0475:                ScriptEditorFrame f = new ScriptEditorFrame(initMenus(),
0476:                        actionMap, this , title, scriptTable, prefs) {
0477:                    /** @deprecated Don't allow code under test to hide the editor. */
0478:                    public void hide() {
0479:                        if (hiding || isDisposeFromRootEditor()) {
0480:                            hiding = false;
0481:                            super .hide();
0482:                        }
0483:                    }
0484:
0485:                    public void dispose() {
0486:                        // Need to prevent arbitrary disposal by the code under test.
0487:                        // Only allow the dispose if one of the following is true:
0488:                        // a) we triggered it (exiting == true)
0489:                        // b) the root script editor is disposing us
0490:                        if (exiting || isDisposeFromRootEditor()) {
0491:                            super .dispose();
0492:                        }
0493:                    }
0494:
0495:                    public String getName() {
0496:                        String name = super .getName();
0497:                        if (isRoot)
0498:                            name += " (root)";
0499:                        return name;
0500:                    }
0501:                };
0502:                return f;
0503:            }
0504:
0505:            /** Provide a color that is a mix of the two given colors. */
0506:            private Color mixColors(Color c1, Color c2) {
0507:                return new Color((c1.getRed() + c2.getRed()) / 2, (c1
0508:                        .getGreen() + c2.getGreen()) / 2, (c1.getBlue() + c2
0509:                        .getBlue()) / 2);
0510:            }
0511:
0512:            /** Return whether the root editor disposed of this instance. */
0513:            private boolean isDisposeFromRootEditor() {
0514:                // FIXME cf how applets prevent disposal of embedded frame
0515:                // AWTHierarchy surrounds disposal calls with the property
0516:                // abbot.finder.disposal set to "true"
0517:                return !isRootEditor
0518:                        && Boolean.getBoolean("abbot.finder.disposal");
0519:            }
0520:
0521:            private void createAsserts(ArrayList list, ComponentTester tester,
0522:                    boolean wait) {
0523:                list.clear();
0524:                Method[] methods = tester.getAssertMethods();
0525:                for (int i = 0; i < methods.length; i++) {
0526:                    list.add(new TesterMethodAction(tester, methods[i], wait));
0527:                }
0528:                methods = tester.getComponentAssertMethods();
0529:                if (list.size() != 0 && methods.length != 0)
0530:                    list.add(null);
0531:                for (int i = 0; i < methods.length; i++) {
0532:                    list.add(new TesterMethodAction(tester, methods[i], wait));
0533:                }
0534:                methods = tester.getPropertyMethods();
0535:                if (list.size() != 0 && methods.length != 0)
0536:                    list.add(null);
0537:                for (int i = 0; i < methods.length; i++) {
0538:                    String name = methods[i].getName();
0539:                    if (name.startsWith("is"))
0540:                        name = name.substring(2);
0541:                    else if (name.startsWith("get") || name.startsWith("has"))
0542:                        name = name.substring(3);
0543:                    list.add(new TesterMethodAction(tester, methods[i], wait));
0544:                }
0545:            }
0546:
0547:            /** Return a script step encapsulating an image comparison.  
0548:             * Assumes the script context is not null.
0549:             */
0550:            private Step captureComponentImage(Component comp) {
0551:                Step step = null;
0552:                ComponentTester tester = ComponentTester.getTester(comp);
0553:                java.awt.image.BufferedImage img = tester.capture(comp,
0554:                        !(comp instanceof  Window));
0555:                try {
0556:                    // Save the image file relative to the current context
0557:                    ComponentReference ref = addComponent(comp);
0558:                    File scriptFile = ((Script) getResolverContext()).getFile();
0559:                    File newFile = new File(
0560:                            getResolverContext().getDirectory(), scriptFile
0561:                                    .getName()
0562:                                    + "-"
0563:                                    + ref.getID()
0564:                                    + ImageComparator.IMAGE_SUFFIX);
0565:                    int index = 1;
0566:                    while (newFile.exists()) {
0567:                        newFile = new File(getResolverContext().getDirectory(),
0568:                                scriptFile.getName() + "-" + ref.getID() + "-"
0569:                                        + index++
0570:                                        + ImageComparator.IMAGE_SUFFIX);
0571:                    }
0572:                    ImageComparator.writeImage(newFile, img);
0573:                    // Note that the pathname is saved relative to the script
0574:                    // context. 
0575:                    step = new Assert(getResolverContext(), null,
0576:                            ComponentTester.class.getName(), "assertImage",
0577:                            new String[] { ref.getID(), newFile.getName(),
0578:                                    "true" }, "true", false);
0579:                } catch (IOException io) {
0580:                    Log.warn(io);
0581:                }
0582:                return step;
0583:            }
0584:
0585:            /** Start recording, launching the code under test if necessary. */
0586:            private void startRecording(Recorder rec) {
0587:                Log.debug("Starting recorder");
0588:                boolean noWindows = countShowingWindows(null) == 0;
0589:                boolean canLaunch = testScript != null
0590:                        && testScript.hasLaunch() && !isAppLaunched();
0591:                if (noWindows && !canLaunch) {
0592:                    // Can't launch, and there are no windows to
0593:                    // record on, so show a warning
0594:                    view.showError(Strings.get("NoWindows.title"), Strings
0595:                            .get("NoWindows"));
0596:                } else {
0597:                    if (recorder != null)
0598:                        stopRecording(true);
0599:                    Log.debug("Now recording with " + rec);
0600:                    recording = true;
0601:                    recorder = rec;
0602:
0603:                    setStatus("Please wait...");
0604:                    // Apply an input blocking mask to show the recorder is busy
0605:                    //waiter = new SpinningDialWaitIndicator(view);
0606:                    //waiter.setText("Recording...");
0607:                    // get us out of the way
0608:                    // FIXME this puts us WAY back on linux; this is only a
0609:                    // problem in that the status bar is often hidden
0610:                    // Maybe make a floating status while the recorder is
0611:                    // running. 
0612:                    // Only go back if the app is already up, otherwise the
0613:                    // about-to-be-launched app is hidden.
0614:                    if (!noWindows)
0615:                        view.toBack();
0616:                    recorder.start();
0617:
0618:                    if (noWindows) {
0619:                        launch(false);
0620:                    }
0621:                }
0622:            }
0623:
0624:            /** Stop recording and update the recorder actions' state. */
0625:            private void stopRecording(boolean discardRecording) {
0626:                Log.debug("Stopping recorder");
0627:                recording = false;
0628:                int type = INFO;
0629:                String extended = null;
0630:                String status = Strings
0631:                        .get(discardRecording ? "RecorderCanceled"
0632:                                : "RecorderFinished");
0633:                try {
0634:                    recorder.terminate();
0635:                } catch (RecordingFailedException e) {
0636:                    String msg = Strings.get("editor.recording.stop_failure");
0637:                    Throwable error = e.getReason() instanceof  BugReport ? e
0638:                            .getReason() : new BugReport(msg, e.getReason());
0639:                    Log.log("Recording stop failure: " + error.toString());
0640:                    view.showWarning(msg);
0641:                    status = error.getMessage();
0642:                    extended = error.toString();
0643:                    type = ERROR;
0644:                }
0645:                try {
0646:                    if (!discardRecording) {
0647:                        Step step = recorder.getStep();
0648:                        // Ignore empty results
0649:                        if (!(step instanceof  Sequence && ((Sequence) step)
0650:                                .size() == 0)) {
0651:                            addStep(step);
0652:                        }
0653:                    }
0654:                } finally {
0655:                    recorder = null;
0656:                    if (waiter != null) {
0657:                        waiter.dispose();
0658:                        waiter = null;
0659:                    }
0660:                }
0661:                view.toFront();
0662:                setStatus(status, extended, type);
0663:            }
0664:
0665:            private RecordAllAction recordAllAction;
0666:            private RecordAllAction recordAllMotionAction;
0667:
0668:            private void updateDynamicActions(ScriptEditorFrame view) {
0669:                Class cls = selectedComponent == null ? Component.class
0670:                        : selectedComponent.getClass();
0671:                ComponentTester tester = ComponentTester.getTester(cls);
0672:                // assert submenu
0673:                createAsserts(assertActions, tester, false);
0674:                // wait submenu
0675:                createAsserts(waitActions, tester, true);
0676:                // insert submenu (only include one instance of each uniquely-named
0677:                // method. 
0678:                insertActions.clear();
0679:                Map map = new HashMap();
0680:                Method[] methods = tester.getActions();
0681:                for (int i = 0; i < methods.length; i++) {
0682:                    TesterMethodAction action = new TesterMethodAction(tester,
0683:                            methods[i], true);
0684:                    map.put(action.getName(), action);
0685:                }
0686:                methods = tester.getComponentActions();
0687:                for (int i = 0; i < methods.length; i++) {
0688:                    TesterMethodAction action = new TesterMethodAction(tester,
0689:                            methods[i], true);
0690:                    map.put(action.getName(), action);
0691:                }
0692:                insertActions.addAll(map.values());
0693:                // capture actions
0694:
0695:                captureActions.clear();
0696:                recordAllAction = new RecordAllAction(ACTION_CAPTURE,
0697:                        recorders[0], false);
0698:                captureActions.add(recordAllAction);
0699:                recordAllMotionAction = new RecordAllAction(ACTION_CAPTURE_ALL,
0700:                        recorders[1], true);
0701:                captureActions.add(recordAllMotionAction);
0702:                captureActions.add(null);
0703:                captureActions.add(new CaptureImageAction());
0704:                captureActions.add(new CaptureComponentAction());
0705:
0706:                view.populateInsertMenu(insertActions);
0707:                view.populateAssertMenu(assertActions);
0708:                view.populateWaitMenu(waitActions);
0709:                view.populateCaptureMenu(captureActions);
0710:            }
0711:
0712:            private void setSelected(String which, boolean select) {
0713:                javax.swing.Action action = actionMap.get(which);
0714:                if (action != null) {
0715:                    ((EditorToggleAction) action).setSelected(select);
0716:                } else {
0717:                    Log.warn("Toggle action " + which + " is missing");
0718:                }
0719:            }
0720:
0721:            private void setEnabled(String which, boolean enable) {
0722:                javax.swing.Action action;
0723:                if (which == ACTION_DYNAMIC) {
0724:                    ArrayList[] lists = new ArrayList[] { captureActions,
0725:                            waitActions, assertActions, insertActions };
0726:                    for (int i = 0; i < lists.length; i++) {
0727:                        Iterator iter = lists[i].iterator();
0728:                        while (iter.hasNext()) {
0729:                            action = (javax.swing.Action) iter.next();
0730:                            if (action != null)
0731:                                action.setEnabled(enable);
0732:                        }
0733:                    }
0734:                } else {
0735:                    action = actionMap.get(which);
0736:                    if (action != null) {
0737:                        action.setEnabled(enable);
0738:                    } else {
0739:                        Log.warn("Action " + which + " is missing");
0740:                    }
0741:                }
0742:            }
0743:
0744:            /**
0745:             * Initalize the componentBrowser and listeners to the scriptTable
0746:             */
0747:            private ComponentBrowser createComponentBrowser() {
0748:                ComponentBrowser cb = new ComponentBrowser(this , hierarchy);
0749:                cb.setEnabled(false);
0750:                cb.addSelectionListener(new ComponentBrowserListener() {
0751:                    public void selectionChanged(ComponentBrowser src,
0752:                            Component comp, ComponentReference ref) {
0753:                        setSelectedComponent(comp, ref);
0754:                    }
0755:
0756:                    public void propertyAction(ComponentBrowser src, Method m,
0757:                            Object value, boolean sample) {
0758:                        if (selectedComponent == null)
0759:                            return;
0760:                        addPropertyMethodCall(m, value, sample);
0761:                    }
0762:                });
0763:                return cb;
0764:            }
0765:
0766:            /**
0767:             * Install a new security manager to prevent launched applications
0768:             * from exiting the JVM.  This is only a partial solution; ideally
0769:             * we'd like to be able to kill all the launched app's threads, or force
0770:             * an unload of the class and reload it.
0771:             * Should only be installed once, in the root editor context.
0772:             */
0773:            private void initSecurityManager() {
0774:                if (Boolean.getBoolean("abbot.no_security_manager"))
0775:                    return;
0776:
0777:                securityManager = editorConfiguration.getSecurityManager();
0778:                if (securityManager == null) {
0779:                    securityManager = new EditorSecurityManager();
0780:                }
0781:
0782:                try {
0783:                    oldSecurityManager = System.getSecurityManager();
0784:                    System.setSecurityManager(securityManager);
0785:                } catch (Exception e) {
0786:                    oldSecurityManager = securityManager = null;
0787:                    Log.warn(e);
0788:                }
0789:            }
0790:
0791:            /** Respond to various components. */
0792:            public void actionPerformed(ActionEvent ev) {
0793:                if (ev.getSource() == view.getTestScriptSelector()
0794:                        && !ignoreComboBox) {
0795:                    Script script = (Script) view.getTestScriptSelector()
0796:                            .getSelectedItem();
0797:                    if (script != testScript)
0798:                        setScript(script);
0799:                } else if (ev.getSource() == view.getTestScriptDescription()) {
0800:                    if (testScript != null) {
0801:                        JTextField tf = view.getTestScriptDescription();
0802:                        String desc = tf.getText();
0803:                        if ("".equals(desc)) {
0804:                            String cmd = ev.getActionCommand();
0805:                            if (!TextField.isDocumentAction(cmd)) {
0806:                                tf.setText(testScript.getDefaultDescription());
0807:                                testScript.setDescription(null);
0808:                            }
0809:                        } else if (!desc.equals(testScript
0810:                                .getDefaultDescription())) {
0811:                            testScript.setDescription(desc);
0812:                        }
0813:                    }
0814:                } else {
0815:                    Log.warn("Unrecognized event: " + ev.getActionCommand()
0816:                            + "(" + ev.getID() + ")");
0817:                }
0818:            }
0819:
0820:            /** Remove the selected step. */
0821:            private void cutSelection() {
0822:                int row = scriptTable.getSelectedRow();
0823:                if (row == -1) {
0824:                    Log.warn("Unexpected cut state");
0825:                    return;
0826:                }
0827:                scriptModel.removeSteps(scriptTable.getSelectedSteps());
0828:                int count = scriptTable.getRowCount();
0829:                if (count > 0) {
0830:                    if (row >= count)
0831:                        row = count - 1;
0832:                    scriptTable.setRowSelectionInterval(row, row);
0833:                    scriptTable.setCursorLocation(row + 1);
0834:                }
0835:                setActionsEnabledState();
0836:                setStatus("");
0837:            }
0838:
0839:            private void moveSelectionUp() {
0840:                scriptTable.moveUp();
0841:                setActionsEnabledState();
0842:            }
0843:
0844:            /** Move the selected step down. */
0845:            private void moveSelectionDown() {
0846:                scriptTable.moveDown();
0847:                setActionsEnabledState();
0848:            }
0849:
0850:            /** Put the current selection into a sequence. */
0851:            private void groupSelection() {
0852:                int row = scriptTable.getSelectedRow();
0853:                Sequence seq = new Sequence(getResolverContext(), (String) null);
0854:                List list = scriptTable.getSelectedSteps();
0855:                Step first = (Step) list.get(0);
0856:                Sequence parent = scriptModel.getParent(first);
0857:                int index = parent.indexOf(first);
0858:                scriptModel.removeSteps(list);
0859:                Iterator iter = list.iterator();
0860:                Step last = parent;
0861:                while (iter.hasNext()) {
0862:                    last = (Step) iter.next();
0863:                    seq.addStep(last);
0864:                }
0865:                scriptModel.insertStep(parent, seq, index);
0866:                scriptModel.toggle(row);
0867:                scriptTable.setRowSelectionInterval(row, scriptModel
0868:                        .getRowOf(last));
0869:                setActionsEnabledState();
0870:            }
0871:
0872:            /** Insert a launch step. */
0873:            void insertLaunch() {
0874:                Step step = new Launch(getResolverContext(),
0875:                        LaunchEditor.HELP_DESC, "abbot.editor.ScriptEditor",
0876:                        "main", new String[] { "[]" }, ".", false);
0877:                addStep(step);
0878:            }
0879:
0880:            /** Insert an applet step. */
0881:            void insertApplet() {
0882:                Step step = new Appletviewer(getResolverContext(),
0883:                        AppletviewerEditor.HELP_DESC, "your.applet.class.here",
0884:                        new HashMap(), null, null, null);
0885:                addStep(step);
0886:            }
0887:
0888:            /** Insert a terminate step. */
0889:            void insertTerminate() {
0890:                Step step = new Terminate(getResolverContext(), (String) null);
0891:                scriptTable.setCursorLocation(scriptTable.getRowCount());
0892:                addStep(step);
0893:            }
0894:
0895:            private void insertCall(boolean sample) {
0896:                if (sample) {
0897:                    addStep(new Sample(getResolverContext(), (String) null,
0898:                            Strings.get("YourClassName"), Strings
0899:                                    .get("YourMethodName"), null, Strings
0900:                                    .get("YourPropertyName")));
0901:                } else {
0902:                    addStep(new Call(getResolverContext(), (String) null,
0903:                            Strings.get("YourClassName"), Strings
0904:                                    .get("YourMethodName"), null));
0905:                }
0906:            }
0907:
0908:            /** Insert a new, empty sequence. */
0909:            private void insertSequence() {
0910:                addStep(new Sequence(getResolverContext(), (String) null, null));
0911:            }
0912:
0913:            private void insertComment() {
0914:                addStep(new Comment(getResolverContext(), ""));
0915:            }
0916:
0917:            private void insertExpression() {
0918:                addStep(new Expression(getResolverContext(), ""));
0919:            }
0920:
0921:            private void insertAnnotation() {
0922:                addStep(new Annotation(getResolverContext(), ""));
0923:            }
0924:
0925:            /** Insert another script as a step in this one. */
0926:            private void insertScript(boolean fixture) {
0927:                JFileChooser chooser = getChooser(filter);
0928:                chooser.setCurrentDirectory(getWorkingDirectory());
0929:                if (chooser.showOpenDialog(view) == JFileChooser.APPROVE_OPTION) {
0930:                    File file = chooser.getSelectedFile();
0931:                    if (!file.exists()) {
0932:                        try {
0933:                            file.createNewFile();
0934:                        } catch (IOException e) {
0935:                            view.showError(e.toString());
0936:                        }
0937:                    }
0938:                    Script script = fixture ? new Fixture(file
0939:                            .getAbsolutePath(), hierarchy) : new Script(file
0940:                            .getAbsolutePath(), hierarchy);
0941:                    try {
0942:                        script.load();
0943:                        addStep(script);
0944:                    } catch (Exception exc) {
0945:                        view.showError(exc.toString());
0946:                    }
0947:                }
0948:            }
0949:
0950:            /** Returns the current test suite's directory, if available, the
0951:                directory of the current script, if available, or the current working 
0952:                directory.  If the current script has not yet been saved, 
0953:                uses the current working directory.
0954:             */
0955:            private File getWorkingDirectory() {
0956:                return testSuite != null ? testSuite.getDirectory()
0957:                        : (testScript != null && !editingTempFile() ? testScript
0958:                                .getDirectory()
0959:                                : new File(System.getProperty("user.dir")));
0960:            }
0961:
0962:            /** Return a file chooser that filters for test scripts. */
0963:            // FIXME some open, close operations should be sticky w/r/t
0964:            // last directory used
0965:            private JFileChooser getChooser(FileFilter f) {
0966:                if (chooser == null) {
0967:                    chooser = new JFileChooser();
0968:                    chooser.setCurrentDirectory(getWorkingDirectory());
0969:                }
0970:                chooser.setFileFilter(f);
0971:                return chooser;
0972:            }
0973:
0974:            /** Set the test case to the one corresponding to the given index. */
0975:            private void setScript(int index) {
0976:                if (getScripts().size() == 0) {
0977:                    setScript((Script) null);
0978:                    if (testSuite != null)
0979:                        setStatus(Strings.get("NoScripts"), null, WARN);
0980:
0981:                } else {
0982:                    if (index >= getScripts().size())
0983:                        index = getScripts().size() - 1;
0984:                    setScript(getScriptAt(index));
0985:                }
0986:            }
0987:
0988:            private void setScript(Script script) {
0989:                if (script == testScript && script != null)
0990:                    return;
0991:
0992:                Log.debug("Setting script to '" + script + "'");
0993:                if (script != null) {
0994:                    try {
0995:                        script.load();
0996:                    } catch (InvalidScriptException ise) {
0997:                        Log.warn(ise);
0998:                        setScript((String) null);
0999:                        view.showError("Invalid Script", ise.toString());
1000:                        return;
1001:                    } catch (Exception e) {
1002:                        setScript((String) null);
1003:                        Log.warn(e);
1004:                        return;
1005:                    }
1006:                }
1007:
1008:                if (testScript != null) {
1009:                    UIContext context = testScript.getUIContext();
1010:                    if (context != null
1011:                            && !context.equivalent(runner.getCurrentContext()))
1012:                        runner.terminate();
1013:                }
1014:                testScript = script;
1015:                scriptTable.clearSelection();
1016:                scriptModel.setScript(script);
1017:                if (script == null) {
1018:                    scriptTable.setCursorLocation(0);
1019:                    scriptTable.setEnabled(false);
1020:                    view.getTestScriptDescription().setText("");
1021:                    view.getTestScriptDescription().setEnabled(false);
1022:                    setStatus(Strings.get("NoScript"));
1023:                } else {
1024:                    scriptTable.setEnabled(true);
1025:                    scriptTable.setCursorLocation(script.hasLaunch() ? 1 : 0);
1026:                    if (chooser != null) {
1027:                        chooser.setCurrentDirectory(script.getDirectory());
1028:                    }
1029:                    view.getTestScriptDescription().setText(
1030:                            script.getDescription());
1031:                    view.getTestScriptDescription().setEnabled(true);
1032:                    setStatus(Strings.get("editor.editing_script",
1033:                            new Object[] { testScript.getName() }));
1034:                }
1035:                setActionsEnabledState();
1036:
1037:                ignoreComboBox = true;
1038:                view.getTestScriptSelector().setSelectedItem(testScript);
1039:                ignoreComboBox = false;
1040:                updateTitle();
1041:            }
1042:
1043:            /** Update the state of all actions.  This method should be invoked after
1044:             * any GUI state change.
1045:             */
1046:            private void setActionsEnabledState() {
1047:                if (!SwingUtilities.isEventDispatchThread()) {
1048:                    SwingUtilities.invokeLater(new Runnable() {
1049:                        public void run() {
1050:                            setActionsEnabledState();
1051:                        }
1052:                    });
1053:                    return;
1054:                }
1055:
1056:                boolean haveScript = testScript != null;
1057:                boolean haveSelection = scriptTable.getSelectedRow() != -1;
1058:                boolean notEmdedded = !editorConfiguration.isEmbedded();
1059:
1060:                setEnabled(ACTION_SCRIPT_OPEN, true);
1061:                setEnabled(ACTION_TOGGLE_STOP_ON_FAILURE, haveScript);
1062:                setSelected(ACTION_TOGGLE_STOP_ON_FAILURE, haveScript
1063:                        && runner.getStopOnFailure());
1064:                setEnabled(ACTION_TOGGLE_STOP_ON_ERROR, haveScript);
1065:                setSelected(ACTION_TOGGLE_STOP_ON_ERROR, haveScript
1066:                        && runner.getStopOnError());
1067:                setEnabled(ACTION_TOGGLE_FORKED, haveScript);
1068:                setSelected(ACTION_TOGGLE_FORKED, haveScript
1069:                        && testScript.isForked());
1070:                setEnabled(ACTION_GET_VMARGS, haveScript
1071:                        && testScript.isForked());
1072:                setEnabled(ACTION_TOGGLE_SLOW_PLAYBACK, haveScript);
1073:                setSelected(ACTION_TOGGLE_SLOW_PLAYBACK, haveScript
1074:                        && testScript.isSlowPlayback());
1075:                setEnabled(ACTION_TOGGLE_AWT_MODE, haveScript);
1076:                setSelected(ACTION_TOGGLE_AWT_MODE, haveScript
1077:                        && testScript.isAWTMode());
1078:
1079:                setEnabled(ACTION_RUN, haveScript);
1080:                setEnabled(ACTION_RUN_TO, haveScript && haveSelection);
1081:                setEnabled(ACTION_RUN_SELECTED, haveScript && haveSelection
1082:                        && isAppLaunched());
1083:                setEnabled(ACTION_EXPORT_HIERARCHY, haveScript
1084:                        && isAppLaunched());
1085:                setEnabled(ACTION_RUN_LAUNCH, haveScript && notEmdedded
1086:                        && testScript.hasLaunch() && !isAppLaunched());
1087:                setEnabled(ACTION_RUN_TERMINATE, isAppLaunched() && notEmdedded);
1088:                setEnabled(ACTION_SCRIPT_NEW, true);
1089:                setEnabled(ACTION_SCRIPT_DUPLICATE, haveScript);
1090:                setEnabled(ACTION_SCRIPT_SAVE, haveScript);
1091:                setEnabled(ACTION_SCRIPT_SAVE_AS, haveScript);
1092:                setEnabled(ACTION_SCRIPT_RENAME, haveScript);
1093:                setEnabled(ACTION_SCRIPT_DELETE, haveScript);
1094:                setEnabled(ACTION_SCRIPT_CLOSE, haveScript);
1095:
1096:                setEnabled(ACTION_STEP_CUT, haveScript && haveSelection);
1097:                setEnabled(ACTION_STEP_MOVE_UP, haveScript && haveSelection
1098:                        && scriptTable.canMoveUp());
1099:                setEnabled(ACTION_STEP_MOVE_DOWN, haveScript && haveSelection
1100:                        && scriptTable.canMoveDown());
1101:                setEnabled(ACTION_STEP_GROUP, haveScript && haveSelection);
1102:                setEnabled(ACTION_SCRIPT_CLEAR, haveScript);
1103:
1104:                setEnabled(ACTION_INSERT_LAUNCH, notEmdedded && haveScript
1105:                        && !testScript.hasLaunch());
1106:                setEnabled(ACTION_INSERT_FIXTURE, haveScript
1107:                        && !testScript.hasLaunch());
1108:                setEnabled(ACTION_INSERT_APPLET, notEmdedded && haveScript
1109:                        && !testScript.hasLaunch());
1110:                setEnabled(ACTION_INSERT_TERMINATE, notEmdedded && haveScript
1111:                        && !testScript.hasTerminate());
1112:                setEnabled(ACTION_INSERT_SCRIPT, haveScript);
1113:                setEnabled(ACTION_INSERT_CALL, haveScript);
1114:                setEnabled(ACTION_INSERT_SAMPLE, haveScript);
1115:                setEnabled(ACTION_INSERT_SEQUENCE, haveScript);
1116:                setEnabled(ACTION_INSERT_COMMENT, haveScript);
1117:                setEnabled(ACTION_INSERT_EXPRESSION, haveScript);
1118:                setEnabled(ACTION_INSERT_ANNOTATION, haveScript);
1119:                setEnabled(ACTION_DYNAMIC, haveScript);
1120:
1121:                view.getComponentBrowser().setEnabled(!isScriptRunning);
1122:            }
1123:
1124:            /** Set the current test script.  */
1125:            void setScript(String filename) {
1126:                Script script = filename != null ? new Script(filename,
1127:                        hierarchy) : null;
1128:                setScript(script);
1129:            }
1130:
1131:            /** Indicate the component and/or reference currently in use. */
1132:            private void setSelectedComponent(Component c,
1133:                    ComponentReference ref) {
1134:
1135:                if (c == selectedComponent && ref == selectedReference)
1136:                    return;
1137:
1138:                boolean updateActions = c != selectedComponent;
1139:                selectedComponent = c;
1140:                selectedReference = ref;
1141:                String status;
1142:                if (ref != null) {
1143:                    status = Strings.get(c == null ? "ComponentReferenceX"
1144:                            : "ComponentReference",
1145:                            new Object[] { ref.getID() });
1146:                } else if (c != null) {
1147:                    status = hierarchy.contains(c) ? Strings
1148:                            .get("UnreferencedComponent") : Strings
1149:                            .get("editor.component_filtered");
1150:                } else {
1151:                    status = Strings.get("NoComponent");
1152:                }
1153:                setStatus(status);
1154:                if (updateActions) {
1155:                    updateDynamicActions(view);
1156:                }
1157:            }
1158:
1159:            private void setTestSuite(String suiteClassname) {
1160:                setTestSuite(suiteClassname, null);
1161:            }
1162:
1163:            /** Sets the currently selected test suite, updating all gui components
1164:                appropriately.  */
1165:            private void setTestSuite(String suiteClassname, ClassLoader cl) {
1166:                if (cl == null)
1167:                    cl = getClass().getClassLoader();
1168:                Log.debug("Setting test suite to " + suiteClassname);
1169:                testSuite = null;
1170:                testScriptList = null;
1171:                if (suiteClassname != null) {
1172:                    try {
1173:                        // FIXME use a dynamic class loader so we can reload after
1174:                        // changes to the suite/fixture class. 
1175:                        Class cls = Class.forName(suiteClassname, true, cl);
1176:                        if (!ScriptFixture.class.isAssignableFrom(cls)
1177:                                && !ScriptTestSuite.class.isAssignableFrom(cls)) {
1178:                            view.showWarning(Strings.get("editor.wrong_class",
1179:                                    new Object[] { cls.getName() }));
1180:                        } else {
1181:                            testClass = cls;
1182:                            Method suiteMethod = null;
1183:                            testSuite = null;
1184:                            try {
1185:                                suiteMethod = testClass.getMethod("suite",
1186:                                        new Class[0]);
1187:                                testSuite = (ScriptTestSuite) suiteMethod
1188:                                        .invoke(null, new Class[0]);
1189:                            } catch (NoSuchMethodException nsm) {
1190:                                view.showError(nsm.toString());
1191:                                testSuite = null;
1192:                            } catch (InvocationTargetException ite) {
1193:                                view.showError(ite.toString());
1194:                            } catch (IllegalAccessException iae) {
1195:                                view.showError(iae.toString());
1196:                            }
1197:                        }
1198:                    } catch (ClassNotFoundException e) {
1199:                        view.showWarning(Strings.get("editor.suite_not_found",
1200:                                new Object[] { suiteClassname }));
1201:                    }
1202:                }
1203:                if (testSuite == null) {
1204:                    view.getCurrentTestSuiteLabel().setText(
1205:                            Strings.get("NoSuite"));
1206:                    model = new DefaultComboBoxModel();
1207:                    view.getTestScriptSelector().setModel(model);
1208:                    view.getTestScriptSelector().setEnabled(false);
1209:                    model.setSelectedItem(null);
1210:                } else {
1211:                    view.getTestScriptSelector().setEnabled(true);
1212:                    view.getCurrentTestSuiteLabel().setText(
1213:                            testSuite.toString());
1214:                    Object oldSelection = view.getTestScriptSelector()
1215:                            .getSelectedItem();
1216:                    ignoreComboBox = true;
1217:                    view.getTestScriptSelector().setEnabled(true);
1218:                    // Workaround for indexing bug on OSX
1219:                    view.getTestScriptSelector().setSelectedItem(null);
1220:                    List list = getScripts();
1221:                    Object[] data = list.toArray(new Object[list.size()]);
1222:                    model = new DefaultComboBoxModel(data);
1223:                    view.getTestScriptSelector().setModel(model);
1224:                    // If the test suite didn't actually change, then keep the old
1225:                    // selection. 
1226:                    if (getScripts().contains(oldSelection))
1227:                        model.setSelectedItem(oldSelection);
1228:                    ignoreComboBox = false;
1229:                }
1230:            }
1231:
1232:            /** Set the frame title to the default. */
1233:            private void updateTitle() {
1234:                String title = Strings.get("ScriptEditor.title",
1235:                        new Object[] { testScript != null ? (" ("
1236:                                + testScript.getName() + ")") : "" });
1237:                view.setTitle(title);
1238:            }
1239:
1240:            /** Pull up a dialog with all available test suites.  */
1241:            private void browseTests() {
1242:                ClassLoader cl = getContextClassLoader();
1243:                String path = cl instanceof  PathClassLoader ? ((PathClassLoader) cl)
1244:                        .getClassPath()
1245:                        : null;
1246:                if (path == null)
1247:                    path = System.getProperty("java.class.path");
1248:
1249:                TestSelector selector = new TestSelector(view, path);
1250:                selector.setVisible(true);
1251:                String className = selector.getSelectedItem();
1252:                if (className != null && checkSaveBeforeClose()) {
1253:                    terminate();
1254:                    boolean none = className.equals(TestSelector.TEST_NONE);
1255:                    setTestSuite(none ? null : className, cl);
1256:                    setScript(0);
1257:                    if (none) {
1258:                        setStatus(Strings.get("editor.no_suite"));
1259:                    }
1260:                }
1261:            }
1262:
1263:            /** @return true if it's ok to exit. */
1264:            protected boolean checkSaveBeforeClose() {
1265:                // query save/cancel/exit
1266:                if (testScript != null && (testScript.isDirty())) {
1267:                    int opt = view.showConfirmation(Strings
1268:                            .get("ScriptModified"),
1269:                            JOptionPane.YES_NO_CANCEL_OPTION);
1270:                    if (opt == JOptionPane.CANCEL_OPTION
1271:                            || opt == JOptionPane.CLOSED_OPTION) {
1272:                        return false;
1273:                    } else if (opt == JOptionPane.YES_OPTION) {
1274:                        saveScript();
1275:                    }
1276:                }
1277:                return true;
1278:            }
1279:
1280:            private void closeScript() {
1281:                if (!checkSaveBeforeClose())
1282:                    return;
1283:                setScript((Script) null);
1284:            }
1285:
1286:            /** Quit the application. */
1287:            void quitApplication() {
1288:                if (!checkSaveBeforeClose())
1289:                    return;
1290:
1291:                Log.debug("editor quit" + (isRootEditor ? " (root)" : ""));
1292:                dispose();
1293:                if (isRootEditor) {
1294:                    rootIsExiting = true;
1295:                } else {
1296:                    AWTHierarchy.setDefault(oldHierarchy);
1297:                }
1298:
1299:                if (!editorConfiguration.isEmbedded()) {
1300:                    System.exit(0);
1301:                }
1302:            }
1303:
1304:            /** Set the contents of the status message. */
1305:            public void setStatus(String msg) {
1306:                setStatus(msg, null, INFO);
1307:            }
1308:
1309:            /** Set the contents of the status message to the given exception. */
1310:            private String getStackTrace(Throwable thr) {
1311:                StringWriter writer = new StringWriter();
1312:                thr.printStackTrace(new PrintWriter(writer));
1313:                return writer.toString();
1314:            }
1315:
1316:            /** Set the contents of the status message. */
1317:            public void setStatus(String msg, String extended, int type) {
1318:                String text = Strings.get(statusFormat[type],
1319:                        new Object[] { msg });
1320:                view.setStatus(text, extended, statusColor[type]);
1321:                // Save all messages to the log
1322:                Log.log(text);
1323:            }
1324:
1325:            private void setStatusForStep(Step step) {
1326:                if (step == null) {
1327:                    setStatus("");
1328:                    return;
1329:                }
1330:
1331:                Throwable error = runner.getError(step);
1332:                boolean fromScript = step == testScript;
1333:                String msg = error != null ? error.toString() : null;
1334:                String inStep = Strings.get("InStep", new Object[] { step });
1335:                String where = Strings.get("StepAt",
1336:                        new Object[] { Script.getFile(step),
1337:                                new Integer(Script.getLine(step)) })
1338:                        + "\n";
1339:                // Don't need location info for these
1340:                if (error instanceof  AssertionFailedError
1341:                        && ((AssertionFailedError) error).getLine() != 0) {
1342:                    where = "";
1343:                }
1344:
1345:                String extended = null;
1346:                int type = INFO;
1347:                if (error != null) {
1348:                    Log.log(error);
1349:                    boolean isFailure = (error instanceof  AssertionFailedError);
1350:                    type = isFailure ? FAILURE : ERROR;
1351:                    extended = getStackTrace(error);
1352:                    // If we're not stopping on failure, don't mention it
1353:                    // specifically
1354:                    if (fromScript) {
1355:                        if ((isFailure && !runner.getStopOnFailure())
1356:                                || (!isFailure && !runner.getStopOnError())) {
1357:                            msg = Strings.get(isFailure ? "ScriptFailure"
1358:                                    : "ScriptError");
1359:                        } else {
1360:                            // Otherwise ignore messages from the script itself
1361:                            return;
1362:                        }
1363:                    } else {
1364:                        extended = inStep + "\n" + where + extended;
1365:                    }
1366:                } else if (fromScript) {
1367:                    msg = Strings.get("ScriptSuccess");
1368:                }
1369:                // If nothing interesting happened, leave the status alone
1370:                if (msg != null)
1371:                    setStatus(msg, extended, type);
1372:            }
1373:
1374:            /** Return a ComponentReference corresponding to the currently selected
1375:                Component or ComponentReference, creating one if necessary.
1376:             */
1377:            private String getSelectedComponentID() {
1378:                String id = null;
1379:                if (selectedReference != null) {
1380:                    id = selectedReference.getID();
1381:                } else if (selectedComponent != null) {
1382:                    ComponentReference ref = addComponent(selectedComponent);
1383:                    id = ref.getID();
1384:                    setStatus(Strings.get("ComponentReference",
1385:                            new Object[] { id }));
1386:                }
1387:                return id;
1388:            }
1389:
1390:            /** Add either an Action or an Assert method provided by the given
1391:                Tester. */
1392:            private void addTesterCall(Method method, ComponentTester tester,
1393:                    boolean wait, String docs) {
1394:                boolean invert = invertAssertions;
1395:                Class[] params = method.getParameterTypes();
1396:                String id = getSelectedComponentID();
1397:                Class componentClass = selectedComponent != null ? selectedComponent
1398:                        .getClass()
1399:                        : null;
1400:                boolean componentArg0 = params.length > 0
1401:                        && Component.class.isAssignableFrom(params[0]);
1402:
1403:                String argString = view.showInputDialog(Strings
1404:                        .get("IdentifyArguments"), docs, componentArg0 ? id
1405:                        : null);
1406:                if (argString == null)
1407:                    return;
1408:
1409:                String[] args = ArgumentParser.parseArgumentList(argString);
1410:                try {
1411:                    insertTesterCall(tester, method, componentClass, id, args,
1412:                            wait, invert);
1413:                } catch (IllegalArgumentException iae) {
1414:                    Log.warn(iae);
1415:                } catch (NoSuchReferenceException nsr) {
1416:                    Log.warn(nsr);
1417:                }
1418:            }
1419:
1420:            /** Invoked after the user has selected a component and a property for
1421:             * it.
1422:             */
1423:            private void addPropertyMethodCall(Method method, Object value,
1424:                    boolean sample) {
1425:                String id = getSelectedComponentID();
1426:                String methodName = method.getName();
1427:                String[] args = ComponentTester.class.isAssignableFrom(method
1428:                        .getDeclaringClass()) ? new String[] { id } : null;
1429:                String targetClassName = method.getDeclaringClass().getName();
1430:                if (sample) {
1431:                    String varName = Strings.get("YourPropertyName");
1432:                    Sample step = args == null ? new Sample(
1433:                            getResolverContext(), null, methodName, id, varName)
1434:                            : new Sample(getResolverContext(), null,
1435:                                    targetClassName, methodName, args, varName);
1436:                    addStep(step);
1437:                } else {
1438:                    String expectedValue = ArgumentParser.toString(value);
1439:                    Assert step = args == null ? new Assert(
1440:                            getResolverContext(), null, methodName, id,
1441:                            expectedValue, invertAssertions) : new Assert(
1442:                            getResolverContext(), null, targetClassName,
1443:                            methodName, args, expectedValue, invertAssertions);
1444:                    step.setWait(waitAssertions);
1445:                    addStep(step);
1446:                }
1447:            }
1448:
1449:            /** Returns null if not found. */
1450:            public String getComponentID(Component comp) {
1451:                ComponentReference ref = getComponentReference(comp);
1452:                return ref != null ? ref.getID() : null;
1453:            }
1454:
1455:            /** Insert a new step at the current cursor location.  */
1456:            void addStep(Step step) {
1457:                Sequence parent = scriptTable.getCursorParent();
1458:                int index = scriptTable.getCursorParentIndex();
1459:                scriptModel.insertStep(parent, step, index);
1460:                int row = scriptModel.getRowOf(step);
1461:                scriptTable.setRowSelectionInterval(row, row);
1462:                scriptTable.setCursorLocation(row + 1);
1463:                setActionsEnabledState();
1464:            }
1465:
1466:            /** Create a new script. */
1467:            private void newScript(boolean copyFixture) {
1468:                if (!checkSaveBeforeClose())
1469:                    return;
1470:                File file = editorConfiguration.getNewFileTemplate();
1471:                if (file == null) {
1472:                    try {
1473:                        file = File
1474:                                .createTempFile(Script.UNTITLED_FILE, ".xml");
1475:                        tempFile = file;
1476:                    } catch (IOException io) {
1477:                        JFileChooser chooser = getChooser(filter);
1478:                        File dir = getWorkingDirectory();
1479:                        chooser.setCurrentDirectory(dir);
1480:                        chooser.setSelectedFile(new File(dir,
1481:                                Script.UNTITLED_FILE + ".xml"));
1482:                        if (chooser.showSaveDialog(view) != JFileChooser.APPROVE_OPTION) {
1483:                            return;
1484:                        }
1485:                        file = chooser.getSelectedFile();
1486:                    }
1487:                }
1488:
1489:                if (!file.exists() || file.isFile()) {
1490:                    newScript(file, copyFixture);
1491:                } else {
1492:                    // FIXME display an error
1493:                }
1494:            }
1495:
1496:            /** Create a new script at the given filename, or open it if it already
1497:             * exists.  Optionally copies the fixture from the current script.
1498:             */
1499:            void newScript(File file, boolean copyFixture) {
1500:                if (!checkSaveBeforeClose())
1501:                    return;
1502:
1503:                try {
1504:                    boolean insert = file.createNewFile() || file.length() == 0;
1505:                    Script srcFixture = testScript;
1506:                    setScript(file.getAbsolutePath());
1507:                    if (insert) {
1508:                        if (!copyFixture || srcFixture == null) {
1509:                            insertTerminate();
1510:                            insertLaunch();
1511:                        } else {
1512:                            copyFixture(srcFixture);
1513:                        }
1514:                    }
1515:                    setStatus(Strings.get(copyFixture ? "FixtureDuplicated"
1516:                            : "NewScriptCreated",
1517:                            new Object[] { file.getName() }));
1518:                } catch (IOException io) {
1519:                    view.showError("File Error", io.toString());
1520:                }
1521:            }
1522:
1523:            /** Copy the fixture from the given script into the current one. */
1524:            public void copyFixture(Script src) {
1525:                Step first = src.getStep(0);
1526:                Step last = src.getStep(src.size() - 1);
1527:                if (first instanceof  UIContext) {
1528:                    setStatus(Strings.get("editor.adding_launch"));
1529:                    addStep(first);
1530:                }
1531:                if (src.size() > 1 && (src.getStep(1) instanceof  Assert)) {
1532:                    Assert wait = (Assert) src.getStep(1);
1533:                    if (wait.isWait()
1534:                            && wait.getMethodName()
1535:                                    .equals("assertFrameShowing")) {
1536:                        setStatus(Strings.get("editor.adding_wait"));
1537:                        addStep(wait);
1538:                    }
1539:                }
1540:                if (last instanceof  Terminate) {
1541:                    setStatus(Strings.get("editor.adding_terminate"));
1542:                    addStep(last);
1543:                }
1544:            }
1545:
1546:            /** Launch the GUI under test. */
1547:            private void launch(boolean terminateRecorder) {
1548:                if (testScript == null) {
1549:                    Log.warn("null testScript");
1550:                    return;
1551:                }
1552:
1553:                ignoreStepEvents = true;
1554:                invertAssertions = false;
1555:                waitAssertions = false;
1556:                view.setAssertOptions(waitAssertions, invertAssertions);
1557:
1558:                // Clean up any extant windows
1559:                if (terminateRecorder && recorder != null) {
1560:                    // Assume we want to keep the results
1561:                    stopRecording(false);
1562:                }
1563:
1564:                setStatus(Strings.get("Launching"));
1565:                // FIXME time out and flag an error if the launch never returns
1566:                // (even if threaded, it should return at some point)
1567:                runSteps(testScript, true, Strings.get("LaunchingDone"),
1568:                        new Runnable() {
1569:                            public void run() {
1570:                                ignoreStepEvents = false;
1571:                            }
1572:                        });
1573:            }
1574:
1575:            /** Do everything we can to dispose of the application under test. */
1576:            private void terminate() {
1577:                if (recorder != null) {
1578:                    // Assume we want to keep the results
1579:                    stopRecording(false);
1580:                }
1581:                scriptTable.clearSelection();
1582:                try {
1583:                    runner.terminate();
1584:                } catch (Throwable e) {
1585:                    Log.warn(e);
1586:                }
1587:            }
1588:
1589:            private void openScript() {
1590:                if (!checkSaveBeforeClose())
1591:                    return;
1592:                JFileChooser chooser = getChooser(filter);
1593:                chooser.setCurrentDirectory(getWorkingDirectory());
1594:                if (testScript != null) {
1595:                    chooser.setSelectedFile(testScript.getFile());
1596:                }
1597:                if (chooser.showOpenDialog(view) == JFileChooser.APPROVE_OPTION) {
1598:                    File file = chooser.getSelectedFile();
1599:                    setScript(file.getAbsolutePath());
1600:                }
1601:                if (!getScripts().contains(testScript) && model != null) {
1602:                    model.setSelectedItem(null);
1603:                }
1604:            }
1605:
1606:            private void stopOnFailureToggle() {
1607:                if (testScript != null) {
1608:                    runner.setStopOnFailure(!runner.getStopOnFailure());
1609:                }
1610:            }
1611:
1612:            private void stopOnErrorToggle() {
1613:                if (testScript != null) {
1614:                    runner.setStopOnError(!runner.getStopOnError());
1615:                }
1616:            }
1617:
1618:            private void forkedToggle() {
1619:                if (testScript != null) {
1620:                    testScript.setForked(!testScript.isForked());
1621:                }
1622:                setActionsEnabledState();
1623:            }
1624:
1625:            private void getVMArgs() {
1626:                String args = view.showInputDialog(Strings
1627:                        .get("GetVMArgs.title"), Strings.get("GetVMArgs.msg"),
1628:                        testScript.getVMArgs());
1629:                if (args != null) {
1630:                    testScript.setVMArgs(args);
1631:                }
1632:            }
1633:
1634:            private void slowPlaybackToggle() {
1635:                if (testScript != null) {
1636:                    testScript.setSlowPlayback(!testScript.isSlowPlayback());
1637:                }
1638:            }
1639:
1640:            private void awtModeToggle() {
1641:                if (testScript != null) {
1642:                    testScript.setAWTMode(!testScript.isAWTMode());
1643:                }
1644:            }
1645:
1646:            private void runScript(Step stopAt) {
1647:                if (testScript == null) {
1648:                    Log.warn("null testScript");
1649:                    return;
1650:                }
1651:                Log.debug("Running test case " + testScript);
1652:
1653:                stopStep = stopAt;
1654:                setStatus(Strings.get("actions.run.start"));
1655:                Runnable completion = new Runnable() {
1656:                    public void run() {
1657:                        // When the script finishes, bring the main
1658:                        // app forward.
1659:                        view.toFront();
1660:                    }
1661:                };
1662:                runSteps(testScript, false, Strings.get("actions.run.finish"),
1663:                        completion);
1664:            }
1665:
1666:            private void exportHierarchy() {
1667:                JFileChooser chooser = getChooser(null);
1668:                if (chooser.showSaveDialog(view) == JFileChooser.APPROVE_OPTION) {
1669:                    setStatus(Strings.get("actions.export-hierarchy.start"));
1670:                    final File file = chooser.getSelectedFile();
1671:                    new Thread("Hierarchy Export") {
1672:                        public void run() {
1673:                            HierarchyWriter hw = new HierarchyWriter(hierarchy);
1674:                            try {
1675:                                FileWriter writer = new FileWriter(file);
1676:                                hw.writeHierarchy(writer);
1677:                            } catch (IOException io) {
1678:                                view.showError(Strings.get("SaveFailed.title"),
1679:                                        io.toString());
1680:                            }
1681:                            setStatus(Strings
1682:                                    .get("actions.export-hierarchy.finish"));
1683:                        }
1684:                    }.start();
1685:                }
1686:            }
1687:
1688:            private void runSelectedSteps() {
1689:                final List stepList = scriptTable.getSelectedSteps();
1690:                if (testScript == null || stepList == null
1691:                        || stepList.size() == 0 || !isAppLaunched()) {
1692:                    Log.warn("inconsistent program state");
1693:                    return;
1694:                }
1695:
1696:                Sequence steps = new Sequence(getResolverContext(), null,
1697:                        stepList);
1698:                final int row0 = scriptModel.getRowOf((Step) stepList.get(0));
1699:                final int row1 = scriptModel.getRowOf((Step) stepList.get(steps
1700:                        .size() - 1));
1701:                setStatus(Strings.get("actions.run-selected.start"));
1702:                hideView();
1703:                runSteps(steps, false, Strings
1704:                        .get("actions.run-selected.finish"), new Runnable() {
1705:                    public void run() {
1706:                        scriptTable.setRowSelectionInterval(row0, row1);
1707:                        view.setVisible(true);
1708:                    }
1709:                });
1710:            }
1711:
1712:            /** Invoke the given test script.  All test execution is done on a dedicated
1713:             * thread/thread group to avoid interfering with the event dispatch thread.
1714:             */
1715:            private void runSteps(final Step which, final boolean launch,
1716:                    final String completionMessage, final Runnable onCompletion) {
1717:                Log.debug("running " + which);
1718:                setActionsEnabledState();
1719:                lastLaunchTime = System.currentTimeMillis();
1720:                //waiter = new SpinningDialWaitIndicator(view);
1721:                //waiter.setText("Running...");
1722:                Runnable action = new LaunchAction(which, onCompletion,
1723:                        completionMessage, launch);
1724:                String groupName = "AUT Thread Group for " + this  + ":"
1725:                        + nonce++;
1726:                if (appGroup == null) {
1727:                    appGroup = new ThreadGroup(groupName) {
1728:                        public void uncaughtException(Thread t, Throwable thrown) {
1729:                            if (!(thrown instanceof  ExitException)
1730:                                    && !(thrown instanceof  ThreadDeath)) {
1731:                                Log
1732:                                        .warn("Application thread exception not caught: "
1733:                                                + t);
1734:                                Log.warn(thrown);
1735:                            }
1736:                        }
1737:                    };
1738:                }
1739:                Thread launcher = new Thread(appGroup, action, "Script runner:"
1740:                        + nonce);
1741:                launcher.setDaemon(true);
1742:                view.getComponentBrowser().setEnabled(false);
1743:                view.setEditor(null);
1744:                isScriptRunning = true;
1745:                launcher.start();
1746:            }
1747:
1748:            /** Remove all contents from the current script. */
1749:            private void clearScript() {
1750:                if (testScript == null) {
1751:                    Log.warn("null testScript");
1752:                    return;
1753:                }
1754:                if (view.showConfirmation(Strings
1755:                        .get("editor.confirm.clear_script")) == JOptionPane.YES_OPTION) {
1756:                    scriptTable.clearSelection();
1757:                    scriptTable.setCursorLocation(0);
1758:                    testScript.clear();
1759:                    scriptModel.setScript(testScript);
1760:                }
1761:            }
1762:
1763:            /** Delete the currently selected script/test case. */
1764:            private void deleteScript() {
1765:                if (testScript == null) {
1766:                    Log.warn("null testScript");
1767:                    return;
1768:                }
1769:                if (view.showConfirmation(Strings
1770:                        .get("editor.confirm.delete_script")) == JOptionPane.YES_OPTION) {
1771:                    File file = testScript.getFile();
1772:                    int index = view.getTestScriptSelector().getSelectedIndex();
1773:                    file.delete();
1774:                    setTestSuite(testClass.getName(), testClass
1775:                            .getClassLoader());
1776:                    setScript(index);
1777:                }
1778:            }
1779:
1780:            /** Change the file backing the current script/test case, renaming
1781:             * its file if <code>rename</code> is true, or saving to a new destination
1782:             * if not. 
1783:             */
1784:            private void saveAsScript(boolean rename) {
1785:                if (testScript == null) {
1786:                    Log.warn("null testScript");
1787:                    return;
1788:                }
1789:                File oldFile = testScript.getFile();
1790:                JFileChooser chooser = getChooser(filter);
1791:                chooser.setCurrentDirectory(getWorkingDirectory());
1792:                // FIXME make sure it falls within the test suite's script set?
1793:                //chooser.setFileFilter(testScript.getFileFilter());
1794:                Log.debug("Showing save dialog");
1795:                if (chooser.showSaveDialog(view) == JFileChooser.APPROVE_OPTION) {
1796:                    Log.debug("Accepted");
1797:                    File newFile = chooser.getSelectedFile();
1798:                    if (rename) {
1799:                        if (!oldFile.renameTo(newFile)) {
1800:                            view.showError(Strings.get(
1801:                                    "editor.save.rename_failed", new Object[] {
1802:                                            oldFile, newFile }));
1803:                            return;
1804:                        }
1805:                    }
1806:                    testScript.setFile(newFile);
1807:                    saveScript();
1808:                    updateTitle();
1809:
1810:                    if (testSuite != null && testSuite.accept(newFile)) {
1811:                        setTestSuite(testClass.getName(), testSuite.getClass()
1812:                                .getClassLoader());
1813:                    } else {
1814:                        setTestSuite(null);
1815:                    }
1816:
1817:                    if (rename) {
1818:                        setStatus(Strings.get("ScriptRename",
1819:                                new Object[] { newFile.getName() }));
1820:                    } else {
1821:                        setStatus(Strings.get("ScriptSaved",
1822:                                new Object[] { newFile.getName() }));
1823:                    }
1824:                    // Combo box doesn't know that the script has changed its
1825:                    // toString 
1826:                    view.getTestScriptSelector().repaint();
1827:
1828:                    // Default script description reflects the path
1829:                    String text = testScript != null ? testScript
1830:                            .getDescription() : "";
1831:                    view.getTestScriptDescription().setText(text);
1832:                }
1833:            }
1834:
1835:            private boolean editingTempFile() {
1836:                return testScript != null
1837:                        && testScript.getFile().equals(tempFile);
1838:            }
1839:
1840:            /** Save the current script/test case state to disk. */
1841:            private void saveScript() {
1842:                if (testScript == null) {
1843:                    Log.warn("null testScript");
1844:                    return;
1845:                }
1846:                // If the file is a temporary file, prompt for its real location
1847:                if (editingTempFile()) {
1848:                    // This will recurse back into saveScript, so we're done
1849:                    Log
1850:                            .debug("Directory is temporary directory, need to rename");
1851:                    saveAsScript(false);
1852:                    return;
1853:                }
1854:                File file = testScript.getFile();
1855:                File parent = file.getParentFile();
1856:
1857:                // Try to ensure that the file and parent are writable, these operations
1858:                // might fail so we still might get a failure later on.
1859:                //
1860:
1861:                FileSystemHelper fileSystemHelper = editorConfiguration
1862:                        .getFileSystemHelper();
1863:
1864:                //
1865:
1866:                boolean canWrite = (!file.exists() && fileSystemHelper
1867:                        .makeWritable(parent))
1868:                        || (file.exists() && fileSystemHelper
1869:                                .makeWritable(file));
1870:                if (!canWrite) {
1871:                    String msg = Strings.get("NoFilePermission",
1872:                            new Object[] { file.toString() });
1873:                    view.showError(Strings.get("SaveFailed.title"), msg);
1874:                } else {
1875:                    try {
1876:                        setStatus(Strings.get("Saving", new Object[] { file }));
1877:                        saveNestedScripts(testScript);
1878:                        setStatus(Strings.get("Saved", new Object[] { file }));
1879:                    } catch (IOException exc) {
1880:                        view.showError(Strings.get("SaveFailed.title"), exc
1881:                                .toString());
1882:                    }
1883:                }
1884:            }
1885:
1886:            void saveNestedScripts(Sequence seq) throws IOException {
1887:                if (seq instanceof  Script) {
1888:                    Script script = (Script) seq;
1889:                    File file = script.getFile();
1890:
1891:                    // Make sure that the file can be written to
1892:                    //
1893:
1894:                    if (!editorConfiguration.getFileSystemHelper()
1895:                            .makeWritable(file)) {
1896:                        throw new IOException(Strings.get("NoFilePermission",
1897:                                new Object[] { file.toString() }));
1898:
1899:                    }
1900:
1901:                    // Save the script
1902:                    script.save();
1903:                }
1904:
1905:                Iterator iter = seq.steps().iterator();
1906:                while (iter.hasNext()) {
1907:                    Step step = (Step) iter.next();
1908:                    if (step instanceof  Sequence) {
1909:                        saveNestedScripts((Sequence) step);
1910:                    }
1911:                }
1912:            }
1913:
1914:            private EventNormalizer normalizer = new EventNormalizer();
1915:
1916:            /** Start listening to GUI events. */
1917:            private void startListening() {
1918:                normalizer.startListening(new SingleThreadedEventListener() {
1919:                    protected void processEvent(AWTEvent event) {
1920:                        ScriptEditor.this .processEvent(event);
1921:                    }
1922:                }, FIXTURE_EVENT_MASK);
1923:                view.getComponentBrowser().setEnabled(true);
1924:            }
1925:
1926:            /** Return the number of windows that are showing. */
1927:            private int countShowingWindows(Window root) {
1928:                int count = root != null && root.isShowing() ? 1 : 0;
1929:                Iterator iter = root == null ? hierarchy.getRoots().iterator()
1930:                        : hierarchy.getComponents(root).iterator();
1931:                while (iter.hasNext()) {
1932:                    Component c = (Component) iter.next();
1933:                    if (c instanceof  Window) {
1934:                        count += countShowingWindows((Window) c);
1935:                    }
1936:                }
1937:                return count;
1938:            }
1939:
1940:            private int DONT_CARE = -1;
1941:
1942:            private boolean isKeyPress(AWTEvent event, int code, int modifiers) {
1943:                return event.getID() == KeyEvent.KEY_PRESSED
1944:                        && ((KeyEvent) event).getKeyCode() == code
1945:                        && (((KeyEvent) event).getModifiers() == modifiers || modifiers == DONT_CARE);
1946:            }
1947:
1948:            private boolean isKeyRelease(AWTEvent event, int code, int modifiers) {
1949:                return event.getID() == KeyEvent.KEY_RELEASED
1950:                        && ((KeyEvent) event).getKeyCode() == code
1951:                        && (((KeyEvent) event).getModifiers() == modifiers || modifiers == DONT_CARE);
1952:            }
1953:
1954:            /** The editor does many things with the event stream, including logging
1955:             * events, passing them off to the recorder, and updating its internal
1956:             * state.
1957:             */
1958:            private void processEvent(AWTEvent event) {
1959:                Object src = event.getSource();
1960:                boolean isComponent = src instanceof  Component;
1961:                boolean isFiltered = isComponent
1962:                        && hierarchy.isFiltered((Component) src);
1963:                // Keep a log of all events we see on non-filtered components
1964:                if (isRootEditor) {
1965:                    if ((LOG_ALL_EVENTS || (!isFiltered && !ignoreEvents))
1966:                            && Boolean.getBoolean("abbot.fixture.log_events")) {
1967:                        Log.log("ED: " + Robot.toString(event) + " ("
1968:                                + Thread.currentThread() + ")");
1969:                    }
1970:                }
1971:                // Allow only component events and AWT menu actions
1972:                if (!isComponent && !(src instanceof  MenuComponent)) {
1973:                    Log.warn("Source not a Component or MenuComponent: "
1974:                            + event);
1975:                    return;
1976:                }
1977:                // If the script is running (or even being launched), the code
1978:                // under test may do things that should really be done on the event
1979:                // dispatch thread (initial component show and such).  
1980:                // If this is the case, defer mucking about with AWT until the code
1981:                // under test has stabilized.
1982:                if (isScriptRunning) {
1983:                    return;
1984:                }
1985:
1986:                if (!handleEditorTransient(event)
1987:                        && !handleRecordingControl(event)
1988:                        && !handleImageCaptureControl(event)
1989:                        && !handleComponentSelection(event) && recorder != null
1990:                        && recording && !isFiltered) {
1991:                    Log.debug("recorder process event");
1992:                    try {
1993:                        recorder.record(event);
1994:                    } catch (RecordingFailedException e) {
1995:                        // Stop recording, but keep what we've got so far
1996:                        stopRecording(false);
1997:                        String msg = Strings.get("editor.recording.failure");
1998:                        Throwable error = e.getReason() instanceof  BugReport ? e
1999:                                .getReason()
2000:                                : new BugReport(msg, e.getReason());
2001:                        Log.log("Recording failure: " + error.toString());
2002:                        setStatus(error.getMessage(), error.toString(), ERROR);
2003:                        view.showWarning(msg);
2004:                    }
2005:                }
2006:
2007:                updateComponents(event);
2008:            }
2009:
2010:            private boolean handleComponentSelection(AWTEvent event) {
2011:                Component ultimateComponent = state.getUltimateMouseComponent();
2012:                if (ultimateComponent != null
2013:                        && !hierarchy.isFiltered(ultimateComponent)) {
2014:                    boolean keySelect = isKeyPress(event, selectKey,
2015:                            KeyEvent.SHIFT_MASK);
2016:                    boolean mouseSelect = event.getID() == MouseEvent.MOUSE_PRESSED
2017:                            && AWT.isTertiaryButton(((MouseEvent) event)
2018:                                    .getModifiers());
2019:                    boolean makeReference = isKeyPress(event, selectKey,
2020:                            KeyEvent.SHIFT_MASK | KeyEvent.ALT_MASK);
2021:
2022:                    if (keySelect || mouseSelect || makeReference) {
2023:                        Component selected = event instanceof  MouseEvent ? InputState
2024:                                .getComponentAt((Component) event.getSource(),
2025:                                        ((MouseEvent) event).getPoint())
2026:                                : ultimateComponent;
2027:                        selectComponent(selected, makeReference);
2028:                        return true;
2029:                    }
2030:                }
2031:                return false;
2032:            }
2033:
2034:            /** Update the state of components whose appearance depends on keyboard 
2035:             * state.
2036:             * @param event
2037:             */
2038:            private void updateComponents(AWTEvent event) {
2039:                // Adjust the state of the assert/sample options
2040:                if (isKeyPress(event, KC_INVERT, DONT_CARE)) {
2041:                    invertAssertions = true;
2042:                    view.setAssertOptions(waitAssertions, invertAssertions);
2043:                } else if (isKeyRelease(event, KC_INVERT, DONT_CARE)) {
2044:                    invertAssertions = false;
2045:                    view.setAssertOptions(waitAssertions, invertAssertions);
2046:                } else if (isKeyPress(event, KC_WAIT, DONT_CARE)) {
2047:                    waitAssertions = true;
2048:                    view.setAssertOptions(waitAssertions, invertAssertions);
2049:                } else if (isKeyRelease(event, KC_WAIT, DONT_CARE)) {
2050:                    waitAssertions = false;
2051:                    view.setAssertOptions(waitAssertions, invertAssertions);
2052:                }
2053:            }
2054:
2055:            private boolean handleEditorTransient(AWTEvent event) {
2056:                // Make sure we filter any transient windows generated by the
2057:                // script editor's frame.  This avoids some of the hierarchy event
2058:                // NPEs present on pre-1.4 VMs.
2059:                if (event.getID() == WindowEvent.WINDOW_OPENED
2060:                        && ((WindowEvent) event).getWindow().getParent() == view) {
2061:                    hierarchy.setFiltered(((WindowEvent) event).getWindow(),
2062:                            true);
2063:                    view.getComponentBrowser().refresh();
2064:                    return true;
2065:                }
2066:                return false;
2067:            }
2068:
2069:            private boolean handleImageCaptureControl(AWTEvent event) {
2070:                Object src = event.getSource();
2071:                boolean isComponent = event.getSource() instanceof  Component;
2072:                boolean isFiltered = isComponent
2073:                        && hierarchy.isFiltered((Component) event.getSource());
2074:                Component ultimateComponent = state.getUltimateMouseComponent();
2075:                if (capturingImage) {
2076:                    // Cancel an image capture on ESC
2077:                    if (isKeyRelease(event, KeyEvent.VK_ESCAPE, 0)) {
2078:                        imageCaptureCancel();
2079:                    } else if (captureComponent != null
2080:                            && isKeyPress(event, KeyEvent.VK_UP, 0)
2081:                            && !(src instanceof  Window)) {
2082:                        imageCaptureSelect(true);
2083:                    } else if (captureComponent != null
2084:                            && isKeyPress(event, KeyEvent.VK_DOWN, 0)
2085:                            && !(src instanceof  Window)) {
2086:                        imageCaptureSelect(false);
2087:                    } else if (isKeyRelease(event, captureImageKey,
2088:                            KeyEvent.SHIFT_MASK)
2089:                            && !isFiltered
2090:                            && testScript != null
2091:                            && ultimateComponent != null) {
2092:                        imageCapture();
2093:                    }
2094:                    return true;
2095:                } else if (isKeyRelease(event, captureImageKey,
2096:                        KeyEvent.SHIFT_MASK)
2097:                        && !isFiltered
2098:                        && testScript != null
2099:                        && ultimateComponent != null) {
2100:                    imageCaptureStart(ultimateComponent);
2101:                    return true;
2102:                }
2103:                return false;
2104:            }
2105:
2106:            private boolean handleRecordingControl(AWTEvent e) {
2107:                boolean editorActivated = e.getID() == WindowEvent.WINDOW_ACTIVATED
2108:                        && e.getSource() == view;
2109:                boolean appGone = isAppLaunched()
2110:                        && countShowingWindows(null) == 0
2111:                        && (appGroup != null && appGroup.activeCount() == 0)
2112:                        && System.currentTimeMillis() - lastLaunchTime > 7500;
2113:                if (appGone)
2114:                    Log.debug("Code under test no longer running");
2115:                boolean isComponent = e.getSource() instanceof  Component;
2116:                boolean isFiltered = isComponent
2117:                        && hierarchy.isFiltered((Component) e.getSource());
2118:
2119:                if (isKeyPress(e, captureKey, KeyEvent.SHIFT_MASK)
2120:                        || editorActivated || appGone) {
2121:                    Log.debug("stop recording trigger");
2122:                    if (recording) {
2123:                        stopRecording(false);
2124:                        justStoppedRecording = true;
2125:                        if (capturingImage)
2126:                            imageCaptureCancel();
2127:                    } else {
2128:                        justStoppedRecording = false;
2129:                    }
2130:                    return true;
2131:                }
2132:                // Start recording all events on alt+shift+F2
2133:                else if (isKeyRelease(e, captureKey, KeyEvent.SHIFT_MASK
2134:                        | KeyEvent.ALT_MASK)) {
2135:                    Log.debug("start recording trigger");
2136:                    if (!isFiltered && !recording && !justStoppedRecording) {
2137:                        Log.debug("Start recording events (+motion)");
2138:                        startRecording(recorders[1]);
2139:                        return true;
2140:                    }
2141:                }
2142:                // Start recording on shift+F2
2143:                else if (isKeyRelease(e, captureKey, KeyEvent.SHIFT_MASK)) {
2144:                    Log.debug("start recording trigger");
2145:                    if (!isFiltered && !recording && !justStoppedRecording) {
2146:                        Log.debug("Start recording events");
2147:                        startRecording(recorders[0]);
2148:                        return true;
2149:                    }
2150:                }
2151:                return false;
2152:            }
2153:
2154:            private void selectComponent(Component c, boolean makeReference) {
2155:                Log.debug("Selected: " + Robot.toString(c));
2156:                // We usually want the combo box itself, not its LAF button
2157:                if (c != null && (c.getParent() instanceof  JComboBox))
2158:                    c = c.getParent();
2159:                if (makeReference && getResolverContext() != null) {
2160:                    getResolverContext().addComponent(c);
2161:                    // FIXME tell the reference browser that the list of references
2162:                    // has changed. 
2163:                }
2164:                view.getComponentBrowser().setSelectedComponent(c);
2165:            }
2166:
2167:            private void imageCaptureStart(Component ultimateComponent) {
2168:                Log.debug("image capture locate");
2169:                recording = false;
2170:                capturingImage = true;
2171:                captureComponent = ultimateComponent;
2172:                innermostCaptureComponent = captureComponent;
2173:                if (captureComponent instanceof  JComponent) {
2174:                    highlighter = new Highlighter((JComponent) captureComponent);
2175:                }
2176:                setStatus("Image capture target is "
2177:                        + Robot.toString(captureComponent));
2178:            }
2179:
2180:            private void imageCaptureCancel() {
2181:                Log.debug("stop image capture command");
2182:                highlighter.dispose();
2183:                setStatus("Image capture canceled");
2184:                captureComponent = innermostCaptureComponent = null;
2185:                capturingImage = false;
2186:            }
2187:
2188:            private void imageCaptureSelect(boolean up) {
2189:                if (up) {
2190:                    Log.debug("image capture move up");
2191:                    Component parent = captureComponent.getParent();
2192:                    if (parent instanceof  JComponent
2193:                            && !(captureComponent instanceof  JLayeredPane)) {
2194:                        Log.debug("Changing from "
2195:                                + Robot.toString(captureComponent) + " to "
2196:                                + Robot.toString(parent));
2197:                        highlighter.dispose();
2198:                        highlighter = new Highlighter((JComponent) parent);
2199:                        captureComponent = parent;
2200:                    }
2201:                } else {
2202:                    Log.debug("image capture move down");
2203:                    if (captureComponent instanceof  Container) {
2204:                        Component[] subs = ((Container) captureComponent)
2205:                                .getComponents();
2206:                        for (int i = 0; i < subs.length; i++) {
2207:                            if (SwingUtilities.isDescendingFrom(
2208:                                    innermostCaptureComponent, subs[i])
2209:                                    && subs[i] instanceof  JComponent) {
2210:                                Log.debug("Changing from "
2211:                                        + Robot.toString(captureComponent)
2212:                                        + " to " + Robot.toString(subs[i]));
2213:                                highlighter.dispose();
2214:                                highlighter = new Highlighter(
2215:                                        (JComponent) subs[i]);
2216:                                captureComponent = subs[i];
2217:                                break;
2218:                            }
2219:                        }
2220:                    }
2221:                }
2222:                setStatus("Image capture target is "
2223:                        + Robot.toString(captureComponent));
2224:            }
2225:
2226:            private void imageCapture() {
2227:                Log.debug("image capture snapshot");
2228:                setStatus("Capturing image...");
2229:                view.repaint();
2230:                highlighter.dispose();
2231:                // Must wait for the highlight to go away
2232:                new Thread("wait for repaint") {
2233:                    public void run() {
2234:                        while (Toolkit.getDefaultToolkit()
2235:                                .getSystemEventQueue().peekEvent() != null) {
2236:                            try {
2237:                                sleep(10);
2238:                            } catch (InterruptedException e) {
2239:                            }
2240:                        }
2241:                        SwingUtilities.invokeLater(new Runnable() {
2242:                            public void run() {
2243:                                Step step = captureComponentImage(captureComponent);
2244:                                if (step != null) {
2245:                                    // If we capture while recording, add it to the
2246:                                    // recorder's stream.  Otherwise, add it directly.
2247:                                    if (recorder != null) {
2248:                                        recorder.insertStep(step);
2249:                                    } else {
2250:                                        addStep(step);
2251:                                    }
2252:                                }
2253:                                setStatus("Capturing image...done");
2254:                                captureComponent = innermostCaptureComponent = null;
2255:                                capturingImage = false;
2256:                            }
2257:                        });
2258:                    }
2259:                }.start();
2260:            }
2261:
2262:            /** Return a List of script filenames in the current suite. */
2263:            private List getScripts() {
2264:                if (testScriptList == null) {
2265:                    testScriptList = getScripts(testSuite);
2266:                }
2267:                return testScriptList;
2268:            }
2269:
2270:            /** Return a List of script filenames contained in the given Test. */
2271:            private List getScripts(junit.framework.Test node) {
2272:                ArrayList names = new ArrayList();
2273:                if (node == null) {
2274:                } else if (node instanceof  ScriptFixture) {
2275:                    names.add(((ScriptFixture) node).getName());
2276:                } else if (node instanceof  junit.framework.TestSuite) {
2277:                    Enumeration e = ((junit.framework.TestSuite) node).tests();
2278:                    while (e.hasMoreElements()) {
2279:                        junit.framework.Test test = (junit.framework.Test) e
2280:                                .nextElement();
2281:                        names.addAll(getScripts(test));
2282:                    }
2283:                } else if (node instanceof  junit.extensions.TestDecorator) {
2284:                    junit.framework.Test base = ((junit.extensions.TestDecorator) node)
2285:                            .getTest();
2286:                    names.addAll(getScripts(base));
2287:                }
2288:                //Log.debug("Test scripts under " + node + ": " + names.size());
2289:                return names;
2290:            }
2291:
2292:            /** Returns the test case at the given index.  */
2293:            private Script getScriptAt(int index) {
2294:                List filenames = getScripts();
2295:                if (index >= filenames.size())
2296:                    index = filenames.size() - 1;
2297:                return new Script((String) filenames.get(index), hierarchy);
2298:            }
2299:
2300:            /** Create a new step and insert it at the cursor. */
2301:            private void insertTesterCall(ComponentTester tester,
2302:                    Method method, Class componentClass, String id,
2303:                    String[] argList, boolean wait, boolean invert)
2304:                    throws NoSuchReferenceException {
2305:                String expectedResult = "true";
2306:                String methodName = method.getName();
2307:
2308:                if (methodName.startsWith("assert")) {
2309:                    Assert step;
2310:                    if (id == null) {
2311:                        // Built-in ComponentTester assertion
2312:                        step = new Assert(getResolverContext(), null, method
2313:                                .getDeclaringClass().getName(), methodName,
2314:                                argList, expectedResult, invert);
2315:                    } else {
2316:                        // Property method on a component
2317:                        ComponentReference ref = getComponentReference(id);
2318:                        if (ref == null)
2319:                            throw new NoSuchReferenceException(id);
2320:                        step = new Assert(getResolverContext(), null,
2321:                                methodName, argList,
2322:                                method.getDeclaringClass(), expectedResult,
2323:                                invert);
2324:                    }
2325:                    step.setWait(wait);
2326:                    addStep(step);
2327:                } else if (methodName.startsWith("action")) {
2328:                    if (id == null) {
2329:                        // non-component action
2330:                        addStep(new Action(getResolverContext(), null,
2331:                                methodName, argList));
2332:                    } else {
2333:                        ComponentReference ref = getComponentReference(id);
2334:                        if (ref == null)
2335:                            throw new NoSuchReferenceException(id);
2336:                        addStep(new Action(getResolverContext(), null,
2337:                                methodName, argList, method.getDeclaringClass()));
2338:                    }
2339:                } else {
2340:                    // It's an tester-provided property method
2341:                    ComponentReference ref = getComponentReference(id);
2342:                    if (ref == null)
2343:                        throw new NoSuchReferenceException(id);
2344:                    addStep(new Assert(getResolverContext(), null, methodName,
2345:                            argList, tester.getTestedClass(componentClass),
2346:                            expectedResult, invert));
2347:                }
2348:            }
2349:
2350:            /** Update the UI to reflect the current state of the script's
2351:             * execution.
2352:             */
2353:            private void reflectScriptExecutionState(StepEvent ev) {
2354:                Step step = ev.getStep();
2355:                String cmd = ev.getType();
2356:                Log.debug("Got step event " + ev);
2357:                if (cmd.equals(StepEvent.STEP_START)) {
2358:                    if (step == stopStep) {
2359:                        runner.stop();
2360:                        stopStep = null;
2361:                    }
2362:                    if (step != testScript) {
2363:                        final int row = scriptModel.getRowOf(step);
2364:                        if (row == -1) {
2365:                            // Step not visible, ignore
2366:                        } else {
2367:                            SwingUtilities.invokeLater(new Runnable() {
2368:                                public void run() {
2369:                                    scriptTable.setRowSelectionInterval(row,
2370:                                            row);
2371:                                    scriptTable.setCursorLocation(row + 1);
2372:                                    Rectangle rect = scriptTable.getCellRect(
2373:                                            row, 0, true);
2374:                                    scriptTable.scrollRectToVisible(rect);
2375:                                }
2376:                            });
2377:                        }
2378:                        int i = testScript.indexOf(step);
2379:                        if (i != -1) {
2380:                            setStatus(Strings.get("RunningStep", new Object[] {
2381:                                    String.valueOf(i + 1),
2382:                                    String.valueOf(testScript.size()) }));
2383:                        }
2384:                    }
2385:                } else if (cmd.equals(StepEvent.STEP_FAILURE)
2386:                        || cmd.equals(StepEvent.STEP_ERROR)) {
2387:                    // Make sure the table updates its colors
2388:                    int index = scriptModel.getRowOf(step);
2389:                    if (index != -1) {
2390:                        scriptModel.fireTableRowsUpdated(index, index);
2391:                    }
2392:                    setStatusForStep(step);
2393:                }
2394:            }
2395:
2396:            Resolver getResolverContext() {
2397:                return scriptTable.getScriptContext();
2398:            }
2399:
2400:            /** From abbot.Resolver. */
2401:            public ComponentReference getComponentReference(String refid) {
2402:                return getResolverContext() != null ? getResolverContext()
2403:                        .getComponentReference(refid) : null;
2404:            }
2405:
2406:            /** From abbot.Resolver. */
2407:            public ComponentReference getComponentReference(Component comp) {
2408:                return getResolverContext() != null ? getResolverContext()
2409:                        .getComponentReference(comp) : null;
2410:            }
2411:
2412:            /** From abbot.Resolver. */
2413:            public void addComponentReference(ComponentReference ref) {
2414:                if (getResolverContext() == null) {
2415:                    throw new RuntimeException(Strings.get("NoContext"));
2416:                }
2417:                getResolverContext().addComponentReference(ref);
2418:            }
2419:
2420:            /** From abbot.Resolver. */
2421:            public ComponentReference addComponent(Component comp) {
2422:                if (getResolverContext() == null) {
2423:                    throw new RuntimeException(Strings.get("NoContext"));
2424:                }
2425:                return getResolverContext().addComponent(comp);
2426:            }
2427:
2428:            /** From abbot.Resolver. */
2429:            public Collection getComponentReferences() {
2430:                if (getResolverContext() == null) {
2431:                    return new HashSet();
2432:                }
2433:                return getResolverContext().getComponentReferences();
2434:            }
2435:
2436:            /** From abbot.Resolver. */
2437:            public String getContext(Step step) {
2438:                Resolver r = getResolverContext();
2439:                if (r != null)
2440:                    return r.getContext(step);
2441:                return "unknown";
2442:            }
2443:
2444:            /** From abbot.Resolver. */
2445:            public File getDirectory() {
2446:                if (getResolverContext() == null) {
2447:                    return new File(System.getProperty("user.dir"));
2448:                }
2449:                return getResolverContext().getDirectory();
2450:            }
2451:
2452:            /** From abbot.Resolver. */
2453:            public void setProperty(String name, Object value) {
2454:                if (getResolverContext() != null) {
2455:                    getResolverContext().setProperty(name, value);
2456:                }
2457:            }
2458:
2459:            /** From abbot.Resolver. */
2460:            public Object getProperty(String name) {
2461:                if (getResolverContext() != null) {
2462:                    return getResolverContext().getProperty(name);
2463:                }
2464:                return null;
2465:            }
2466:
2467:            /** From abbot.Resolver. */
2468:            public ClassLoader getContextClassLoader() {
2469:                if (getResolverContext() != null) {
2470:                    return getResolverContext().getContextClassLoader();
2471:                }
2472:                return Thread.currentThread().getContextClassLoader();
2473:            }
2474:
2475:            public Hierarchy getHierarchy() {
2476:                return hierarchy;
2477:            }
2478:
2479:            public String toString() {
2480:                return name;
2481:            }
2482:
2483:            private void stepSelectionChanged() {
2484:                // ensure the stop step colorization gets cleared 
2485:                stopStep = null;
2486:                setStepEditor();
2487:                setActionsEnabledState();
2488:            }
2489:
2490:            // FIXME this is slow on OSX
2491:            private void setStepEditor(Step step) {
2492:                final StepEditor editor;
2493:                ignoreEvents = true;
2494:                if (step != null
2495:                        && (editor = StepEditor.getEditor(step)) != null) {
2496:                    view.setEditor(editor);
2497:                    // make sure the script model listens to changes from the
2498:                    // step editor 
2499:                    editor.addStepChangeListener(new StepChangeListener() {
2500:                        public void stepChanged(Step step) {
2501:                            int row = scriptModel.getRowOf(step);
2502:                            if (row != -1)
2503:                                scriptModel.fireTableRowsUpdated(row, row);
2504:                        }
2505:                    });
2506:                } else {
2507:                    Log.debug("No editor available for '" + step + "'");
2508:                    view.setEditor(null);
2509:                }
2510:                ignoreEvents = false;
2511:                // Update the component browser if the context changes
2512:                view.getComponentBrowser().setResolver(getResolverContext());
2513:            }
2514:
2515:            private static String usage() {
2516:                return ScriptEditor.class.getName() + " [suite classname]";
2517:            }
2518:
2519:            private class LaunchAction implements  Runnable {
2520:                private final Step which;
2521:                private final Runnable onCompletion;
2522:                private final String completionMessage;
2523:                private final boolean launch;
2524:
2525:                private LaunchAction(Step which, Runnable onCompletion,
2526:                        String completionMessage, boolean launch) {
2527:                    this .which = which;
2528:                    this .onCompletion = onCompletion;
2529:                    this .completionMessage = completionMessage;
2530:                    this .launch = launch;
2531:                }
2532:
2533:                public void run() {
2534:                    try {
2535:                        if (launch) {
2536:                            if (which instanceof  Script) {
2537:                                UIContext context = which instanceof  UIContext ? (UIContext) which
2538:                                        : ((Script) which).getUIContext();
2539:                                if (context != null)
2540:                                    context.launch(runner);
2541:                            }
2542:                        } else {
2543:                            runner.run(which);
2544:                        }
2545:                        if (completionMessage != null)
2546:                            setStatus(completionMessage);
2547:                    } catch (Throwable e) {
2548:                        // launch didn't work, get rid of it
2549:                        if (launch)
2550:                            terminate();
2551:                        setStatus(e.getMessage(), getStackTrace(e), ERROR);
2552:                    }
2553:                    SwingUtilities.invokeLater(new Runnable() {
2554:                        public void run() {
2555:                            if (waiter != null) {
2556:                                waiter.dispose();
2557:                                waiter = null;
2558:                            }
2559:                            isScriptRunning = false;
2560:                            setActionsEnabledState();
2561:                            if (onCompletion != null) {
2562:                                onCompletion.run();
2563:                            }
2564:                        }
2565:                    });
2566:                }
2567:            }
2568:
2569:            /**
2570:             * This class responds to changes in the script table's selection.
2571:             */
2572:            private class ScriptTableSelectionHandler implements 
2573:                    ListSelectionListener {
2574:                public void valueChanged(ListSelectionEvent ev) {
2575:                    if (ev.getValueIsAdjusting() || isScriptRunning)
2576:                        return;
2577:                    stepSelectionChanged();
2578:                }
2579:            }
2580:
2581:            private void setStepEditor() {
2582:                Step step = scriptTable.getSelectedRowCount() == 1 ? scriptModel
2583:                        .getStepAt(scriptTable.getSelectedRow())
2584:                        : null;
2585:                setStepEditor(step);
2586:                setStatusForStep(step);
2587:                setActionsEnabledState();
2588:            }
2589:
2590:            /**
2591:             * Handle the current test case/script selection from the current test
2592:             * suite (if any).
2593:             */
2594:            private class ScriptSelectorItemHandler implements  ItemListener {
2595:                public void itemStateChanged(ItemEvent e) {
2596:                    if (ItemEvent.SELECTED == e.getStateChange()
2597:                            && !ignoreComboBox) {
2598:                        if (checkSaveBeforeClose()) {
2599:                            setScript(new Script((String) e.getItem(),
2600:                                    hierarchy));
2601:                        } else {
2602:                            setScript(testScript);
2603:                        }
2604:                    }
2605:                }
2606:            }
2607:
2608:            /** Provide a global editor context for anyone else that wants to display
2609:             * an appropriate dialog message.
2610:             */
2611:            // FIXME move to ScriptEditorFrame
2612:            private static ScriptEditor editor = null;
2613:
2614:            /** This action shows an input dialog to collect arguments for a given
2615:             * method on a ComponentTester class and adds an assertion or action to
2616:             * the current script. 
2617:             */
2618:            private class TesterMethodAction extends EditorAction implements 
2619:                    Comparable {
2620:                private Method method;
2621:                private ComponentTester tester;
2622:                private boolean wait;
2623:
2624:                public TesterMethodAction(ComponentTester t, Method m, boolean w) {
2625:                    super (m.getName());
2626:                    putValue(NAME, getName(m));
2627:                    putValue(SMALL_ICON, getIcon(m));
2628:                    wait = w;
2629:                    tester = t;
2630:                    method = m;
2631:                }
2632:
2633:                public int compareTo(Object o) {
2634:                    if (o instanceof  TesterMethodAction) {
2635:                        return getName().compareTo(
2636:                                ((TesterMethodAction) o).getName());
2637:                    }
2638:                    return 0;
2639:                }
2640:
2641:                public void actionPerformed(ActionEvent ev) {
2642:                    addTesterCall(method, tester, wait,
2643:                            getArgumentsDescription());
2644:                }
2645:
2646:                /** Return the human-readable menu name for the action. */
2647:                private String getName(Method m) {
2648:                    String name = m.getName();
2649:                    // First try the resource bundle, then a system property
2650:                    String menu = Strings.get(name + ".menu", true);
2651:                    if (menu == null) {
2652:                        menu = System.getProperty(name + ".menu");
2653:                        // Default to the stripped-down method name
2654:                        if (menu == null) {
2655:                            if (name.startsWith("action")
2656:                                    || name.startsWith("assert"))
2657:                                menu = name.substring(6);
2658:                            else if (name.startsWith("is"))
2659:                                menu = name.substring(2);
2660:                            else if (name.startsWith("get"))
2661:                                menu = name.substring(3);
2662:                            else
2663:                                menu = name;
2664:                            // Break up words if we can
2665:                            menu = TextFormat.wordBreak(menu);
2666:                        }
2667:                    }
2668:                    return menu;
2669:                }
2670:
2671:                private Icon getIcon(Method m) {
2672:                    // This loads the icon if it's in a jar file.  Doesn't seem to work
2673:                    // when loading from a raw class file in the classpath.
2674:                    Icon icon = null;
2675:                    String path = Strings.get(m.getName() + ".icon", true);
2676:                    if (path == null) {
2677:                        path = System.getProperty(m.getName() + ".icon");
2678:                    }
2679:                    if (path != null) {
2680:                        URL url = ScriptEditor.class.getResource(path);
2681:                        if (url == null) {
2682:                            url = ScriptEditor.class.getResource("icons/"
2683:                                    + path + ".gif");
2684:                        }
2685:                        if (url != null) {
2686:                            icon = new ImageIcon(url);
2687:                        }
2688:                    }
2689:                    return icon;
2690:                }
2691:
2692:                /** Provide a description of required arguments for this method. */
2693:                private String getArgumentsDescription() {
2694:                    String name = method.getName();
2695:                    String cname = Robot.simpleClassName(method
2696:                            .getDeclaringClass());
2697:                    String args = Strings.get(cname + "." + name + ".args",
2698:                            true);
2699:                    if (args == null) {
2700:                        args = System.getProperty(cname + "." + name + ".args");
2701:                        if (args == null) {
2702:                            args = method.toString();
2703:                        }
2704:                    }
2705:                    return args;
2706:                }
2707:
2708:                public String getName() {
2709:                    return (String) getValue(NAME);
2710:                }
2711:
2712:                public int hashCode() {
2713:                    return getName().hashCode();
2714:                }
2715:
2716:                public boolean equals(Object o) {
2717:                    return o instanceof  TesterMethodAction
2718:                            && getName().equals(
2719:                                    ((TesterMethodAction) o).getName());
2720:                }
2721:            }
2722:
2723:            /** Security manager to prevent applications under test from exiting.
2724:             * StepRunner provides one of these, but we need to do additional 
2725:             * checking in the context of the script editor.
2726:             */
2727:            private class EditorSecurityManager extends NoExitSecurityManager {
2728:
2729:                public void checkRead(String file) {
2730:                    // avoid annoying drive A: bug on w32
2731:                }
2732:
2733:                /** We do additional checking to allow exit from the editor itself. */
2734:                public void checkExit(int status) {
2735:                    // Only allow exits by the root script editor
2736:                    if (!rootIsExiting) {
2737:                        super .checkExit(status);
2738:                    }
2739:                }
2740:
2741:                protected void exitCalled(int status) {
2742:                    terminate();
2743:                }
2744:            }
2745:
2746:            private void hideView() {
2747:                hiding = true;
2748:                view.setVisible(false);
2749:            }
2750:
2751:            private void disposeView() {
2752:                // Close this frame; flag to the view to allow it to be disposed
2753:                exiting = true;
2754:                view.dispose();
2755:            }
2756:
2757:            void dispose() {
2758:                // Close any application under test
2759:                terminate();
2760:                normalizer.stopListening();
2761:                hideView();
2762:                disposeView();
2763:
2764:                // Get rid of the security manager
2765:                if (securityManager != null) {
2766:                    System.setSecurityManager(oldSecurityManager);
2767:                    securityManager = null;
2768:                }
2769:            }
2770:
2771:            private static void bugCheck() {
2772:                Window w = Costello.getSplashScreen();
2773:                if (w != null) {
2774:                    // Test for bugs that the user should know about
2775:                    String[] bugs = Bugs.bugCheck(Costello.getSplashScreen());
2776:                    for (int i = 0; i < bugs.length; i++) {
2777:                        String title = Strings.get("BugWarning.title");
2778:                        String msg = TextFormat.dialog(bugs[i]);
2779:                        JOptionPane.showMessageDialog(w, msg, title,
2780:                                JOptionPane.WARNING_MESSAGE);
2781:                    }
2782:                }
2783:            }
2784:
2785:            /** Launch the script editor, with an argument of either a test suite
2786:             * class or a script filename.
2787:             */
2788:            public static void main(String[] args) {
2789:                showEditor(new EditorContext(args));
2790:            }
2791:
2792:            /** 
2793:             * Launch the script editor, with an argument that represents a variety 
2794:             * of editor customizations.
2795:             */
2796:            public static void showEditor(EditorContext ec) {
2797:                try {
2798:                    String args[] = Log.init(ec.getArguments());
2799:
2800:                    bugCheck();
2801:
2802:                    if (args.length > 1) {
2803:                        if (ec.isEmbedded()) {
2804:                            JOptionPane.showMessageDialog(null,
2805:                                    "Invalid arguments when invoking abbot");
2806:                            return;
2807:                        } else {
2808:                            System.err.println("usage: " + usage());
2809:                            System.exit(1);
2810:                        }
2811:
2812:                    }
2813:
2814:                    editor = new ScriptEditor(ec);
2815:
2816:                    // Load the requested script or suite
2817:                    String arg = args.length == 1 ? args[0] : null;
2818:                    if (arg != null && new File(arg).exists()
2819:                            && Script.isScript(new File(arg))) {
2820:                        editor.setTestSuite(null);
2821:                        editor.setScript(arg);
2822:                    } else {
2823:                        editor.setTestSuite(arg);
2824:                        editor.setScript(0);
2825:                    }
2826:
2827:                    // Make sure everything currently extant is
2828:                    // ignored in the test hierarchy.
2829:                    // Skip this step if the context provides a test hierarchy
2830:                    editor.hierarchy.ignoreExisting();
2831:
2832:                    editor.view.pack();
2833:                    editor.view.setVisible(true);
2834:                    // Don't start listening to events until we're done generating them
2835:                    // (the "show" above can trigger deadlocks when the framework is
2836:                    // under test).
2837:                    editor.startListening();
2838:                } catch (Throwable e) {
2839:                    if (editor != null)
2840:                        editor.dispose();
2841:                    System.err.println("Unexpected exception trying to launch "
2842:                            + "the script editor");
2843:                    e.printStackTrace();
2844:                    System.exit(1);
2845:                }
2846:            }
2847:
2848:            /**
2849:             * @return Returns whether the code under test is currently launched.
2850:             */
2851:            private boolean isAppLaunched() {
2852:
2853:                // Override for embeded cases
2854:                if (editorConfiguration.isEmbedded()) {
2855:                    return true;
2856:                }
2857:
2858:                if (testScript != null) {
2859:                    UIContext ctxt = testScript.getUIContext();
2860:                    if (ctxt != null)
2861:                        return ctxt.isLaunched();
2862:                }
2863:                return false;
2864:            }
2865:
2866:            private class RecordAllAction extends EditorAction {
2867:                private Recorder recorder;
2868:
2869:                public RecordAllAction(String actionName, Recorder rec,
2870:                        boolean extraModifier) {
2871:                    super (actionName);
2872:                    recorder = rec;
2873:                    int mask = InputEvent.SHIFT_MASK;
2874:                    if (extraModifier)
2875:                        mask |= InputEvent.ALT_MASK;
2876:                    putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(
2877:                            captureKey, mask));
2878:                }
2879:
2880:                public void actionPerformed(ActionEvent ev) {
2881:                    Log.debug("Menu action: start recording due to "
2882:                            + ev.getActionCommand());
2883:                    startRecording(recorder);
2884:                }
2885:            }
2886:
2887:            private class EditorAboutAction extends EditorAction {
2888:                public EditorAboutAction() {
2889:                    super (ACTION_EDITOR_ABOUT);
2890:                }
2891:
2892:                public void actionPerformed(ActionEvent e) {
2893:                    view.showAboutBox();
2894:                }
2895:            }
2896:
2897:            private class EditorEmailAction extends EditorAction {
2898:                public EditorEmailAction() {
2899:                    super (ACTION_EDITOR_EMAIL);
2900:                }
2901:
2902:                public void actionPerformed(ActionEvent e) {
2903:                    new Thread("mailing-list") {
2904:                        public void run() {
2905:                            try {
2906:                                Launcher.mail(Strings.get("editor.email.list"),
2907:                                        Strings.get("editor.email.subject"),
2908:                                        Strings.get("editor.email.body",
2909:                                                new Object[] { BugReport
2910:                                                        .getSystemInfo() }));
2911:                            } catch (IOException e) {
2912:                                view.showWarning(e.getMessage());
2913:                            }
2914:                        }
2915:                    }.start();
2916:                }
2917:            }
2918:
2919:            private class EditorBugReportAction extends EditorAction {
2920:                public EditorBugReportAction() {
2921:                    super (ACTION_EDITOR_BUGREPORT);
2922:                }
2923:
2924:                public void actionPerformed(ActionEvent e) {
2925:                    new Thread("bug-report") {
2926:                        public void run() {
2927:                            try {
2928:                                Launcher.open(Strings.get("editor.submit_bug"));
2929:                            } catch (IOException e) {
2930:                                view.showWarning(e.getMessage());
2931:                            }
2932:                        }
2933:                    }.start();
2934:                }
2935:            }
2936:
2937:            private class EditorWebsiteAction extends EditorAction {
2938:                public EditorWebsiteAction() {
2939:                    super (ACTION_EDITOR_WEBSITE);
2940:                }
2941:
2942:                public void actionPerformed(ActionEvent e) {
2943:                    new Thread("mailing-list") {
2944:                        public void run() {
2945:                            try {
2946:                                Launcher.open(Strings.get("editor.website"));
2947:                            } catch (IOException e) {
2948:                                view.showWarning(e.getMessage());
2949:                            }
2950:                        }
2951:                    }.start();
2952:                }
2953:            }
2954:
2955:            private class EditorUserGuideAction extends EditorAction {
2956:                public EditorUserGuideAction() {
2957:                    super (ACTION_EDITOR_USERGUIDE);
2958:                }
2959:
2960:                public void actionPerformed(ActionEvent e) {
2961:                    new Thread("mailing-list") {
2962:                        public void run() {
2963:                            try {
2964:                                Launcher.open(Strings.get("editor.userguide"));
2965:                            } catch (IOException e) {
2966:                                view.showWarning(e.getMessage());
2967:                            }
2968:                        }
2969:                    }.start();
2970:                }
2971:            }
2972:
2973:            private class EditorQuitAction extends EditorAction {
2974:                public EditorQuitAction() {
2975:                    super (ACTION_EDITOR_QUIT);
2976:                }
2977:
2978:                public void actionPerformed(ActionEvent e) {
2979:                    quitApplication();
2980:                }
2981:            }
2982:
2983:            private class ScriptNewAction extends EditorAction {
2984:                public ScriptNewAction() {
2985:                    super (ACTION_SCRIPT_NEW);
2986:                }
2987:
2988:                public void actionPerformed(ActionEvent e) {
2989:                    newScript(false);
2990:                }
2991:            }
2992:
2993:            private class ScriptDuplicateAction extends EditorAction {
2994:                public ScriptDuplicateAction() {
2995:                    super (ACTION_SCRIPT_DUPLICATE);
2996:                }
2997:
2998:                public void actionPerformed(ActionEvent e) {
2999:                    newScript(true);
3000:                }
3001:            }
3002:
3003:            private class ScriptOpenAction extends EditorAction {
3004:                public ScriptOpenAction() {
3005:                    super (ACTION_SCRIPT_OPEN);
3006:                }
3007:
3008:                public void actionPerformed(ActionEvent e) {
3009:                    openScript();
3010:                }
3011:            }
3012:
3013:            private class ScriptClearAction extends EditorAction {
3014:                public ScriptClearAction() {
3015:                    super (ACTION_SCRIPT_CLEAR);
3016:                }
3017:
3018:                public void actionPerformed(ActionEvent e) {
3019:                    clearScript();
3020:                }
3021:            }
3022:
3023:            private class ScriptDeleteAction extends EditorAction {
3024:                public ScriptDeleteAction() {
3025:                    super (ACTION_SCRIPT_DELETE);
3026:                }
3027:
3028:                public void actionPerformed(ActionEvent e) {
3029:                    deleteScript();
3030:                }
3031:            }
3032:
3033:            private class ScriptSaveAction extends EditorAction {
3034:                public ScriptSaveAction() {
3035:                    super (ACTION_SCRIPT_SAVE);
3036:                }
3037:
3038:                public void actionPerformed(ActionEvent e) {
3039:                    saveScript();
3040:                }
3041:            }
3042:
3043:            private class ScriptSaveAsAction extends EditorAction {
3044:                public ScriptSaveAsAction() {
3045:                    super (ACTION_SCRIPT_SAVE_AS);
3046:                }
3047:
3048:                public void actionPerformed(ActionEvent e) {
3049:                    saveAsScript(false);
3050:                }
3051:            }
3052:
3053:            private class ScriptRenameAction extends EditorAction {
3054:                public ScriptRenameAction() {
3055:                    super (ACTION_SCRIPT_RENAME);
3056:                }
3057:
3058:                public void actionPerformed(ActionEvent e) {
3059:                    saveAsScript(true);
3060:                }
3061:            }
3062:
3063:            private class ScriptCloseAction extends EditorAction {
3064:                public ScriptCloseAction() {
3065:                    super (ACTION_SCRIPT_CLOSE);
3066:                }
3067:
3068:                public void actionPerformed(ActionEvent e) {
3069:                    closeScript();
3070:                }
3071:            }
3072:
3073:            private class StepCutAction extends EditorAction {
3074:                public StepCutAction() {
3075:                    super (ACTION_STEP_CUT);
3076:                }
3077:
3078:                public void actionPerformed(ActionEvent e) {
3079:                    cutSelection();
3080:                }
3081:            }
3082:
3083:            private class StepMoveUpAction extends EditorAction {
3084:                public StepMoveUpAction() {
3085:                    super (ACTION_STEP_MOVE_UP);
3086:                }
3087:
3088:                public void actionPerformed(ActionEvent e) {
3089:                    moveSelectionUp();
3090:                }
3091:            }
3092:
3093:            private class StepMoveDownAction extends EditorAction {
3094:                public StepMoveDownAction() {
3095:                    super (ACTION_STEP_MOVE_DOWN);
3096:                }
3097:
3098:                public void actionPerformed(ActionEvent e) {
3099:                    moveSelectionDown();
3100:                }
3101:            }
3102:
3103:            private class StepGroupAction extends EditorAction {
3104:                public StepGroupAction() {
3105:                    super (ACTION_STEP_GROUP);
3106:                }
3107:
3108:                public void actionPerformed(ActionEvent e) {
3109:                    groupSelection();
3110:                }
3111:            }
3112:
3113:            private class RunAction extends EditorAction {
3114:                public RunAction() {
3115:                    super (ACTION_RUN);
3116:                }
3117:
3118:                public void actionPerformed(ActionEvent e) {
3119:                    runScript(null);
3120:                }
3121:            }
3122:
3123:            private class RunSelectedAction extends EditorAction {
3124:                public RunSelectedAction() {
3125:                    super (ACTION_RUN_SELECTED);
3126:                }
3127:
3128:                public void actionPerformed(ActionEvent e) {
3129:                    runSelectedSteps();
3130:                }
3131:            }
3132:
3133:            private class RunToAction extends EditorAction {
3134:                public RunToAction() {
3135:                    super (ACTION_RUN_TO);
3136:                }
3137:
3138:                public void actionPerformed(ActionEvent e) {
3139:                    runScript(scriptTable.getSelectedStep());
3140:                }
3141:            }
3142:
3143:            private class ExportHierarchyAction extends EditorAction {
3144:                public ExportHierarchyAction() {
3145:                    super (ACTION_EXPORT_HIERARCHY);
3146:                }
3147:
3148:                public void actionPerformed(ActionEvent e) {
3149:                    exportHierarchy();
3150:                }
3151:            }
3152:
3153:            private class SelectTestSuiteAction extends EditorAction {
3154:                public SelectTestSuiteAction() {
3155:                    super (ACTION_SELECT_TESTSUITE);
3156:                }
3157:
3158:                public void actionPerformed(ActionEvent e) {
3159:                    browseTests();
3160:                }
3161:            }
3162:
3163:            private class RunLaunchAction extends EditorAction {
3164:                public RunLaunchAction() {
3165:                    super (ACTION_RUN_LAUNCH);
3166:                }
3167:
3168:                public void actionPerformed(ActionEvent e) {
3169:                    launch(true);
3170:                }
3171:            }
3172:
3173:            private class RunTerminateAction extends EditorAction {
3174:                public RunTerminateAction() {
3175:                    super (ACTION_RUN_TERMINATE);
3176:                }
3177:
3178:                public void actionPerformed(ActionEvent e) {
3179:                    terminate();
3180:                }
3181:            }
3182:
3183:            private class InsertLaunchAction extends EditorAction {
3184:                public InsertLaunchAction() {
3185:                    super (ACTION_INSERT_LAUNCH);
3186:                }
3187:
3188:                public void actionPerformed(ActionEvent e) {
3189:                    insertLaunch();
3190:                }
3191:            }
3192:
3193:            private class InsertFixtureAction extends EditorAction {
3194:                public InsertFixtureAction() {
3195:                    super (ACTION_INSERT_FIXTURE);
3196:                }
3197:
3198:                public void actionPerformed(ActionEvent e) {
3199:                    insertScript(true);
3200:                }
3201:            }
3202:
3203:            private class InsertAppletAction extends EditorAction {
3204:                public InsertAppletAction() {
3205:                    super (ACTION_INSERT_APPLET);
3206:                }
3207:
3208:                public void actionPerformed(ActionEvent e) {
3209:                    insertApplet();
3210:                }
3211:            }
3212:
3213:            private class InsertTerminateAction extends EditorAction {
3214:                public InsertTerminateAction() {
3215:                    super (ACTION_INSERT_TERMINATE);
3216:                }
3217:
3218:                public void actionPerformed(ActionEvent e) {
3219:                    insertTerminate();
3220:                }
3221:            }
3222:
3223:            private class InsertCallAction extends EditorAction {
3224:                public InsertCallAction() {
3225:                    super (ACTION_INSERT_CALL);
3226:                }
3227:
3228:                public void actionPerformed(ActionEvent e) {
3229:                    insertCall(false);
3230:                }
3231:            }
3232:
3233:            private class InsertSampleAction extends EditorAction {
3234:                public InsertSampleAction() {
3235:                    super (ACTION_INSERT_SAMPLE);
3236:                }
3237:
3238:                public void actionPerformed(ActionEvent e) {
3239:                    insertCall(true);
3240:                }
3241:            }
3242:
3243:            private class InsertSequenceAction extends EditorAction {
3244:                public InsertSequenceAction() {
3245:                    super (ACTION_INSERT_SEQUENCE);
3246:                }
3247:
3248:                public void actionPerformed(ActionEvent e) {
3249:                    insertSequence();
3250:                }
3251:            }
3252:
3253:            private class InsertScriptAction extends EditorAction {
3254:                public InsertScriptAction() {
3255:                    super (ACTION_INSERT_SCRIPT);
3256:                }
3257:
3258:                public void actionPerformed(ActionEvent e) {
3259:                    insertScript(false);
3260:                }
3261:            }
3262:
3263:            private class InsertCommentAction extends EditorAction {
3264:                public InsertCommentAction() {
3265:                    super (ACTION_INSERT_COMMENT);
3266:                }
3267:
3268:                public void actionPerformed(ActionEvent e) {
3269:                    insertComment();
3270:                }
3271:            }
3272:
3273:            private class InsertExpressionAction extends EditorAction {
3274:                public InsertExpressionAction() {
3275:                    super (ACTION_INSERT_EXPRESSION);
3276:                }
3277:
3278:                public void actionPerformed(ActionEvent e) {
3279:                    insertExpression();
3280:                }
3281:            }
3282:
3283:            private class InsertAnnotationAction extends EditorAction {
3284:                public InsertAnnotationAction() {
3285:                    super (ACTION_INSERT_ANNOTATION);
3286:                }
3287:
3288:                public void actionPerformed(ActionEvent e) {
3289:                    insertAnnotation();
3290:                }
3291:            }
3292:
3293:            private class GetVMArgsAction extends EditorAction {
3294:                public GetVMArgsAction() {
3295:                    super (ACTION_GET_VMARGS);
3296:                }
3297:
3298:                public void actionPerformed(ActionEvent e) {
3299:                    getVMArgs();
3300:                }
3301:            }
3302:
3303:            private class SelectComponentAction extends EditorAction {
3304:                public SelectComponentAction() {
3305:                    super (ACTION_SELECT_COMPONENT);
3306:                    putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(selectKey,
3307:                            InputEvent.SHIFT_MASK));
3308:                }
3309:
3310:                public void actionPerformed(ActionEvent e) {
3311:                    // This is really only for documentation purposes; there is
3312:                    // nothing to capture if the menu item can be activated, since
3313:                    // the editor has focus when the menu is selected.
3314:                    view.showWarning(Strings
3315:                            .get("actions.select-component.desc"));
3316:                }
3317:            }
3318:
3319:            private class CaptureComponentAction extends EditorAction {
3320:                public CaptureComponentAction() {
3321:                    super (ACTION_CAPTURE_COMPONENT);
3322:                    putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(selectKey,
3323:                            InputEvent.SHIFT_MASK | InputEvent.ALT_MASK));
3324:                }
3325:
3326:                public void actionPerformed(ActionEvent e) {
3327:                    // This is really only for documentation purposes; there is
3328:                    // nothing to capture if the menu item can be activated, since
3329:                    // the editor has focus when the menu is selected.
3330:                    view.showWarning(Strings
3331:                            .get("actions.capture-component.desc"));
3332:                }
3333:            }
3334:
3335:            private class CaptureImageAction extends EditorAction {
3336:                public CaptureImageAction() {
3337:                    super (ACTION_CAPTURE_IMAGE);
3338:                    putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(
3339:                            captureImageKey, InputEvent.SHIFT_MASK));
3340:                }
3341:
3342:                public void actionPerformed(ActionEvent e) {
3343:                    // This is really only for documentation purposes; there is
3344:                    // nothing to capture if the menu item can be activated, since
3345:                    // the editor has focus when the menu is selected.
3346:                    view.showWarning(Strings.get("actions.capture-image.desc"));
3347:                }
3348:            }
3349:
3350:            private class ToggleForkedAction extends EditorToggleAction {
3351:                public ToggleForkedAction() {
3352:                    super (ACTION_TOGGLE_FORKED);
3353:                }
3354:
3355:                public void actionPerformed(ActionEvent e) {
3356:                    forkedToggle();
3357:                }
3358:            }
3359:
3360:            private class ToggleSlowPlaybackAction extends EditorToggleAction {
3361:                public ToggleSlowPlaybackAction() {
3362:                    super (ACTION_TOGGLE_SLOW_PLAYBACK);
3363:                }
3364:
3365:                public void actionPerformed(ActionEvent e) {
3366:                    slowPlaybackToggle();
3367:                }
3368:            }
3369:
3370:            private class ToggleAWTModeAction extends EditorToggleAction {
3371:                public ToggleAWTModeAction() {
3372:                    super (ACTION_TOGGLE_AWT_MODE);
3373:                }
3374:
3375:                public void actionPerformed(ActionEvent e) {
3376:                    awtModeToggle();
3377:                }
3378:            }
3379:
3380:            private class ToggleStopOnErrorAction extends EditorToggleAction {
3381:                public ToggleStopOnErrorAction() {
3382:                    super (ACTION_TOGGLE_STOP_ON_ERROR);
3383:                }
3384:
3385:                public void actionPerformed(ActionEvent e) {
3386:                    stopOnErrorToggle();
3387:                }
3388:            }
3389:
3390:            private class ToggleStopOnFailureAction extends EditorToggleAction {
3391:                public ToggleStopOnFailureAction() {
3392:                    super (ACTION_TOGGLE_STOP_ON_FAILURE);
3393:                }
3394:
3395:                public void actionPerformed(ActionEvent e) {
3396:                    stopOnFailureToggle();
3397:                }
3398:            }
3399:
3400:            private class EditorStepRunner extends StepRunner {
3401:                /** We use a single runner througout the editor's lifetime, 
3402:                 * so one saved UI context will suffice.
3403:                 */
3404:                public EditorStepRunner() {
3405:                    super (new AWTFixtureHelper());
3406:                }
3407:
3408:                public Hierarchy getHierarchy() {
3409:                    return ScriptEditor.this .hierarchy;
3410:                }
3411:
3412:                public void terminate() {
3413:                    super.terminate();
3414:                    setActionsEnabledState();
3415:                    view.getComponentBrowser().refresh();
3416:                }
3417:            }
3418:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.