Clover coverage report - clover
Coverage timestamp: Sat Oct 8 2005 22:54:17 EDT
file stats: LOC: 3,283   Methods: 264
NCLOC: 2,724   Classes: 54
 
 Source file Conditionals Statements Methods TOTAL
ScriptEditor.java 16.4% 30.5% 36.7% 27.6%
coverage coverage
 1   
 package abbot.editor;
 2   
 
 3   
 import java.awt.*;
 4   
 import java.awt.event.*;
 5   
 import java.io.*;
 6   
 import java.lang.reflect.*;
 7   
 import java.net.URL;
 8   
 import java.util.*;
 9   
 import java.util.List;
 10   
 
 11   
 import javax.swing.*;
 12   
 import javax.swing.filechooser.FileFilter;
 13   
 import javax.swing.event.*;
 14   
 
 15   
 import junit.extensions.abbot.*;
 16   
 import junit.runner.TestCollector;
 17   
 import abbot.BugReport;
 18   
 import abbot.Log;
 19   
 import abbot.ExitException;
 20   
 import abbot.NoExitSecurityManager;
 21   
 import abbot.AssertionFailedError;
 22   
 import abbot.Platform;
 23   
 import abbot.editor.actions.*;
 24   
 import abbot.editor.editors.*;
 25   
 import abbot.editor.recorder.*;
 26   
 import abbot.editor.widgets.*;
 27   
 import abbot.editor.widgets.TextField;
 28   
 import abbot.finder.*;
 29   
 import abbot.i18n.Strings;
 30   
 import abbot.script.*;
 31   
 import abbot.script.Action;
 32   
 import abbot.script.Resolver;
 33   
 import abbot.tester.*;
 34   
 import abbot.tester.Robot;
 35   
 import abbot.util.*;
 36   
 import abbot.util.Properties;
 37   
 import abbot.util.ThreadTerminatingSecurityManager.ThreadTerminatedException;
 38   
 
 39   
 import com.apple.mrj.*;
 40   
 
 41   
 /**
 42   
  * This is the 'model' behind the script editor UI.<p>
 43   
  *
 44   
  * Acts as a resolver, using the currently in-context script as the component
 45   
  * resolver. <p>
 46   
  */
 47   
 
 48   
 /* To add new actions, add the action to the list in initActions(),
 49   
  * and optionally add it to the menu layout in initMenus.  Define a name for
 50   
  * it in EditorConstants, and an inner Action class for it which uses that
 51   
  * name. 
 52   
  */
 53   
 // Apologies for the extreme cruftiness and lack of proper factoring.  This
 54   
 // was written at the same time as the underlying framework, and refactored
 55   
 // (sort of) into model/view at the same time, so it's hardly a shining
 56   
 // example of clean design.  Don't know if it would have been any better
 57   
 // written TDD, though.
 58   
 public class ScriptEditor 
 59   
     implements ActionListener, Resolver, EditorConstants {
 60   
 
 61   
     private static int selectKey;
 62   
     private static int captureKey;
 63   
     private static int captureImageKey;
 64   
 
 65   
     static {
 66  2
         try {
 67  2
             new EventExceptionHandler().install();
 68   
         }
 69   
         catch(Exception e) {
 70   
             // Ignore for now
 71   
         }
 72  2
         String key = System.getProperty("abbot.editor.select_key", "F1");
 73  2
         selectKey = KeyStroke.getKeyStroke(key).getKeyCode();
 74  2
         key = System.getProperty("abbot.editor.capture_key", "F2");
 75  2
         captureKey = KeyStroke.getKeyStroke(key).getKeyCode();
 76  2
         key = System.getProperty("abbot.editor.capture_image_key", "F3");
 77  2
         captureImageKey = KeyStroke.getKeyStroke(key).getKeyCode();
 78   
     }
 79   
 
 80   
     // if set, log all events, even those going to filtered components
 81   
     private static final boolean LOG_ALL_EVENTS =
 82   
         Boolean.getBoolean("abbot.editor.log_all_events");
 83   
     private static final long FIXTURE_EVENT_MASK =
 84   
         Long.getLong("abbot.fixture.event_mask", 
 85   
                     EventRecorder.RECORDING_EVENT_MASK).longValue();
 86   
 
 87   
     /** Key to use to invert an assertion/wait. */
 88   
     public static final int KC_INVERT = KeyEvent.VK_SHIFT;
 89   
     /** Key to use to insert a wait instead of an assertion.   Use option key
 90   
         on mac, control key anywhere else. */
 91   
     public static final int KC_WAIT =
 92  2
         Platform.isMacintosh() ? KeyEvent.VK_ALT : KeyEvent.VK_CONTROL;
 93   
     /** Flag for informational status. */
 94   
     private static final int INFO = 0;
 95   
     /** Flag to indicate a warning. */
 96   
     private static final int WARN = 1;
 97   
     /** Flag to indicate an error. */
 98   
     private static final int ERROR = 2;
 99   
     /** Flag to indicate a script failure. */
 100   
     private static final int FAILURE = 3;
 101   
     /** Prefixes for different types of status messages. */
 102   
     private static final String[] statusFormat =
 103   
         { "Normal", "Warning", "Error", "Failure" };
 104   
     private static final Color[] statusColor = {
 105   
         Color.black,
 106   
         Color.orange.darker(),
 107   
         Color.red,
 108   
         Color.red,
 109   
     };
 110   
 
 111   
     private ArrayList insertActions = new ArrayList();
 112   
     private ArrayList assertActions = new ArrayList();
 113   
     private ArrayList waitActions = new ArrayList();
 114   
     private ArrayList captureActions = new ArrayList();
 115   
 
 116   
     /** Adapter for representing the script itself, providing access to
 117   
      * individual script steps.
 118   
      */
 119   
     private ScriptModel scriptModel;
 120   
     private ScriptTable scriptTable;
 121   
     private EditorSecurityManager securityManager;
 122   
     private SecurityManager oldSecurityManager;
 123   
 
 124   
     private int nonce;
 125   
     /** Keep all application under test threads in the same group to make them
 126   
      * easier to track. */
 127   
     private ThreadGroup appGroup;
 128   
     private TestHierarchy hierarchy;
 129   
     private Hierarchy oldHierarchy;
 130   
     private Recorder[] recorders;
 131   
     private java.util.List savedStateWhileRecording;
 132   
     /** Allow exits from anywhere until the editor is fully initialized. */
 133   
     private boolean rootIsExiting = true;
 134   
     private boolean exiting;
 135   
     private boolean hiding;
 136   
     private boolean ignoreStepEvents;
 137   
     /** Whether to ignore incoming AWT events. */
 138   
     private boolean ignoreEvents;
 139   
     /** Is there a script or launch step currently running? */
 140   
     private boolean isScriptRunning;
 141   
     /** When was some portion of the app exercised? */
 142   
     private long lastLaunchTime;
 143   
     /** Are we trying to capture an image? */
 144   
     private boolean capturingImage;
 145   
     /** What component is currently "selected" for capture? */
 146   
     private Component captureComponent;
 147   
     private Component innermostCaptureComponent;
 148   
     private Highlighter highlighter;
 149   
     /** Is this the first editor launched, or one under test? */
 150   
     private boolean isRootEditor = true;
 151   
     /** AWT input state. */
 152   
     private static InputState state = Robot.getState();
 153   
     /** Generic filter to select a test script. */
 154   
     private ScriptFilter filter = new ScriptFilter();
 155   
 
 156   
     /** Current test case class (should derive from AWTTestCase). */
 157   
     private Class testClass;
 158   
     /** Current test suite.  */
 159   
     private ScriptTestSuite testSuite;
 160   
     /** Current test script. */
 161   
     private Script testScript;
 162   
     /** Is the current script a temporary placeholder? */
 163   
     private File tempFile;
 164   
     /** Runner used to execute the script. */
 165   
     private StepRunner runner;
 166   
     /** Current set of scripts, based on the test suite (if any). */
 167   
     private List testScriptList;
 168   
     /** Currently selected component.  Note that this may be a dummy
 169   
      * component.
 170   
      */
 171   
     private Component selectedComponent;
 172   
     /** Currently selected reference, if any. */
 173   
     private ComponentReference selectedReference;
 174   
 
 175   
     /** Are we currently recording events? */
 176   
     private boolean recording;
 177   
     /** The current recorder to pass events for capture. */
 178   
     private Recorder recorder;
 179   
     /** Since recorder starts with a key release, and stops with a key press,
 180   
         make sure we don't start immediately after stopping.
 181   
     */
 182   
     private boolean justStoppedRecording;
 183   
     /** Need to be able to set the combo box selection w/o reacting to the
 184   
      * resulting posted action.
 185   
      */
 186   
     private boolean ignoreComboBox;
 187   
     /** Where to stop. */
 188   
     private Step stopStep;
 189   
 
 190   
     // GUI components
 191   
     private JFileChooser chooser;
 192   
     private ScriptEditorFrame view;
 193   
     private ComboBoxModel model;
 194   
 
 195   
     private boolean invertAssertions;
 196   
     private boolean waitAssertions;
 197   
     private ActionMap actionMap;
 198   
     private String name;
 199   
 
 200   
     /**
 201   
      * Constructs a ScriptEditor which handles script editing logic.
 202   
      * ScriptEditorFrame provides the view/controller.
 203   
      * @see ScriptEditorFrame
 204   
      */
 205  2
     public ScriptEditor() {
 206   
 
 207  2
         if (Boolean.getBoolean("abbot.framework.launched")) {
 208  0
             isRootEditor = false;
 209  0
             name = "Script Editor (under test)";
 210   
         }
 211   
         else {
 212  2
             System.setProperty("abbot.framework.launched", "true");
 213  2
             name = "Script Editor (root)";
 214   
         }
 215   
 
 216   
         // TODO: clean this up
 217  2
         actionMap = initActions();
 218  2
         hierarchy = initContext(isRootEditor);
 219  2
         recorders = initRecorders();
 220  2
         view = initFrame(isRootEditor);
 221  2
         hierarchy.setFiltered(view, true);
 222  2
         updateDynamicActions(view);
 223   
 
 224  2
         view.setComponentBrowser(createComponentBrowser());
 225  2
         addEventHandlers(view);
 226   
 
 227   
         // Clear the status only if there were no errors
 228  2
         if (view.getStatus().equals(Strings.get("Initializing"))) {
 229  2
             setStatus(Strings.get("Ready"));
 230   
         }
 231  2
         rootIsExiting = false;
 232   
     }
 233   
 
 234   
     /** Provides a convenient menu setup definition.
 235   
         Use a defined action name to indicate that action's place within the
 236   
         menu.  Null values indicate menu separators.
 237   
      */
 238  2
     private String[][] initMenus() {
 239  2
         ArrayList fileMenu = new ArrayList();
 240  2
         ArrayList helpMenu = new ArrayList();
 241  2
         fileMenu.addAll(Arrays.asList(new String[] {
 242   
             MENU_FILE,
 243   
             ACTION_SCRIPT_NEW,
 244   
             ACTION_SCRIPT_DUPLICATE,
 245   
             ACTION_SCRIPT_OPEN,
 246   
             null,
 247   
             ACTION_SCRIPT_SAVE,
 248   
             ACTION_SCRIPT_SAVE_AS,
 249   
             ACTION_SCRIPT_RENAME,
 250   
             ACTION_SCRIPT_CLOSE,
 251   
             null,
 252   
             ACTION_SCRIPT_DELETE,
 253   
         }));
 254   
 
 255  2
         helpMenu.add(MENU_HELP);
 256  2
         if (!Platform.isOSX()) {
 257  2
             fileMenu.add(null);
 258  2
             fileMenu.add(ACTION_EDITOR_QUIT);
 259  2
             helpMenu.add(ACTION_EDITOR_ABOUT);
 260   
         }
 261  2
         helpMenu.addAll(Arrays.asList(new String[] {
 262   
             ACTION_EDITOR_USERGUIDE,
 263   
             ACTION_EDITOR_WEBSITE,
 264   
             ACTION_EDITOR_EMAIL,
 265   
             ACTION_EDITOR_BUGREPORT,
 266   
         }));
 267   
 
 268  2
         return new String[][] {
 269   
             (String[])fileMenu.toArray(new String[fileMenu.size()]),
 270   
             {
 271   
                 MENU_EDIT,
 272   
                 ACTION_STEP_CUT,
 273   
                 null,
 274   
                 ACTION_STEP_MOVE_UP,
 275   
                 ACTION_STEP_MOVE_DOWN,
 276   
                 ACTION_STEP_GROUP,
 277   
                 null,
 278   
                 ACTION_SELECT_COMPONENT,
 279   
                 null,
 280   
                 ACTION_SCRIPT_CLEAR,
 281   
             },
 282   
             {
 283   
                 MENU_TEST,
 284   
                 ACTION_RUN,
 285   
                 ACTION_RUN_TO,
 286   
                 ACTION_RUN_SELECTED,
 287   
                 null,
 288   
                 ACTION_EXPORT_HIERARCHY,
 289   
                 null,
 290   
                 ACTION_RUN_LAUNCH,
 291   
                 ACTION_RUN_TERMINATE,
 292   
                 null,
 293   
                 ACTION_TOGGLE_STOP_ON_FAILURE,
 294   
                 ACTION_TOGGLE_STOP_ON_ERROR,
 295   
                 ACTION_TOGGLE_FORKED,
 296   
                 ACTION_GET_VMARGS,
 297   
                 ACTION_TOGGLE_SLOW_PLAYBACK,
 298   
                 ACTION_TOGGLE_AWT_MODE,
 299   
             },
 300   
             {
 301   
                 MENU_INSERT,
 302   
                 ACTION_INSERT_ANNOTATION,
 303   
                 ACTION_INSERT_APPLET,
 304   
                 ACTION_INSERT_CALL,
 305   
                 ACTION_INSERT_COMMENT,
 306   
                 ACTION_INSERT_EXPRESSION,
 307   
                 ACTION_INSERT_LAUNCH,
 308   
                 ACTION_INSERT_FIXTURE,
 309   
                 ACTION_INSERT_SAMPLE,
 310   
                 ACTION_INSERT_SCRIPT,
 311   
                 ACTION_INSERT_SEQUENCE,
 312   
                 ACTION_INSERT_TERMINATE,
 313   
             },
 314   
             {
 315   
                 MENU_CAPTURE,
 316   
             },
 317   
             (String[])helpMenu.toArray(new String[helpMenu.size()]),
 318   
         };
 319   
     }
 320   
 
 321   
     // All editor actions should be defined here
 322  2
     private ActionMap initActions() {
 323  2
         javax.swing.Action[] actions = {
 324   
             new EditorAboutAction(),
 325   
             new EditorEmailAction(),
 326   
             new EditorBugReportAction(),
 327   
             new EditorWebsiteAction(),
 328   
             new EditorUserGuideAction(),
 329   
             new EditorQuitAction(),
 330   
             new ScriptOpenAction(),
 331   
             new ScriptNewAction(),
 332   
             new ScriptDuplicateAction(),
 333   
             new ScriptSaveAction(),
 334   
             new ScriptSaveAsAction(),
 335   
             new ScriptRenameAction(),
 336   
             new ScriptCloseAction(),
 337   
             new ScriptDeleteAction(),
 338   
             new ScriptClearAction(),
 339   
             new StepCutAction(),
 340   
             new StepMoveUpAction(),
 341   
             new StepMoveDownAction(),
 342   
             new StepGroupAction(),
 343   
             new RunAction(),
 344   
             new RunToAction(),
 345   
             new RunSelectedAction(),
 346   
             new RunLaunchAction(),
 347   
             new RunTerminateAction(),
 348   
             new GetVMArgsAction(),
 349   
             new SelectTestSuiteAction(),
 350   
             new ExportHierarchyAction(),
 351   
             new ToggleForkedAction(),
 352   
             new InsertLaunchAction(),
 353   
             new InsertFixtureAction(),
 354   
             new InsertAppletAction(),
 355   
             new InsertTerminateAction(),
 356   
             new InsertCallAction(),
 357   
             new InsertSampleAction(),
 358   
             new InsertSequenceAction(),
 359   
             new InsertScriptAction(),
 360   
             new InsertCommentAction(),
 361   
             new InsertExpressionAction(),
 362   
             new InsertAnnotationAction(),
 363   
             new ToggleStopOnFailureAction(),
 364   
             new ToggleStopOnErrorAction(),
 365   
             new ToggleSlowPlaybackAction(),
 366   
             new ToggleAWTModeAction(),
 367   
             new CaptureImageAction(),
 368   
             new CaptureComponentAction(),
 369   
             new SelectComponentAction(),
 370   
         };
 371  2
         ActionMap map = new ActionMap();
 372  2
         for (int i=0;i < actions.length;i++) {
 373  92
             Object key = actions[i].getValue(EditorAction.ACTION_KEY);
 374  92
             map.put(key, actions[i]);
 375   
         }
 376  2
         return map;
 377   
     }
 378   
 
 379   
     /**
 380   
      *  Add event handlers to their respective components
 381   
      */
 382  2
     private void addEventHandlers(final ScriptEditorFrame view) {
 383  2
         scriptTable.getSelectionModel().
 384   
             addListSelectionListener(new ScriptTableSelectionHandler());
 385  2
         scriptTable.addMouseListener(new MouseAdapter() {
 386  0
             public void mouseClicked(MouseEvent me) {
 387  0
                 if ((me.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
 388  0
                     if (view.getEditor() == null)
 389  0
                         setStepEditor();
 390   
                 }
 391   
             }
 392   
         });
 393  2
         MouseListener ml = new MouseAdapter() {
 394  0
             public void mouseClicked(MouseEvent me) {                          
 395  0
                 if ((me.getModifiers() & MouseEvent.BUTTON1_MASK) != 0) {
 396  0
                     int size = scriptTable.getRowCount();            
 397  0
                     scriptTable.clearSelection();                    
 398  0
                     scriptTable.setCursorLocation(size); 
 399   
                 }                                                              
 400   
             }                                                                  
 401   
         };
 402  2
         view.addMouseListener(ml);
 403  2
         view.getTestScriptSelector().addItemListener(new ScriptSelectorItemHandler());
 404  2
         view.addWindowListener(new WindowAdapter() {
 405  0
             public void windowClosing(WindowEvent e) {
 406  0
                 quitApplication();
 407   
             }
 408   
         });
 409  2
         if (Platform.isOSX()) {
 410   
             // Mac has it's own dedicated Quit/About menu items
 411  0
             MRJApplicationUtils.registerQuitHandler(new MRJQuitHandler() {
 412  0
                 public void handleQuit() {
 413  0
                     quitApplication();
 414   
                 }
 415   
             });
 416  0
             MRJApplicationUtils.registerAboutHandler(new MRJAboutHandler() {
 417  0
                 public void handleAbout() {
 418  0
                     view.showAboutBox();
 419   
                 }
 420   
             });
 421   
         }
 422   
     }
 423