1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2004, 2014, Oracle and/or its affiliates. All rights reserved.
   5  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   6  *
   7  * This code is free software; you can redistribute it and/or modify it
   8  * under the terms of the GNU General Public License version 2 only, as
   9  * published by the Free Software Foundation.  Oracle designates this
  10  * particular file as subject to the "Classpath" exception as provided
  11  * by Oracle in the LICENSE file that accompanied this code.
  12  *
  13  * This code is distributed in the hope that it will be useful, but WITHOUT
  14  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  16  * version 2 for more details (a copy is included in the LICENSE file that
  17  * accompanied this code).
  18  *
  19  * You should have received a copy of the GNU General Public License version
  20  * 2 along with this work; if not, write to the Free Software Foundation,
  21  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  22  *
  23  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  24  * or visit www.oracle.com if you need additional information or have any
  25  * questions.
  26  */
  27 package com.sun.javatest.exec;
  28 
  29 import java.awt.AWTEvent;
  30 import java.awt.BorderLayout;
  31 import java.awt.Color;
  32 import java.awt.Component;
  33 import java.awt.Container;
  34 import java.awt.Dimension;
  35 import java.awt.Font;
  36 import java.awt.GridBagConstraints;
  37 import java.awt.GridBagLayout;
  38 import java.awt.KeyboardFocusManager;
  39 import java.awt.Window;
  40 import java.awt.event.ActionEvent;
  41 import java.awt.event.ActionListener;
  42 import java.awt.event.KeyEvent;
  43 import java.io.BufferedInputStream;
  44 import java.io.File;
  45 import java.io.FileNotFoundException;
  46 import java.io.IOException;
  47 import java.io.InputStream;
  48 import java.io.FileInputStream;
  49 import java.net.URL;
  50 import java.util.Properties;
  51 import java.util.Set;
  52 import java.util.TreeSet;
  53 import java.util.Vector;
  54 import javax.swing.BorderFactory;
  55 import javax.swing.ButtonGroup;
  56 import javax.swing.Icon;
  57 import javax.swing.ImageIcon;
  58 import javax.swing.JButton;
  59 import javax.swing.JCheckBox;
  60 import javax.swing.JComboBox;
  61 import javax.swing.JComponent;
  62 import javax.swing.JDialog;
  63 import javax.swing.JFileChooser;
  64 import javax.swing.JInternalFrame;
  65 import javax.swing.JLabel;
  66 import javax.swing.JPanel;
  67 import javax.swing.JRadioButton;
  68 import javax.swing.JTextArea;
  69 import javax.swing.JTextField;
  70 import javax.swing.KeyStroke;
  71 import javax.swing.event.AncestorEvent;
  72 import javax.swing.event.AncestorListener;
  73 import javax.swing.event.ChangeEvent;
  74 import javax.swing.event.ChangeListener;
  75 import javax.swing.event.DocumentEvent;
  76 import javax.swing.event.DocumentListener;
  77 
  78 import com.sun.interview.Interview;
  79 import com.sun.javatest.Harness;
  80 import com.sun.javatest.InterviewParameters;
  81 import com.sun.javatest.ResourceLoader;
  82 import com.sun.javatest.TemplateUtilities;
  83 //import com.sun.javatest.TemplateUtilities;
  84 import com.sun.javatest.TestSuite;
  85 import com.sun.javatest.WorkDirectory;
  86 import com.sun.javatest.tool.FileChooser;
  87 import com.sun.javatest.tool.FileHistory;
  88 import com.sun.javatest.tool.TestSuiteChooser;
  89 import com.sun.javatest.tool.ToolDialog;
  90 import com.sun.javatest.tool.UIFactory;
  91 import com.sun.javatest.tool.WorkDirChooser;
  92 
  93 
  94 class QuickStartWizard extends ToolDialog
  95 {
  96     QuickStartWizard(JComponent parent, Icon logoIcon,
  97             QSW_Listener finisher,  UIFactory uif) {
  98         super(parent, uif, "qsw");
  99         this.logoIcon = logoIcon;
 100         this.qswListener = finisher;
 101     }
 102 
 103 
 104     protected void initGUI() {
 105         disableDefaultDisposeHandler();
 106         initDirs();
 107         initPanes();
 108 
 109         setHelp("qsw.window.csh");
 110         setI18NTitle("qsw.title");
 111 
 112         body = uif.createPanel("qsw.body", new BorderLayout(), false);
 113         body.setBorder(BorderFactory.createLoweredBevelBorder());
 114 
 115         /*
 116          *      *-----------------------+
 117          *      |       | head          |
 118          *      |       +---------------|
 119          *      |       |               |
 120          *      | logo  | question pane |
 121          *      |       |               |
 122          *      |       +---------------|
 123          *      |       | error         |
 124          *      |-------+---------------+
 125          *      |         buttons       |
 126          *      |-----------------------+
 127          */
 128 
 129         TestSuite ts;
 130         try {
 131             //System.err.println("QSG: installDirIsTestSuite=" + installDirIsTestSuite);
 132             //System.err.println("QSG: installParentDirIsTestSuite=" + installParentDirIsTestSuite);
 133             //System.err.println("QSG: userDirIsTestSuite=" + userDirIsTestSuite);
 134             if (installDirIsTestSuite)
 135                 ts = TestSuite.open(installDir);
 136             else if (installParentDirIsTestSuite)
 137                 ts = TestSuite.open(installParentDir);
 138             else if (userDirIsTestSuite)
 139                 ts = TestSuite.open(userDir);
 140             else
 141                 ts = null;
 142         }
 143         catch (Throwable e) {
 144             ts = null;
 145         }
 146 
 147         // logo...
 148         JLabel logo;
 149 
 150         URL tsLogoURL = (ts == null ? null : ts.getLogo());
 151         //System.err.println("QSG: tsLogoURL=" + tsLogoURL);
 152         if (tsLogoURL == null) {
 153             logo = new JLabel(logoIcon);
 154             logo.setName("qsw.jtlogo");
 155             logo.setBackground(uif.getI18NColor("qsw.jtlogo.bg"));
 156             uif.setAccessibleInfo(logo, "qsw.jtlogo");
 157         }
 158         else {
 159             logo = new JLabel(new ImageIcon(tsLogoURL));
 160             logo.setName("qsw.tslogo");
 161             logo.setBackground(Color.white);
 162             // the following comments are to keep the i18n checker happy
 163             // getI18NString("qsw.tslogo.desc")
 164             // getI18NString("qsw.tslogo.name")
 165             uif.setAccessibleInfo(logo, "qsw.tslogo");
 166         }
 167         logo.setOpaque(true);
 168         logo.setFocusable(false); // mildly questionable, but it can't take/show focus
 169         body.add(logo, BorderLayout.WEST);
 170 
 171         main = uif.createPanel("qsw.main", new BorderLayout(), false);
 172         main.setBorder(BorderFactory.createEmptyBorder(20, 20, 0, 11));
 173         head = uif.createOutputField("qsw.head");
 174         head.setBorder(null);
 175         head.setFont(head.getFont().deriveFont(Font.BOLD));
 176         main.add(head, BorderLayout.NORTH);
 177 
 178         foot = uif.createOutputField("qsw.foot");
 179         foot.setBorder(null);
 180         foot.setFont(foot.getFont().deriveFont(Font.BOLD));
 181         foot.setForeground(uif.getI18NColor("qsw.foot"));
 182         main.add(foot, BorderLayout.SOUTH);
 183 
 184         body.add(main, BorderLayout.CENTER);
 185 
 186         setBody(body);
 187 
 188         backBtn = uif.createButton("qsw.back", listener);
 189         nextBtn = uif.createButton("qsw.next", listener);
 190         doneBtn = uif.createButton("qsw.done", listener);
 191         JButton cancelBtn = uif.createCancelButton("qsw.cancel");
 192         cancelBtn.addActionListener(new ActionListener() {
 193             public void actionPerformed(ActionEvent e) {
 194                 closeExecTool(e);
 195             }
 196 
 197         });
 198         setPane(taskPane);
 199         setButtons(new JButton[] { backBtn, nextBtn, doneBtn, cancelBtn }, null);
 200         setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE);
 201 
 202     }
 203 
 204     private void closeExecTool(AWTEvent ev) {
 205 
 206         Component src = (Component) ev.getSource();
 207         for (Container p = src.getParent(); p != null; p = p.getParent()) {
 208             if (p instanceof JInternalFrame || p instanceof Window &&  p.getParent() != null) {
 209                 p.setVisible(false);
 210                 break;
 211             }
 212         }
 213         qswListener.cancelQSW();
 214         // tool.getDesktop().removeTool(tool1);
 215         // tool.dispose();
 216     }
 217 
 218     private void initDirs() {
 219         File classDir = Harness.getClassDir();
 220         installDir = (classDir == null ? null : classDir.getParentFile());
 221         installDirIsTestSuite = (installDir == null ? false : TestSuite.isTestSuite(installDir));
 222         installParentDir = (installDir == null ? null : installDir.getParentFile());
 223         installParentDirIsTestSuite = (installParentDir == null ? false : TestSuite.isTestSuite(installParentDir));
 224 
 225         userDir = new File(System.getProperty("user.dir"));
 226         userDirIsTestSuite = (userDir == null ? false : TestSuite.isTestSuite(userDir));
 227         userDirIsWorkDirectory = (userDir == null ? false : WorkDirectory.isWorkDirectory(userDir));
 228     }
 229 
 230     private void initPanes() {
 231         taskPane = new TaskPane();
 232         configPane = new ConfigPane();
 233         testSuitePane = new TestSuitePane();
 234         newWorkDirPane = new CreateWorkDirPane();
 235         openWorkDirPane = new OpenWorkDirPane();
 236         endPane = new EndPane();
 237     }
 238 
 239     private void setPane(Pane p) {
 240         if (currPane != null)
 241             main.remove(currPane);
 242 
 243         p.update();
 244         head.setText(p.getHead());
 245         main.add(p, BorderLayout.CENTER);
 246         showError(null);
 247         backBtn.setEnabled(history.size() > 0);
 248         p.updateNextButton();
 249         doneBtn.setEnabled(p == endPane);
 250         currPane = p;
 251 
 252         main.validate();
 253         main.repaint();
 254     }
 255 
 256     private void showError(String key) {
 257         if (key == null) {
 258             foot.setText("");
 259             foot.setEnabled(false);
 260             foot.setVisible(false);
 261         }
 262         else {
 263             foot.setText(uif.getI18NString(key));
 264             foot.setEnabled(true);
 265             foot.setVisible(true);
 266             nextBtn.setEnabled(false);
 267         }
 268     }
 269 
 270     private void doBack() {
 271         int n = history.size();
 272         if (n > 0) {
 273             Pane p = (Pane) (history.remove(n - 1));
 274             setPane(p);
 275         }
 276     }
 277 
 278     private void doNext() {
 279         Pane p = currPane.getNext();
 280         if (p != null) {
 281             history.add(currPane);
 282             setPane(p);
 283         }
 284     }
 285 
 286     boolean checkSingleTestManager() {
 287         /*
 288         if (contextManager != null) {
 289             ExecToolManager em = tool.getExecToolManager();
 290             Desktop d = em.getDesktop();
 291             if(!em.checkOpenNewTool(d, contextManager)) {
 292                 return false;
 293             }
 294         }
 295          */
 296         return true;
 297 
 298     }
 299 
 300     private void doDone() {
 301         setVisible(false);
 302         if (config == null)
 303             throw new IllegalStateException();
 304 
 305         if (workDir != null)
 306             config.setWorkDirectory(workDir);
 307 
 308         qswListener.finishQSW(testSuite, workDir, config,
 309                 showConfigEditorFlag, runTestsFlag);
 310 
 311 /*
 312         tool.setInterviewParameters(config);
 313 
 314         if (showConfigEditorFlag)
 315             tool.showConfigEditor(runTestsFlag);
 316         else if (runTestsFlag)
 317             tool.runTests();
 318 */
 319     }
 320 
 321 
 322     //private ExecTool tool;
 323 
 324     private Pane currPane;
 325     private Pane taskPane;
 326     private ConfigPane configPane;
 327     private Pane testSuitePane;
 328     private Pane newWorkDirPane;
 329     private Pane openWorkDirPane;
 330     private Pane endPane;
 331 
 332     private int task;
 333     private static final int UNSET = 0, NEW = 1, RESUME = 2, BROWSE = 3;
 334     // indicates using jtm or jti templates
 335     private boolean jtmTemplate = true;
 336 
 337     private Properties configData;
 338     private File configFile;
 339     private Properties jtmData;
 340     private File jtmFile;
 341 
 342     private QSW_Listener qswListener;
 343     private Icon logoIcon;
 344     private InterviewParameters config;
 345     private ContextManager contextManager;
 346     private TestSuite testSuite;
 347     private WorkDirectory workDir;
 348     private boolean showConfigEditorFlag;
 349     private boolean runTestsFlag;
 350 
 351     private File installDir;
 352     private File installParentDir;
 353     private boolean installDirIsTestSuite;
 354     private boolean installParentDirIsTestSuite;
 355     private File userDir;
 356     private boolean userDirIsTestSuite;
 357     private boolean userDirIsWorkDirectory;
 358 
 359     private JPanel body;
 360     private JPanel main;
 361     private JTextField head;
 362     private JTextField foot;
 363     private JButton backBtn;
 364     private JButton nextBtn;
 365     private JButton doneBtn;
 366     private Listener listener = new Listener();
 367     private KeyStroke enterKey = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0);
 368     private Vector history = new Vector();
 369     private boolean allowConfigLoadOutsideDefault;
 370     private File defaultConfigSavePath;
 371     private boolean allowConfigSaveOutsideDefault;
 372     private File defaultConfigLoadPath;
 373 
 374     /**
 375      * This is the name of system property to turn QuickStartWizard off.
 376      * You should specify "true" value for this property to disable
 377      * QuickStartWizard.
 378      */
 379     static final String QSW_OFF_PROPERTY = "com.sun.javatest.qswDisabled";
 380 
 381     static final String QSW_OFF_FILE = "qswDisabled";
 382 
 383     private static final boolean qswDisabled = initQSWDisabled();
 384 
 385     static boolean isQswDisabled() {
 386         return qswDisabled;
 387     }
 388 
 389     /**
 390      * @return true, if disable
 391      */
 392     private static boolean initQSWDisabled() {
 393         if (Boolean.parseBoolean(System.getProperty(QSW_OFF_PROPERTY))) {
 394             return true;
 395         }
 396         try {
 397             return ResourceLoader.getResourceFile(QSW_OFF_FILE, null) != null;
 398         } catch (Exception ignore) {
 399             return false;
 400         }
 401     }
 402 
 403     private class Listener implements ActionListener
 404     {
 405         public void actionPerformed(ActionEvent e) {
 406             Object src = e.getSource();
 407             if (src == nextBtn)
 408                 doNext();
 409             else if (src == backBtn)
 410                 doBack();
 411             else if (src == doneBtn)
 412                 doDone();
 413             else
 414                 System.err.println("QSG.Listener " + e);
 415         }
 416     }
 417 
 418     private class FilePanel extends JPanel {
 419 
 420         FilePanel(String key, final JFileChooser chooser) {
 421             uif.initPanel(this, key, new BorderLayout(), false);
 422 
 423             label = uif.createLabel(key, true);
 424 
 425             field = uif.createInputField(key, label);
 426             currPathComp = field;
 427 
 428             button = uif.createButton(key + ".browse");
 429             button.addActionListener(new ActionListener() {
 430                     public void actionPerformed(ActionEvent e) {
 431                         // seed the path if the user has started to enter
 432                         // something
 433                         String path = getPath();
 434                         if (chooser instanceof FileChooser  &&
 435                                 ((FileChooser)chooser).getChosenExtension() != null &&
 436                                 ((FileChooser)chooser).getChosenExtension().equals(".jti")) {
 437 
 438                             File f = InterviewEditor.loadConfigFile(
 439                                 contextManager, parent, uif,
 440                                 (FileChooser)chooser);
 441                             path = (f == null ? null : f.getPath());
 442                         }
 443                         else {
 444                             // set chooser to value in field?
 445                             if (path != null && path.length() > 0)
 446                                 chooser.setSelectedFile(new File(path));
 447 
 448                             int rc = chooser.showDialog(body, chooser.getApproveButtonText());
 449                             if (rc != JFileChooser.APPROVE_OPTION)
 450                                 return;
 451 
 452                             path = chooser.getSelectedFile().getPath();
 453                         }
 454 
 455                         field.setText(path);
 456                         if (combo != null)
 457                                 combo.setSelectedItem(path);
 458                     }
 459                 });
 460 
 461             add(label, BorderLayout.WEST);
 462             add(field, BorderLayout.CENTER); // default, may be changed to combo
 463             add(button, BorderLayout.EAST);
 464         }
 465 
 466         public void setEnabled(boolean b) {
 467             super.setEnabled(b);
 468             label.setEnabled(b);
 469             currPathComp.setEnabled(b);
 470             button.setEnabled(b);
 471         }
 472 
 473         void setSuggestions(String[] suggestions) {
 474             if (suggestions == null || suggestions.length == 0)
 475                 setPathComponent(field);
 476             else {
 477                 if (combo == null) {
 478                     combo = uif.createChoice(getName()/*key*/, true, label);
 479                     //combo.setEditable(true);
 480                     combo.setFont(combo.getFont().deriveFont(Font.PLAIN));
 481                     if (listener != null) {
 482                         // would be better to use editor addActionListener
 483                         Component c = combo.getEditor().getEditorComponent();
 484                         if (c instanceof JTextField)
 485                             ((JTextField) c).getDocument().addDocumentListener(listener);
 486                     }
 487                 }
 488                 setPathComponent(combo);
 489                 combo.removeAllItems();
 490                 for (int i = 0; i < suggestions.length; i++)
 491                     combo.addItem(suggestions[i]);
 492             }
 493         }
 494 
 495         /**
 496          * @return Null if no file path was provided, or if the given path is
 497          * rejected due to validation reasons.
 498          */
 499         File getFile() {
 500             String path = getPath();
 501             return (path == null || path.length() == 0 ? null : new File(path));
 502         }
 503 
 504         String getPath() {
 505             //System.err.println("QSG.FP.getPath currComp=" + currPathComp);
 506             //System.err.println("QSG.FP.getPath combo.selectedItem=" + (combo == null ? "null" : String.valueOf(combo.getSelectedItem())));
 507             if (currPathComp == field)
 508                 return field.getText();
 509             else if (currPathComp == combo) {
 510                 Component c = combo.getEditor().getEditorComponent();
 511                 if (c.isShowing() && c instanceof JTextField)
 512                     return ((JTextField) c).getText();
 513                 else
 514                     return ((String) (combo.getSelectedItem()));
 515             }
 516             else
 517                 throw new IllegalStateException();
 518         }
 519 
 520         void setDocumentListener(DocumentListener l) {
 521             field.getDocument().addDocumentListener(l);
 522             listener = l;
 523         }
 524 
 525         private void setPathComponent(JComponent newPathComp) {
 526             //System.err.println("QSG.FP.setPathComponent " + newPathComp);
 527             if (newPathComp != currPathComp) {
 528                 if (currPathComp != null)
 529                     remove(currPathComp);
 530                 add(newPathComp, BorderLayout.CENTER);
 531                 newPathComp.setEnabled(isEnabled());
 532                 label.setLabelFor(newPathComp);
 533                 currPathComp = newPathComp;
 534             }
 535         }
 536 
 537         private JLabel label;
 538         private JTextField field;
 539         private JComboBox combo;
 540         private JComponent currPathComp;
 541         private JButton button;
 542         private DocumentListener listener;
 543     }
 544 
 545     private abstract class Pane extends JPanel {
 546         Pane(String key) {
 547             paneKey = key;
 548             setLayout(new GridBagLayout());
 549             int dpi = uif.getDotsPerInch();
 550             setPreferredSize(new Dimension(5 * dpi, (int) (2.5 * dpi)));
 551             head = uif.getI18NString(paneKey + ".hd");
 552         }
 553 
 554         void stateChanged() { }
 555 
 556         String getHead() {
 557             return head;
 558         }
 559 
 560         void update() {
 561             updateNextButton();
 562         }
 563 
 564         abstract void updateNextButton();
 565 
 566         Pane getNext() {
 567             return null;
 568         }
 569 
 570         JCheckBox addCheck(String key) {
 571             JCheckBox cb = uif.createCheckBox(paneKey + "." + key);
 572             cb.addChangeListener(changeListener);
 573 
 574             GridBagConstraints c = new GridBagConstraints();
 575             c.fill = GridBagConstraints.HORIZONTAL;
 576             c.gridwidth = GridBagConstraints.REMAINDER;
 577             c.insets.left = 10;
 578             c.insets.bottom = 5;
 579             c.weightx = 1;
 580             add(cb, c);
 581 
 582             return cb;
 583         }
 584 
 585         JRadioButton addChoice(String key, ButtonGroup bg) {
 586             JRadioButton rb = uif.createRadioButton(paneKey + "." + key, bg);
 587             rb.addChangeListener(changeListener);
 588 
 589             GridBagConstraints c = new GridBagConstraints();
 590             c.fill = GridBagConstraints.HORIZONTAL;
 591             c.gridwidth = GridBagConstraints.REMAINDER;
 592             c.insets.left = 10;
 593             c.insets.bottom = 5;
 594             c.weightx = 1;
 595             add(rb, c);
 596 
 597             return rb;
 598         }
 599 
 600         FilePanel addFile(String key, JFileChooser chooser) {
 601             return addFile(key, chooser, null);
 602         }
 603 
 604         FilePanel addFile(String key, final JFileChooser chooser, final JRadioButton rb) {
 605             final FilePanel fp = new FilePanel(paneKey + "." + key, chooser);
 606 
 607             GridBagConstraints c = new GridBagConstraints();
 608             c.fill = GridBagConstraints.HORIZONTAL;
 609             c.gridwidth = GridBagConstraints.REMAINDER;
 610             c.insets.bottom = 10;
 611             c.insets.left = (rb == null ? 0 : 30);
 612             c.weightx = 1;
 613             add(fp, c);
 614 
 615             if (rb != null) {
 616                 fp.addAncestorListener(new AncestorListener() {
 617                         public void ancestorAdded(AncestorEvent e) {
 618                             fp.setEnabled(rb.isSelected());
 619                         }
 620                         public void ancestorMoved(AncestorEvent e) { }
 621                         public void ancestorRemoved(AncestorEvent e) { }
 622                     });
 623                 rb.addChangeListener(new ChangeListener() {
 624                         public void stateChanged(ChangeEvent e) {
 625                             fp.setEnabled(rb.isSelected());
 626                         }
 627                     });
 628             }
 629 
 630             fp.setDocumentListener(new DocumentListener() {
 631                     public void changedUpdate(DocumentEvent e) {
 632                         changeListener.stateChanged(new ChangeEvent(fp));
 633                     }
 634                     public void insertUpdate(DocumentEvent e) {
 635                         changedUpdate(e);
 636                     }
 637                     public void removeUpdate(DocumentEvent e) {
 638                         changedUpdate(e);
 639                     }
 640                 });
 641 
 642             return fp;
 643         }
 644 
 645         JTextArea addText() {
 646             return addText(true);
 647         }
 648 
 649         JTextArea addText(boolean initContent) {
 650             // text area...
 651             JTextArea textArea = uif.createTextArea("qsw.text");
 652             textArea.setEditable(false);
 653             textArea.setLineWrap(true);
 654             textArea.setOpaque(false);
 655             textArea.setBackground(UIFactory.Colors.TRANSPARENT.getValue());
 656             textArea.setWrapStyleWord(true);
 657             // override JTextArea focus traversal keys, resetting them to
 658             // the Component default (i.e. the same as for the parent.)
 659             textArea.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS, null);
 660             textArea.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS, null);
 661             if (initContent)
 662                 textArea.setText(uif.getI18NString(paneKey + ".txt"));
 663             /*
 664               // set enter to be same as Next
 665               {
 666               InputMap im = textArea.getInputMap();
 667               im.put(enterKey, "next");
 668               ActionMap am = textArea.getActionMap();
 669               am.put("next", valueAction);
 670               }
 671             */
 672             GridBagConstraints c = new GridBagConstraints();
 673             c.gridwidth = GridBagConstraints.REMAINDER;
 674             c.insets.top = 20;
 675             c.insets.right = 10;
 676             c.insets.bottom = 10;
 677             c.fill = GridBagConstraints.BOTH;
 678             add(textArea, c);
 679             return textArea;
 680         }
 681 
 682         private ChangeListener changeListener = new ChangeListener() {
 683                 public void stateChanged(ChangeEvent e) {
 684                     Pane.this.stateChanged();
 685                 }
 686             };
 687 
 688         private String paneKey;
 689         private String head;
 690     };
 691 
 692     //------------------------------------------------------------------------------
 693 
 694     private class TaskPane extends Pane {
 695         TaskPane() {
 696             super("qsw.tsk");
 697             addText();
 698             newRun = addChoice("new", bg);
 699             resumeRun = addChoice("resume", bg);
 700             browse = addChoice("browse", bg);
 701         }
 702 
 703         void stateChanged() {
 704             task = (newRun.isSelected() ? NEW
 705                     : resumeRun.isSelected() ? RESUME
 706                     : browse.isSelected() ? BROWSE
 707                     : UNSET);
 708             updateNextButton();
 709         }
 710 
 711         void updateNextButton() {
 712             nextBtn.setEnabled(task != UNSET);
 713         }
 714 
 715 
 716         Pane getNext() {
 717 
 718             return (task == NEW || task == BROWSE ? (Pane) testSuitePane
 719                     : task == RESUME ? (Pane) openWorkDirPane
 720                     : null);
 721         }
 722 
 723 
 724         private ButtonGroup bg = new ButtonGroup();
 725         private JRadioButton newRun;
 726         private JRadioButton resumeRun;
 727         private JRadioButton browse;
 728     };
 729 
 730     //------------------------------------------------------------------------------
 731 
 732     private class ConfigPane extends Pane  {
 733         ConfigPane() {
 734             super("qsw.cfg");
 735             addText();
 736             jtiChooser = new FileChooser(true);
 737             jtiChooser.addChoosableExtension(".jti",
 738                                           uif.getI18NString("qsw.cfg.jtiFiles"));
 739 
 740             jtmChooser = new FileChooser(true);
 741             jtmChooser.setDialogTitle(uif.getI18NString("qsw.cfg.jtmChooser.title"));
 742             jtmChooser.addChoosableExtension(".jtm",
 743                                           uif.getI18NString("qsw.cfg.jtmFiles"));
 744 
 745             newConfig = addChoice("new", bg);
 746             jtmConfig = addChoice("template", bg);
 747             jtmPanel = addFile("jtm.field", jtmChooser, jtmConfig);
 748 
 749         }
 750 
 751 
 752         void tuneTemplateFilter() {
 753             if (contextManager != null &&
 754                     contextManager.getFeatureManager() != null &&
 755                     contextManager.getFeatureManager().isEnabled(FeatureManager.WD_WITHOUT_TEMPLATE) ) {
 756                 jtmChooser.addChoosableExtension(".jti",
 757                                               uif.getI18NString("qsw.cfg.jtiFiles"));
 758             }
 759         }
 760 
 761 
 762         private void tunePane() {
 763 
 764             if (contextManager != null) {
 765 
 766                 jtmChooser.setCurrentDirectory(contextManager.getDefaultTemplateLoadPath());
 767 
 768                 if (contextManager.getFeatureManager() != null) {
 769                     FeatureManager fm = contextManager.getFeatureManager();
 770                     jtmConfig.setEnabled(fm.isEnabled(FeatureManager.TEMPLATE_USAGE));
 771                     newConfig.setEnabled(fm.isEnabled(FeatureManager.WD_WITHOUT_TEMPLATE));
 772                 }
 773             }
 774         }
 775 
 776 
 777         void stateChanged() {
 778             showError(null);
 779             updateNextButton();
 780         }
 781 
 782 
 783         void updateNextButton() {
 784 
 785             tunePane();
 786 
 787             if (newConfig.isSelected()) {
 788                 nextBtn.setEnabled(true);
 789             } else if (jtmConfig.isSelected()) {
 790                 File f = jtmPanel.getFile();
 791                 nextBtn.setEnabled(f != null && f.exists() && f.isFile());
 792             }
 793             else
 794                 nextBtn.setEnabled(false);
 795         }
 796 
 797         Pane getNext() {
 798             if (bg.getSelection() == null)
 799                 return null;
 800 
 801             if (newConfig.isSelected()) {
 802                 configData = null;
 803                 configFile = null;
 804                 jtmData = null;
 805                 jtmFile = null;
 806             } else if (jtmConfig.isSelected()) {
 807                 jtmData = new Properties();
 808                 jtmFile = chkConfigFile(jtmPanel, jtmData);
 809                 if (jtmFile == null) {
 810                     return null;
 811                 }
 812 
 813                 if (jtmData != null) {
 814                     String jtmDataInterview = (String) (jtmData.get("INTERVIEW"));
 815 
 816                     if (jtmDataInterview != null
 817                         && !config.getClass().getName().equals(jtmDataInterview)) {
 818                         uif.showError("qsw.ts.templateMismatch");
 819                         return null;
 820                     }
 821 
 822                     jtmTemplate = Boolean.parseBoolean((String)jtmData.get("IS_TEMPLATE"));
 823 
 824                     if (config != null) {
 825                         try {
 826                             if (jtmTemplate) {
 827                                 testSuite.loadInterviewFromTemplate(jtmFile, config);
 828                                 config.setTemplatePath(jtmFile.getAbsolutePath());
 829                             } else {
 830                                 config.load(jtmFile);
 831                             }
 832                         } catch (TestSuite.Fault ex) {
 833                             // todo
 834                             ex.printStackTrace();
 835                         } catch (IOException ex) {
 836                             // todo
 837                             ex.printStackTrace();
 838                         } catch (Interview.Fault ex) {
 839                             uif.showError("qsw.ts.cantLoadConfig", ex.getMessage());
 840                             return null;
 841                         }
 842                     }
 843                 }
 844 
 845                 return (task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);
 846             }
 847 
 848 
 849 
 850             if (configData != null) {
 851                 String configDataInterview = (String) (configData.get("INTERVIEW"));
 852 
 853                 if (configDataInterview != null
 854                     && !config.getClass().getName().equals(configDataInterview)) {
 855                     uif.showError("qsw.ts.configMismatch");
 856                     return null;
 857                 }
 858 
 859                 try {
 860                     config.load(configData, configFile);
 861                 }
 862                 catch (InterviewParameters.Fault e) {
 863                     uif.showError("qsw.ts.cantLoadConfig", e.getMessage());
 864                     return null;
 865                 }
 866             }
 867 
 868             return (config == null ? null : task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);
 869 
 870         }
 871 
 872 
 873         private File chkConfigFile(FilePanel panel, Properties data ) {
 874             String path = panel.getPath();
 875             File file = null;
 876             if (path.length() == 0) {
 877                 showError("qsw.cfg.noFile");
 878                 return null;
 879             }
 880 
 881             File f = new File(path);
 882             if (!f.exists()) {
 883                 showError("qsw.cfg.cantFindFile");
 884                 return null;
 885             }
 886 
 887             if (!f.isFile()) {
 888                 showError("qsw.cfg.badFile");
 889                 return null;
 890             }
 891 
 892             try {
 893                 InputStream in = new BufferedInputStream(new FileInputStream(f));
 894 
 895                 try {
 896                     data.clear();
 897                     data.load(in);
 898                     file = f;
 899                 }
 900                 catch (RuntimeException e) {
 901                         // can get IllegalArgumentException if the file is corrupt
 902                     uif.showError("qsw.cfg.cantReadFile", e);
 903                 return null;
 904                 }
 905                 finally {
 906                     in.close();
 907                 }
 908             }
 909             catch (IOException e) {
 910                 uif.showError("qsw.cfg.cantReadFile", e);
 911                 return null;
 912             }
 913 
 914             return file;
 915         }
 916 
 917         private ButtonGroup bg = new ButtonGroup();
 918         private JRadioButton newConfig;
 919         private JRadioButton fileConfig;
 920         private JRadioButton jtmConfig;
 921         private FilePanel filePanel;
 922         private FilePanel jtmPanel;
 923         private FileChooser jtiChooser;
 924         private FileChooser jtmChooser;
 925 
 926         private long configLastModified;
 927 
 928     };
 929 
 930     //------------------------------------------------------------------------------
 931 
 932     private class TestSuitePane extends Pane {
 933         TestSuitePane() {
 934             super("qsw.ts");
 935             addText();
 936             chooser = new TestSuiteChooser();
 937             testSuitePanel = addFile("file", chooser);
 938         }
 939 
 940         void stateChanged() {
 941             showError(null);
 942             updateNextButton();
 943         }
 944 
 945         void update() {
 946             super.update();
 947 
 948             // update file with suggestions based on -
 949             // - config template
 950             // - installation directory and its parent
 951             // - current directory
 952 
 953             Set s = new TreeSet();
 954             if (configData != null) {
 955                 String configTestSuite = (String) (configData.get("TESTSUITE"));
 956                 if (configTestSuite != null)
 957                     s.add(configTestSuite);
 958             }
 959 
 960             if (userDirIsTestSuite)
 961                 s.add(userDir.getPath());
 962 
 963             if (installDirIsTestSuite)
 964                 s.add(installDir.getPath());
 965 
 966             if (installParentDirIsTestSuite)
 967                 s.add(installParentDir.getPath());
 968 
 969             if (s.size() > 0)
 970                 testSuitePanel.setSuggestions((String[]) (s.toArray(new String[s.size()])));
 971         }
 972 
 973         void updateNextButton() {
 974             File file = testSuitePanel.getFile();
 975             TestSuite chooserTestSuite = chooser.getSelectedTestSuite();
 976 
 977             if (file == null) {
 978                 nextBtn.setEnabled(false);
 979             }
 980             else if (chooserTestSuite != null && chooserTestSuite.getRoot().equals(file)) {
 981                 nextBtn.setEnabled(true);
 982             }
 983             else {
 984                 nextBtn.setEnabled(TestSuite.isTestSuite(file));
 985             }
 986         }
 987 
 988         Pane getNext() {
 989             // update test suite and check validity?
 990             // if ts == chooser.getSelectedFile, use chooser.getSelectedTestSuite
 991             File file = testSuitePanel.getFile();
 992             if (file == null) {
 993                 showError("qsw.ts.noFile");
 994                 return null;
 995             }
 996             else if (testSuite == null || !testSuite.getRoot().equals(file) || config == null) {
 997                 try {
 998                     TestSuite chooserTestSuite = chooser.getSelectedTestSuite();
 999                     if (chooserTestSuite != null
1000                         && chooserTestSuite.getRoot().equals(file))
1001                         testSuite = chooserTestSuite;
1002                     else
1003                         testSuite = TestSuite.open(file);
1004                 }
1005                 catch (FileNotFoundException e) {
1006                     showError("qsw.ts.cantFindFile");
1007                     return null;
1008                 }
1009                 catch (TestSuite.Fault e) {
1010                     uif.showError("qsw.ts.cantOpen",
1011                                   new Object[] { file, e.getMessage() });
1012                     return null;
1013                 }
1014 
1015                 // now that test suite is set, try to update config too
1016                 try {
1017                     if (config != null) {
1018                         config.dispose();
1019                     }
1020                     config = testSuite.createInterview();
1021                 }
1022                 catch (TestSuite.Fault e) {
1023                     uif.showError("qsw.ts.cantCreateInterview", e.getMessage());
1024                     return null;
1025                 }
1026                 catch (Throwable t) {
1027                     uif.showError("qsw.ts.cantCreateInterview", t.toString());
1028                     return null;
1029                 }
1030 
1031             }
1032 
1033             if (testSuite != null) {
1034                 contextManager = ExecTool.createContextManager(testSuite);
1035             }
1036             configPane.tuneTemplateFilter();
1037 
1038             if (!checkSingleTestManager()) {
1039                 return null;
1040             }
1041 
1042 
1043             return (task == NEW || task == BROWSE ? (Pane) configPane
1044                     : task == RESUME ? (Pane) openWorkDirPane
1045                     : null);
1046 
1047            // return (config == null ? null : task == NEW ? (Pane) newWorkDirPane : (Pane) endPane);
1048         }
1049 
1050         private FilePanel testSuitePanel;
1051         private TestSuiteChooser chooser;
1052     };
1053 
1054     //------------------------------------------------------------------------------
1055 
1056     private abstract class WorkDirPane extends Pane {
1057         WorkDirPane(String key) {
1058             super(key);
1059             textArea = addText();
1060             chooser = new WorkDirChooser(true);
1061             workDirPanel = addFile("file", chooser);
1062         }
1063 
1064         protected final JTextArea textArea;
1065         protected final FilePanel workDirPanel;
1066         protected WorkDirChooser chooser;
1067     };
1068 
1069     private class CreateWorkDirPane extends WorkDirPane {
1070         CreateWorkDirPane() {
1071             super("qsw.nwd");
1072             chooser.setMode(WorkDirChooser.NEW);
1073         }
1074 
1075         void stateChanged() {
1076             updateNextButton();
1077         }
1078 
1079         public void update() {
1080             chooser.setTestSuite(testSuite);
1081         }
1082 
1083         void updateNextButton() {
1084             String path = workDirPanel.getPath();
1085             nextBtn.setEnabled(path != null && path.length() > 0);
1086         }
1087 
1088         Pane getNext() {
1089             File file = workDirPanel.getFile();
1090 
1091             if (file == null) {
1092                 showError("qsw.nwd.noFile");
1093                 return null;
1094             }
1095             else if (workDir == null || !workDir.getRoot().equals(file)) {
1096                 try {
1097                     WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();
1098                     if (chooserWorkDir != null && canonicalEquals(chooserWorkDir.getRoot(), file)) {
1099                         // workdir was created inside the chooser
1100                         workDir = chooserWorkDir;
1101                     }
1102                     else
1103                         workDir = WorkDirectory.create(file, testSuite);
1104 
1105                     if (jtmFile != null && workDir != null && jtmTemplate) {
1106                         TemplateUtilities.setTemplateFile(workDir, jtmFile, true);
1107                         //tool.setWorkDir(workDir, true);
1108                         //tool.getConfigHandler().loadConfigNoUI(jtmFile);
1109                     }
1110 
1111                 }
1112                 catch (WorkDirectory.Fault e) {
1113                     uif.showError("qsw.nwd.cantCreate",
1114                                   new Object[] { file, e.getMessage() });
1115                     return null;
1116                 } catch (IOException ex) {
1117                     ex.printStackTrace();
1118                 }
1119             }
1120 
1121             return endPane;
1122         }
1123     };
1124 
1125     private static boolean canonicalEquals(File f1, File f2) {
1126         try {
1127             File c1 = f1.getCanonicalFile();
1128             File c2 = f2.getCanonicalFile();
1129             return (c1.equals(c2));
1130         }
1131         catch (IOException e) {
1132             return false;
1133         }
1134     }
1135 
1136     private class OpenWorkDirPane extends WorkDirPane {
1137         OpenWorkDirPane() {
1138             super("qsw.owd");
1139             chooser.setMode(WorkDirChooser.OPEN_FOR_ANY_TESTSUITE);
1140 
1141             if (userDirIsWorkDirectory)
1142                 workDirPanel.setSuggestions(new String[] { userDir.getPath() });
1143         }
1144 
1145         void stateChanged() {
1146             updateNextButton();
1147         }
1148 
1149         void updateNextButton() {
1150             File file = workDirPanel.getFile();
1151             WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();
1152 
1153             if (file == null)
1154                 nextBtn.setEnabled(false);
1155             else if (chooserWorkDir != null && chooserWorkDir.getRoot().equals(file))
1156                 nextBtn.setEnabled(true);
1157             else
1158                 nextBtn.setEnabled(WorkDirectory.isWorkDirectory(file));
1159         }
1160 
1161         Pane getNext() {
1162             File file = workDirPanel.getFile();
1163 
1164             if (file == null) {
1165                 showError("qsw.owd.noFile");
1166                 return null;
1167             }
1168             else if (workDir == null || !workDir.getRoot().equals(file)) {
1169                 try {
1170                     WorkDirectory chooserWorkDir = chooser.getSelectedWorkDirectory();
1171                     if (chooserWorkDir != null
1172                         && chooserWorkDir.getRoot().equals(file))
1173                         workDir = chooserWorkDir;
1174                     else
1175                         workDir = WorkDirectory.open(file);
1176                     testSuite = workDir.getTestSuite();
1177                 }
1178                 catch (FileNotFoundException e) {
1179                     showError("qsw.owd.cantFindFile");
1180                     return null;
1181                 }
1182                 catch (WorkDirectory.Fault e) {
1183                     uif.showError("qsw.owd.cantOpen",
1184                                   new Object[] { file, e.getMessage() });
1185                     return null;
1186                 }
1187 
1188                 try {
1189                     if (config != null) {
1190                         config.dispose();
1191                     }
1192                     config = testSuite.createInterview();
1193                     // should get latest config for workDir
1194                 }
1195                 catch (TestSuite.Fault e) {
1196                     uif.showError("qsw.owd.createCreateInterview", e.getMessage());
1197                     return null;
1198                 }
1199 
1200                 FileHistory h = FileHistory.getFileHistory(workDir, "configHistory.jtl");
1201                 File latestConfigFile = h.getLatestEntry();
1202                 if (latestConfigFile != null) {
1203                     try {
1204                         config.load(latestConfigFile);
1205                     }
1206                     catch (IOException e) {
1207                         uif.showError("qsw.owd.cantLoadDefaultConfig",
1208                                       new Object[] { latestConfigFile, e });
1209                         return null;
1210                     }
1211                     catch (InterviewParameters.Fault e) {
1212                         uif.showError("qsw.owd.cantLoadDefaultConfig",
1213                                       new Object[] { latestConfigFile, e.getMessage() });
1214                         return null;
1215                     }
1216                 }
1217                 if (testSuite != null) {
1218                     contextManager = ExecTool.createContextManager(testSuite);
1219 
1220                     if (!checkSingleTestManager()) {
1221                         return null;
1222                     }
1223                 }
1224 
1225             }
1226 
1227             return endPane;
1228         }
1229     };
1230 
1231     //------------------------------------------------------------------------------
1232 
1233     private class EndPane extends Pane {
1234         EndPane() {
1235             super("qsw.end");
1236             configTextArea = addText(false);
1237             configCheck = addCheck("cfg");
1238             runTestsTextArea = addText(false);
1239             runTestsCheck = addCheck("run");
1240         }
1241 
1242         void update() {
1243             super.update();
1244 
1245             // update text according to whether config is complete or not
1246             // (and so whether config editor required)
1247             // set configCheck if config incomplete
1248             Integer haveConfig = new Integer(configData == null ? 0 : 1);
1249 
1250             StringBuffer sb = new StringBuffer();
1251             if (config.isFinishable()) {
1252                 // "Your configuration is complete, but you can change it by using
1253                 // the Configuration Editor."
1254                 sb.append(uif.getI18NString("qsw.end.cfgComplete"));
1255                 configCheck.setSelected(task == BROWSE ? false : true);
1256             }
1257             else {
1258                 if (configData != null) {
1259                     // "Your configuration is incomplete."
1260                     sb.append(uif.getI18NString("qsw.end.cfgIncomplete"));
1261                     sb.append(" ");
1262                 }
1263                 // "Before you can run tests, you must complete (a|your) configuration
1264                 // by using the Configuration Editor."
1265                 sb.append(uif.getI18NString("qsw.end.needEditor", haveConfig));
1266                 configCheck.setSelected(task == BROWSE ? false : true);
1267             }
1268             sb.append(" ");
1269             // "You can open the Configuration Editor automatically by
1270             // checking the box below. You can also open the Configuration Editor
1271             // at any time from the Configure menu."
1272             sb.append(uif.getI18NString("qsw.end.editor"));
1273             configTextArea.setText(sb.toString());
1274 
1275             if (task == BROWSE) {
1276                 runTestsTextArea.setVisible(false);
1277                 runTestsCheck.setVisible(false);
1278             }
1279             else {
1280                 runTestsTextArea.setVisible(true);
1281                 runTestsCheck.setVisible(true);
1282                 // "Once (the|your) configuration is complete, you can run tests automatically
1283                 // by checking the box below. You can also run tests at any time from the
1284                 // Run Tests menu."
1285                 runTestsTextArea.setText(uif.getI18NString("qsw.end.runTests", haveConfig));
1286             }
1287 
1288             stateChanged();
1289         }
1290 
1291         void updateNextButton() {
1292             nextBtn.setEnabled(false);
1293         }
1294 
1295         void stateChanged() {
1296             if (runTestsCheck.isSelected()
1297                 && (config == null || !config.isFinishable()))
1298                 configCheck.setSelected(true);
1299             showConfigEditorFlag = configCheck.isSelected();
1300             runTestsFlag = runTestsCheck.isSelected();
1301         }
1302 
1303         private JTextArea configTextArea;
1304         private JCheckBox configCheck;
1305         private JTextArea runTestsTextArea;
1306         private JCheckBox runTestsCheck;
1307     };
1308 
1309     protected void windowClosingAction(AWTEvent e) {
1310         setVisible(false);
1311         closeExecTool(e);
1312     }
1313 
1314 }
1315