1. package junit.swingui;
  2. import java.awt.*;
  3. import java.awt.event.*;
  4. import java.io.*;
  5. import java.net.URL;
  6. import java.util.*;
  7. import javax.swing.*;
  8. import javax.swing.event.*;
  9. import junit.framework.*;
  10. import junit.runner.*;
  11. /**
  12. * A Swing based user interface to run tests.
  13. * Enter the name of a class which either provides a static
  14. * suite method or is a subclass of TestCase.
  15. * <pre>
  16. * Synopsis: java junit.swingui.TestRunner [-noloading] [TestCase]
  17. * </pre>
  18. * TestRunner takes as an optional argument the name of the testcase class to be run.
  19. */
  20. public class TestRunner extends BaseTestRunner implements TestRunContext {
  21. private static final int GAP= 4;
  22. private static final int HISTORY_LENGTH= 5;
  23. protected JFrame fFrame;
  24. private Thread fRunner;
  25. private TestResult fTestResult;
  26. private JComboBox fSuiteCombo;
  27. private ProgressBar fProgressIndicator;
  28. private DefaultListModel fFailures;
  29. private JLabel fLogo;
  30. private CounterPanel fCounterPanel;
  31. private JButton fRun;
  32. private JButton fQuitButton;
  33. private JButton fRerunButton;
  34. private StatusLine fStatusLine;
  35. private FailureDetailView fFailureView;
  36. private JTabbedPane fTestViewTab;
  37. private JCheckBox fUseLoadingRunner;
  38. private Vector fTestRunViews= new Vector(); // view associated with tab in tabbed pane
  39. private static final String TESTCOLLECTOR_KEY= "TestCollectorClass";
  40. private static final String FAILUREDETAILVIEW_KEY= "FailureViewClass";
  41. public TestRunner() {
  42. }
  43. public static void main(String[] args) {
  44. new TestRunner().start(args);
  45. }
  46. public static void run(Class test) {
  47. String args[]= { test.getName() };
  48. main(args);
  49. }
  50. public void testFailed(final int status, final Test test, final Throwable t) {
  51. SwingUtilities.invokeLater(
  52. new Runnable() {
  53. public void run() {
  54. switch (status) {
  55. case TestRunListener.STATUS_ERROR:
  56. fCounterPanel.setErrorValue(fTestResult.errorCount());
  57. appendFailure(test, t);
  58. break;
  59. case TestRunListener.STATUS_FAILURE:
  60. fCounterPanel.setFailureValue(fTestResult.failureCount());
  61. appendFailure(test, t);
  62. break;
  63. }
  64. }
  65. }
  66. );
  67. }
  68. public void testStarted(String testName) {
  69. postInfo("Running: "+testName);
  70. }
  71. public void testEnded(String stringName) {
  72. synchUI();
  73. SwingUtilities.invokeLater(
  74. new Runnable() {
  75. public void run() {
  76. if (fTestResult != null) {
  77. fCounterPanel.setRunValue(fTestResult.runCount());
  78. fProgressIndicator.step(fTestResult.runCount(), fTestResult.wasSuccessful());
  79. }
  80. }
  81. }
  82. );
  83. }
  84. public void setSuite(String suiteName) {
  85. fSuiteCombo.getEditor().setItem(suiteName);
  86. }
  87. private void addToHistory(final String suite) {
  88. for (int i= 0; i < fSuiteCombo.getItemCount(); i++) {
  89. if (suite.equals(fSuiteCombo.getItemAt(i))) {
  90. fSuiteCombo.removeItemAt(i);
  91. fSuiteCombo.insertItemAt(suite, 0);
  92. fSuiteCombo.setSelectedIndex(0);
  93. return;
  94. }
  95. }
  96. fSuiteCombo.insertItemAt(suite, 0);
  97. fSuiteCombo.setSelectedIndex(0);
  98. pruneHistory();
  99. }
  100. private void pruneHistory() {
  101. int historyLength= getPreference("maxhistory", HISTORY_LENGTH);
  102. if (historyLength < 1)
  103. historyLength= 1;
  104. for (int i= fSuiteCombo.getItemCount()-1; i > historyLength-1; i--)
  105. fSuiteCombo.removeItemAt(i);
  106. }
  107. private void appendFailure(Test test, Throwable t) {
  108. fFailures.addElement(new TestFailure(test, t));
  109. if (fFailures.size() == 1)
  110. revealFailure(test);
  111. }
  112. private void revealFailure(Test test) {
  113. for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
  114. TestRunView v= (TestRunView) e.nextElement();
  115. v.revealFailure(test);
  116. }
  117. }
  118. protected void aboutToStart(final Test testSuite) {
  119. for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
  120. TestRunView v= (TestRunView) e.nextElement();
  121. v.aboutToStart(testSuite, fTestResult);
  122. }
  123. }
  124. protected void runFinished(final Test testSuite) {
  125. SwingUtilities.invokeLater(
  126. new Runnable() {
  127. public void run() {
  128. for (Enumeration e= fTestRunViews.elements(); e.hasMoreElements(); ) {
  129. TestRunView v= (TestRunView) e.nextElement();
  130. v.runFinished(testSuite, fTestResult);
  131. }
  132. }
  133. }
  134. );
  135. }
  136. protected CounterPanel createCounterPanel() {
  137. return new CounterPanel();
  138. }
  139. protected JPanel createFailedPanel() {
  140. JPanel failedPanel= new JPanel(new GridLayout(0, 1, 0, 2));
  141. fRerunButton= new JButton("Run");
  142. fRerunButton.setEnabled(false);
  143. fRerunButton.addActionListener(
  144. new ActionListener() {
  145. public void actionPerformed(ActionEvent e) {
  146. rerun();
  147. }
  148. }
  149. );
  150. failedPanel.add(fRerunButton);
  151. return failedPanel;
  152. }
  153. protected FailureDetailView createFailureDetailView() {
  154. String className= BaseTestRunner.getPreference(FAILUREDETAILVIEW_KEY);
  155. if (className != null) {
  156. Class viewClass= null;
  157. try {
  158. viewClass= Class.forName(className);
  159. return (FailureDetailView)viewClass.newInstance();
  160. } catch(Exception e) {
  161. JOptionPane.showMessageDialog(fFrame, "Could not create Failure DetailView - using default view");
  162. }
  163. }
  164. return new DefaultFailureDetailView();
  165. }
  166. /**
  167. * Creates the JUnit menu. Clients override this
  168. * method to add additional menu items.
  169. */
  170. protected JMenu createJUnitMenu() {
  171. JMenu menu= new JMenu("JUnit");
  172. menu.setMnemonic('J');
  173. JMenuItem mi1= new JMenuItem("About...");
  174. mi1.addActionListener(
  175. new ActionListener() {
  176. public void actionPerformed(ActionEvent event) {
  177. about();
  178. }
  179. }
  180. );
  181. mi1.setMnemonic('A');
  182. menu.add(mi1);
  183. menu.addSeparator();
  184. JMenuItem mi2= new JMenuItem(" Exit ");
  185. mi2.addActionListener(
  186. new ActionListener() {
  187. public void actionPerformed(ActionEvent event) {
  188. terminate();
  189. }
  190. }
  191. );
  192. mi2.setMnemonic('x');
  193. menu.add(mi2);
  194. return menu;
  195. }
  196. protected JFrame createFrame() {
  197. JFrame frame= new JFrame("JUnit");
  198. Image icon= loadFrameIcon();
  199. if (icon != null)
  200. frame.setIconImage(icon);
  201. frame.getContentPane().setLayout(new BorderLayout(0, 0));
  202. frame.addWindowListener(
  203. new WindowAdapter() {
  204. public void windowClosing(WindowEvent e) {
  205. terminate();
  206. }
  207. }
  208. );
  209. return frame;
  210. }
  211. protected JLabel createLogo() {
  212. JLabel label;
  213. Icon icon= getIconResource(BaseTestRunner.class, "logo.gif");
  214. if (icon != null)
  215. label= new JLabel(icon);
  216. else
  217. label= new JLabel("JV");
  218. label.setToolTipText("JUnit Version "+Version.id());
  219. return label;
  220. }
  221. protected void createMenus(JMenuBar mb) {
  222. mb.add(createJUnitMenu());
  223. }
  224. protected JCheckBox createUseLoaderCheckBox() {
  225. boolean useLoader= useReloadingTestSuiteLoader();
  226. JCheckBox box= new JCheckBox("Reload classes every run", useLoader);
  227. box.setToolTipText("Use a custom class loader to reload the classes for every run");
  228. if (inVAJava())
  229. box.setVisible(false);
  230. return box;
  231. }
  232. protected JButton createQuitButton() {
  233. // spaces required to avoid layout flicker
  234. // Exit is shorter than Stop that shows in the same column
  235. JButton quit= new JButton(" Exit ");
  236. quit.addActionListener(
  237. new ActionListener() {
  238. public void actionPerformed(ActionEvent e) {
  239. terminate();
  240. }
  241. }
  242. );
  243. return quit;
  244. }
  245. protected JButton createRunButton() {
  246. JButton run= new JButton("Run");
  247. run.setEnabled(true);
  248. run.addActionListener(
  249. new ActionListener() {
  250. public void actionPerformed(ActionEvent e) {
  251. runSuite();
  252. }
  253. }
  254. );
  255. return run;
  256. }
  257. protected Component createBrowseButton() {
  258. JButton browse= new JButton("...");
  259. browse.setToolTipText("Select a Test class");
  260. browse.addActionListener(
  261. new ActionListener() {
  262. public void actionPerformed(ActionEvent e) {
  263. browseTestClasses();
  264. }
  265. }
  266. );
  267. return browse;
  268. }
  269. protected StatusLine createStatusLine() {
  270. return new StatusLine(380);
  271. }
  272. protected JComboBox createSuiteCombo() {
  273. JComboBox combo= new JComboBox();
  274. combo.setEditable(true);
  275. combo.setLightWeightPopupEnabled(false);
  276. combo.getEditor().getEditorComponent().addKeyListener(
  277. new KeyAdapter() {
  278. public void keyTyped(KeyEvent e) {
  279. textChanged();
  280. if (e.getKeyChar() == KeyEvent.VK_ENTER)
  281. runSuite();
  282. }
  283. }
  284. );
  285. try {
  286. loadHistory(combo);
  287. } catch (IOException e) {
  288. // fails the first time
  289. }
  290. combo.addItemListener(
  291. new ItemListener() {
  292. public void itemStateChanged(ItemEvent event) {
  293. if (event.getStateChange() == ItemEvent.SELECTED) {
  294. textChanged();
  295. }
  296. }
  297. }
  298. );
  299. return combo;
  300. }
  301. protected JTabbedPane createTestRunViews() {
  302. JTabbedPane pane= new JTabbedPane(JTabbedPane.BOTTOM);
  303. FailureRunView lv= new FailureRunView(this);
  304. fTestRunViews.addElement(lv);
  305. lv.addTab(pane);
  306. TestHierarchyRunView tv= new TestHierarchyRunView(this);
  307. fTestRunViews.addElement(tv);
  308. tv.addTab(pane);
  309. pane.addChangeListener(
  310. new ChangeListener() {
  311. public void stateChanged(ChangeEvent e) {
  312. testViewChanged();
  313. }
  314. }
  315. );
  316. return pane;
  317. }
  318. public void testViewChanged() {
  319. TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex());
  320. view.activate();
  321. }
  322. protected TestResult createTestResult() {
  323. return new TestResult();
  324. }
  325. protected JFrame createUI(String suiteName) {
  326. JFrame frame= createFrame();
  327. JMenuBar mb= new JMenuBar();
  328. createMenus(mb);
  329. frame.setJMenuBar(mb);
  330. JLabel suiteLabel= new JLabel("Test class name:");
  331. fSuiteCombo= createSuiteCombo();
  332. fRun= createRunButton();
  333. frame.getRootPane().setDefaultButton(fRun);
  334. Component browseButton= createBrowseButton();
  335. fUseLoadingRunner= createUseLoaderCheckBox();
  336. fProgressIndicator= new ProgressBar();
  337. fCounterPanel= createCounterPanel();
  338. fFailures= new DefaultListModel();
  339. fTestViewTab= createTestRunViews();
  340. JPanel failedPanel= createFailedPanel();
  341. fFailureView= createFailureDetailView();
  342. JScrollPane tracePane= new JScrollPane(fFailureView.getComponent(), JScrollPane.VERTICAL_SCROLLBAR_ALWAYS, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
  343. fStatusLine= createStatusLine();
  344. fQuitButton= createQuitButton();
  345. fLogo= createLogo();
  346. JPanel panel= new JPanel(new GridBagLayout());
  347. addGrid(panel, suiteLabel, 0, 0, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  348. addGrid(panel, fSuiteCombo, 0, 1, 1, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  349. addGrid(panel, browseButton, 1, 1, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
  350. addGrid(panel, fRun, 2, 1, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
  351. addGrid(panel, fUseLoadingRunner, 0, 2, 3, GridBagConstraints.NONE, 1.0, GridBagConstraints.WEST);
  352. //addGrid(panel, new JSeparator(), 0, 3, 3, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  353. addGrid(panel, fProgressIndicator, 0, 3, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  354. addGrid(panel, fLogo, 2, 3, 1, GridBagConstraints.NONE, 0.0, GridBagConstraints.NORTH);
  355. addGrid(panel, fCounterPanel, 0, 4, 2, GridBagConstraints.NONE, 0.0, GridBagConstraints.WEST);
  356. addGrid(panel, new JSeparator(), 0, 5, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  357. addGrid(panel, new JLabel("Results:"), 0, 6, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.WEST);
  358. JSplitPane splitter= new JSplitPane(JSplitPane.VERTICAL_SPLIT, fTestViewTab, tracePane);
  359. addGrid(panel, splitter, 0, 7, 2, GridBagConstraints.BOTH, 1.0, GridBagConstraints.WEST);
  360. addGrid(panel, failedPanel, 2, 7, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.NORTH/*CENTER*/);
  361. addGrid(panel, fStatusLine, 0, 9, 2, GridBagConstraints.HORIZONTAL, 1.0, GridBagConstraints.CENTER);
  362. addGrid(panel, fQuitButton, 2, 9, 1, GridBagConstraints.HORIZONTAL, 0.0, GridBagConstraints.CENTER);
  363. frame.setContentPane(panel);
  364. frame.pack();
  365. frame.setLocation(200, 200);
  366. return frame;
  367. }
  368. private void addGrid(JPanel p, Component co, int x, int y, int w, int fill, double wx, int anchor) {
  369. GridBagConstraints c= new GridBagConstraints();
  370. c.gridx= x; c.gridy= y;
  371. c.gridwidth= w;
  372. c.anchor= anchor;
  373. c.weightx= wx;
  374. c.fill= fill;
  375. if (fill == GridBagConstraints.BOTH || fill == GridBagConstraints.VERTICAL)
  376. c.weighty= 1.0;
  377. c.insets= new Insets(y == 0 ? 10 : 0, x == 0 ? 10 : GAP, GAP, GAP);
  378. p.add(co, c);
  379. }
  380. protected String getSuiteText() {
  381. if (fSuiteCombo == null)
  382. return "";
  383. return (String)fSuiteCombo.getEditor().getItem();
  384. }
  385. public ListModel getFailures() {
  386. return fFailures;
  387. }
  388. public void insertUpdate(DocumentEvent event) {
  389. textChanged();
  390. }
  391. public void browseTestClasses() {
  392. TestCollector collector= createTestCollector();
  393. TestSelector selector= new TestSelector(fFrame, collector);
  394. if (selector.isEmpty()) {
  395. JOptionPane.showMessageDialog(fFrame, "No Test Cases found.\nCheck that the configured \'TestCollector\' is supported on this platform.");
  396. return;
  397. }
  398. selector.show();
  399. String className= selector.getSelectedItem();
  400. if (className != null)
  401. setSuite(className);
  402. }
  403. TestCollector createTestCollector() {
  404. String className= BaseTestRunner.getPreference(TESTCOLLECTOR_KEY);
  405. if (className != null) {
  406. Class collectorClass= null;
  407. try {
  408. collectorClass= Class.forName(className);
  409. return (TestCollector)collectorClass.newInstance();
  410. } catch(Exception e) {
  411. JOptionPane.showMessageDialog(fFrame, "Could not create TestCollector - using default collector");
  412. }
  413. }
  414. return new SimpleTestCollector();
  415. }
  416. private Image loadFrameIcon() {
  417. ImageIcon icon= (ImageIcon)getIconResource(BaseTestRunner.class, "smalllogo.gif");
  418. if (icon != null)
  419. return icon.getImage();
  420. return null;
  421. }
  422. private void loadHistory(JComboBox combo) throws IOException {
  423. BufferedReader br= new BufferedReader(new FileReader(getSettingsFile()));
  424. int itemCount= 0;
  425. try {
  426. String line;
  427. while ((line= br.readLine()) != null) {
  428. combo.addItem(line);
  429. itemCount++;
  430. }
  431. if (itemCount > 0)
  432. combo.setSelectedIndex(0);
  433. } finally {
  434. br.close();
  435. }
  436. }
  437. private File getSettingsFile() {
  438. String home= System.getProperty("user.home");
  439. return new File(home,".junitsession");
  440. }
  441. private void postInfo(final String message) {
  442. SwingUtilities.invokeLater(
  443. new Runnable() {
  444. public void run() {
  445. showInfo(message);
  446. }
  447. }
  448. );
  449. }
  450. private void postStatus(final String status) {
  451. SwingUtilities.invokeLater(
  452. new Runnable() {
  453. public void run() {
  454. showStatus(status);
  455. }
  456. }
  457. );
  458. }
  459. public void removeUpdate(DocumentEvent event) {
  460. textChanged();
  461. }
  462. private void rerun() {
  463. TestRunView view= (TestRunView)fTestRunViews.elementAt(fTestViewTab.getSelectedIndex());
  464. Test rerunTest= view.getSelectedTest();
  465. if (rerunTest != null)
  466. rerunTest(rerunTest);
  467. }
  468. private void rerunTest(Test test) {
  469. if (!(test instanceof TestCase)) {
  470. showInfo("Could not reload "+ test.toString());
  471. return;
  472. }
  473. Test reloadedTest= null;
  474. TestCase rerunTest= (TestCase)test;
  475. try {
  476. Class reloadedTestClass= getLoader().reload(test.getClass());
  477. reloadedTest= TestSuite.createTest(reloadedTestClass, rerunTest.getName());
  478. } catch(Exception e) {
  479. showInfo("Could not reload "+ test.toString());
  480. return;
  481. }
  482. TestResult result= new TestResult();
  483. reloadedTest.run(result);
  484. String message= reloadedTest.toString();
  485. if(result.wasSuccessful())
  486. showInfo(message+" was successful");
  487. else if (result.errorCount() == 1)
  488. showStatus(message+" had an error");
  489. else
  490. showStatus(message+" had a failure");
  491. }
  492. protected void reset() {
  493. fCounterPanel.reset();
  494. fProgressIndicator.reset();
  495. fRerunButton.setEnabled(false);
  496. fFailureView.clear();
  497. fFailures.clear();
  498. }
  499. protected void runFailed(String message) {
  500. showStatus(message);
  501. fRun.setText("Run");
  502. fRunner= null;
  503. }
  504. synchronized public void runSuite() {
  505. if (fRunner != null) {
  506. fTestResult.stop();
  507. } else {
  508. setLoading(shouldReload());
  509. reset();
  510. showInfo("Load Test Case...");
  511. final String suiteName= getSuiteText();
  512. final Test testSuite= getTest(suiteName);
  513. if (testSuite != null) {
  514. addToHistory(suiteName);
  515. doRunTest(testSuite);
  516. }
  517. }
  518. }
  519. private boolean shouldReload() {
  520. return !inVAJava() && fUseLoadingRunner.isSelected();
  521. }
  522. synchronized protected void runTest(final Test testSuite) {
  523. if (fRunner != null) {
  524. fTestResult.stop();
  525. } else {
  526. reset();
  527. if (testSuite != null) {
  528. doRunTest(testSuite);
  529. }
  530. }
  531. }
  532. private void doRunTest(final Test testSuite) {
  533. setButtonLabel(fRun, "Stop");
  534. fRunner= new Thread("TestRunner-Thread") {
  535. public void run() {
  536. TestRunner.this.start(testSuite);
  537. postInfo("Running...");
  538. long startTime= System.currentTimeMillis();
  539. testSuite.run(fTestResult);
  540. if (fTestResult.shouldStop()) {
  541. postStatus("Stopped");
  542. } else {
  543. long endTime= System.currentTimeMillis();
  544. long runTime= endTime-startTime;
  545. postInfo("Finished: " + elapsedTimeAsString(runTime) + " seconds");
  546. }
  547. runFinished(testSuite);
  548. setButtonLabel(fRun, "Run");
  549. fRunner= null;
  550. System.gc();
  551. }
  552. };
  553. // make sure that the test result is created before we start the
  554. // test runner thread so that listeners can register for it.
  555. fTestResult= createTestResult();
  556. fTestResult.addListener(TestRunner.this);
  557. aboutToStart(testSuite);
  558. fRunner.start();
  559. }
  560. private void saveHistory() throws IOException {
  561. BufferedWriter bw= new BufferedWriter(new FileWriter(getSettingsFile()));
  562. try {
  563. for (int i= 0; i < fSuiteCombo.getItemCount(); i++) {
  564. String testsuite= fSuiteCombo.getItemAt(i).toString();
  565. bw.write(testsuite, 0, testsuite.length());
  566. bw.newLine();
  567. }
  568. } finally {
  569. bw.close();
  570. }
  571. }
  572. private void setButtonLabel(final JButton button, final String label) {
  573. SwingUtilities.invokeLater(
  574. new Runnable() {
  575. public void run() {
  576. button.setText(label);
  577. }
  578. }
  579. );
  580. }
  581. public void handleTestSelected(Test test) {
  582. fRerunButton.setEnabled(test != null && (test instanceof TestCase));
  583. showFailureDetail(test);
  584. }
  585. private void showFailureDetail(Test test) {
  586. if (test != null) {
  587. ListModel failures= getFailures();
  588. for (int i= 0; i < failures.getSize(); i++) {
  589. TestFailure failure= (TestFailure)failures.getElementAt(i);
  590. if (failure.failedTest() == test) {
  591. fFailureView.showFailure(failure);
  592. return;
  593. }
  594. }
  595. }
  596. fFailureView.clear();
  597. }
  598. private void showInfo(String message) {
  599. fStatusLine.showInfo(message);
  600. }
  601. private void showStatus(String status) {
  602. fStatusLine.showError(status);
  603. }
  604. /**
  605. * Starts the TestRunner
  606. */
  607. public void start(String[] args) {
  608. String suiteName= processArguments(args);
  609. fFrame= createUI(suiteName);
  610. fFrame.pack();
  611. fFrame.setVisible(true);
  612. if (suiteName != null) {
  613. setSuite(suiteName);
  614. runSuite();
  615. }
  616. }
  617. private void start(final Test test) {
  618. SwingUtilities.invokeLater(
  619. new Runnable() {
  620. public void run() {
  621. int total= test.countTestCases();
  622. fProgressIndicator.start(total);
  623. fCounterPanel.setTotal(total);
  624. }
  625. }
  626. );
  627. }
  628. /**
  629. * Wait until all the events are processed in the event thread
  630. */
  631. private void synchUI() {
  632. try {
  633. SwingUtilities.invokeAndWait(
  634. new Runnable() {
  635. public void run() {}
  636. }
  637. );
  638. }
  639. catch (Exception e) {
  640. }
  641. }
  642. /**
  643. * Terminates the TestRunner
  644. */
  645. public void terminate() {
  646. fFrame.dispose();
  647. try {
  648. saveHistory();
  649. } catch (IOException e) {
  650. System.out.println("Couldn't save test run history");
  651. }
  652. System.exit(0);
  653. }
  654. public void textChanged() {
  655. fRun.setEnabled(getSuiteText().length() > 0);
  656. clearStatus();
  657. }
  658. protected void clearStatus() {
  659. fStatusLine.clear();
  660. }
  661. public static Icon getIconResource(Class clazz, String name) {
  662. URL url= clazz.getResource(name);
  663. if (url == null) {
  664. System.err.println("Warning: could not load \""+name+"\" icon");
  665. return null;
  666. }
  667. return new ImageIcon(url);
  668. }
  669. private void about() {
  670. AboutDialog about= new AboutDialog(fFrame);
  671. about.show();
  672. }
  673. }