1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2010, 2012, 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 
  28 package com.sun.javatest.exec;
  29 
  30 import com.sun.javatest.ExcludeListUpdateHandler;
  31 import com.sun.javatest.InterviewParameters;
  32 import com.sun.javatest.Parameters;
  33 import com.sun.javatest.Parameters.LegacyEnvParameters;
  34 import com.sun.javatest.Parameters.MutableConcurrencyParameters;
  35 import com.sun.javatest.Parameters.MutableExcludeListParameters;
  36 import com.sun.javatest.Parameters.MutableKeywordsParameters;
  37 import com.sun.javatest.Parameters.MutablePriorStatusParameters;
  38 import com.sun.javatest.Parameters.MutableTestsParameters;
  39 import com.sun.javatest.Parameters.MutableTimeoutFactorParameters;
  40 import com.sun.javatest.TestSuite;
  41 import com.sun.javatest.WorkDirectory;
  42 import com.sun.javatest.exec.BasicSession.E_NewWD;
  43 import com.sun.javatest.exec.Session.Event;
  44 import com.sun.javatest.exec.Session.Fault;
  45 import com.sun.javatest.tool.FileHistory;
  46 import com.sun.javatest.tool.ToolAction;
  47 import com.sun.javatest.tool.UIFactory;
  48 import com.sun.javatest.tool.WorkDirChooser;
  49 import com.sun.javatest.util.Debug;
  50 import com.sun.javatest.util.I18NResourceBundle;
  51 
  52 import java.awt.Color;
  53 import java.awt.Component;
  54 import java.awt.GridBagConstraints;
  55 import java.awt.GridBagLayout;
  56 import java.awt.Insets;
  57 import java.awt.event.ActionEvent;
  58 import java.awt.event.ActionListener;
  59 import java.awt.event.InputEvent;
  60 import java.awt.event.KeyEvent;
  61 import java.io.File;
  62 import java.io.IOException;
  63 import java.net.URL;
  64 import java.util.Arrays;
  65 import java.util.Date;
  66 import java.util.HashMap;
  67 import java.util.List;
  68 import java.util.Map;
  69 import javax.swing.Action;
  70 import javax.swing.BorderFactory;
  71 import javax.swing.JButton;
  72 import javax.swing.JComponent;
  73 import javax.swing.JLabel;
  74 import javax.swing.JMenu;
  75 import javax.swing.JMenuItem;
  76 import javax.swing.JOptionPane;
  77 import javax.swing.JPanel;
  78 import javax.swing.JTextArea;
  79 import javax.swing.JTextField;
  80 import javax.swing.KeyStroke;
  81 import javax.swing.SwingConstants;
  82 import javax.swing.SwingUtilities;
  83 import javax.swing.event.MenuEvent;
  84 import javax.swing.event.MenuListener;
  85 
  86 /**
  87  * Class that encapsulate logic of user's actions on update session:
  88  * operations on configuration and work directory.
  89  * Some methods are added to preserve old functionality...
  90  *
  91  * @author Dmitry Fazunenko
  92  */
  93 public class BasicSessionControl implements InterviewEditor.Observer,
  94         RunTestsHandler.Observer, ET_SessionControl, Session.Observer {
  95 
  96 
  97     protected final SessionExt session;
  98     protected final TestSuite testSuite;
  99     protected UIFactory uif;
 100     protected JComponent parent;
 101     protected JPanel sessionView;
 102     protected InterviewEditor interviewEditor;
 103     protected ContextManager cm;
 104 
 105     ChangeConfigMenu changeMenu;
 106     Action loadConfigAction;
 107     Action newConfigAction;
 108     Action showFullConfigAction;
 109     Action showStdConfigAction;
 110     Action newWorkDirAction;
 111     Action openWorkDirAction;
 112 
 113     FileHistory.Listener configHistoryListener;
 114     JMenu menuHistory;
 115 
 116     private static KeyStroke configEditorAccelerator =
 117         KeyStroke.getKeyStroke(KeyEvent.VK_E, InputEvent.CTRL_MASK);
 118 
 119     private static I18NResourceBundle i18n = I18NResourceBundle.getBundleForClass(BasicSessionControl.class);
 120     private static int debug = Debug.getInt(BasicSessionControl.class);
 121     private boolean doConfig = false; // flag indicating that configure() method is running
 122 
 123     /**
 124      * Creates a control over new created session for the passed test suite.
 125      * @param parent
 126      * @param uif
 127      * @param ts
 128      * @param cm
 129      * @throws com.sun.javatest.exec.Session.Fault
 130      */
 131     public BasicSessionControl(JComponent parent, UIFactory uif, TestSuite ts,
 132             ContextManager cm) throws Fault {
 133         this.testSuite = ts;
 134         this.cm = cm;
 135         this.uif = uif;
 136         this.parent = parent;
 137         session = createEmptySession();
 138         initActions();
 139         initHistoryListeners();
 140     }
 141 
 142     /**
 143      * Returns the session object under control
 144      */
 145     public Session getSession() {
 146         return session;
 147     }
 148 
 149     /**
 150      * Returns the panel reflecting the current state of the session
 151      */
 152     public JComponent getViewComponent() {
 153         if (sessionView == null) {
 154             sessionView = createSessionView();
 155         }
 156         return sessionView;
 157     }
 158 
 159     /**
 160      * Returns array of actions for the tool bar.
 161      */
 162     Action[] getToolBarActions() {
 163         return new Action[] {
 164             showFullConfigAction,
 165             showStdConfigAction,
 166         };
 167     }
 168 
 169     public List<Action> getToolBarActionList() {
 170         return Arrays.asList(getToolBarActions());
 171     }
 172 
 173     public void save(Map m) {
 174         if (testSuite != null && testSuite.getRoot() != null)
 175             m.put("testSuite", testSuite.getRoot().getPath());
 176 
 177         // save work dir and ip
 178         session.save(m);
 179     }
 180 
 181     public void restore(Map m) {
 182         try {
 183             session.restore(m);
 184         } catch (Fault e) {
 185             if (debug > 0) {
 186                 e.printStackTrace(Debug.getWriter());
 187             }
 188             uif.showError("exec.cantRestoreSession", e.getMessage());
 189         }
 190     }
 191 
 192     public void dispose() {
 193         session.dispose();
 194         if (interviewEditor != null) {
 195             interviewEditor.dispose();
 196             interviewEditor = null;
 197         }
 198     }
 199 
 200     /**
 201      * Creates an empty configuration for the test suite. By default BasicSession
 202      * is used. It's supposed for subclasses to override this method.
 203      * @return created session.
 204      * @throws com.sun.javatest.exec.Session.Fault
 205      */
 206     protected SessionExt createEmptySession() throws Fault {
 207         return new BasicSession(testSuite);
 208     }
 209 
 210     /**
 211      * Clones passed parameters. Works only for InterviewParameters instances.
 212      * @param p instance to clone, might be null.
 213      * @return cloned object obtained for the passed one by performing save/load
 214      * operations.
 215      * @throws com.sun.javatest.exec.Session.Fault
 216      */
 217     public static Parameters clone(Parameters p) throws Session.Fault {
 218         if (p == null) {
 219             return null;
 220         }
 221         if (p instanceof InterviewParameters) {
 222             try {
 223                 InterviewParameters ip = (InterviewParameters)p;
 224                 InterviewParameters clone = ip.getWorkDirectory().getTestSuite().createInterview();
 225                 clone.setWorkDirectory(ip.getWorkDirectory());
 226                 HashMap data = new HashMap();
 227                 ip.save(data);
 228                 clone.load(data, false);
 229                 return clone;
 230             } catch (Exception e) {
 231                 throw new Session.Fault(e);
 232             }
 233 
 234         }
 235         throw new IllegalStateException(i18n.getString("bcc.cantClonParameters.err", p));
 236     }
 237 
 238     public void ensureInterviewUpToDate() {
 239         try {
 240             session.reloadInterview();
 241         } catch (Exception ex) {
 242             if (debug > 0) {
 243                 ex.printStackTrace(Debug.getWriter());
 244             }
 245             uif.showError("exec.loadInterview", ex.toString());
 246         }
 247     }
 248 
 249     /**
 250      * Invoked when runTestHandler is going to start test execution
 251      */
 252     public void startTests(Parameters p) {
 253         if (getNeedToAutoCheckExcludeList(p)) {
 254             checkExcludeListUpdate(parent, false, p);
 255         }
 256     }
 257 
 258     /**
 259      * Invoked when runTestHandler completed test execution
 260      */
 261     public void finishTests(Parameters p) {
 262     }
 263 
 264     public void whatToDoWhenConfigNotReadyButUserPressedStartButton(
 265             final Action startAction) {
 266         final InterviewParameters ip = session.getInterviewParameters();
 267 
 268 
 269         // configuration is incomplete, possibly not even started:
 270         // post a message explaining that the wizard is required.
 271         int option;
 272 
 273         if (!ip.isTemplate() && ip.isStarted()) {
 274             String errorMessage = ip.getErrorMessage();
 275             if (errorMessage != null) {
 276                 option = uif.showOKCancelDialog("rh.configError", errorMessage);
 277             } else {
 278                 option = uif.showOKCancelDialog("rh.completeConfigure");
 279             }
 280         } else {
 281             option = uif.showOKCancelDialog("rh.startConfigure");
 282         }
 283         if (option != JOptionPane.OK_OPTION) {
 284             startAction.setEnabled(true);
 285             return;
 286         }
 287 
 288         if (ip.isTemplate()) {
 289             newConfig();
 290         }
 291 
 292         showConfigEditor(new ActionListener() {
 293             public void actionPerformed(ActionEvent e2) {
 294                 // configuration has been completed: post a message to remind
 295                 // user that tests will now be run
 296                 if (ip.isTemplate() ||
 297                         !ip.isFinishable()) {
 298                     startAction.setEnabled(true);
 299                 }
 300                 else {
 301                     int option = uif.showOKCancelDialog("rh.configDone");
 302                     if (option == JOptionPane.OK_OPTION) {
 303                         startAction.actionPerformed(null);
 304                     }
 305                 }
 306             }
 307         });
 308     }
 309 
 310     void editConfigWithErrorMessage() {
 311         final InterviewParameters ip = session.getInterviewParameters();
 312         String errorMessage = ip.getErrorMessage();
 313         int option = (errorMessage == null) ?
 314             uif.showOKCancelDialog("rh.mustConfigure") :
 315             uif.showOKCancelDialog("rh.configError", errorMessage);
 316 
 317         // show the session editor if user clicks ok
 318         if (option == JOptionPane.OK_OPTION) {
 319             if (ip.isTemplate()) {
 320                 newConfig();
 321             } else {
 322                 showConfigEditor(null);
 323             }
 324         }
 325     }
 326 
 327     protected void checkExcludeListUpdate(JComponent parent, boolean quietIfNoUpdate, Parameters params) {
 328         if (params instanceof InterviewParameters) {
 329             InterviewParameters ip = (InterviewParameters)params;
 330             checkExcludeListUpdate(parent, quietIfNoUpdate, ip,
 331                     ip.getTestSuite(), ip.getWorkDirectory(), uif);
 332 
 333         }
 334     }
 335 
 336     static void checkExcludeListUpdate(JComponent parent, boolean quietIfNoUpdate,
 337             Parameters interviewParams, TestSuite testSuite,
 338             WorkDirectory workDir, UIFactory uif) {
 339         try {
 340             InterviewParameters.ExcludeListParameters elp = interviewParams.getExcludeListParameters();
 341             if ( !(elp instanceof InterviewParameters.MutableExcludeListParameters))
 342                 return;
 343 
 344             URL remote = testSuite.getLatestExcludeList();
 345             File local = workDir.getSystemFile("latest.jtx");
 346             ExcludeListUpdateHandler eluh = new ExcludeListUpdateHandler(remote, local);
 347 
 348             if (quietIfNoUpdate && !eluh.isUpdateAvailable())
 349                 return;
 350 
 351             JPanel info = new JPanel(new GridBagLayout());
 352             info.setBorder(BorderFactory.createEmptyBorder(20, 10, 20, 10));
 353             GridBagConstraints lc = new GridBagConstraints();
 354             lc.anchor = GridBagConstraints.EAST;
 355             GridBagConstraints fc = new GridBagConstraints();
 356             fc.gridwidth = GridBagConstraints.REMAINDER;
 357             fc.fill = GridBagConstraints.HORIZONTAL;
 358             fc.weightx = 1;
 359 
 360             JLabel remoteLbl = uif.createLabel("ch.elu.remote");
 361             info.add(remoteLbl, lc);
 362 
 363             JTextField remoteText = uif.createOutputField("ch.elu.remote", remoteLbl);
 364             remoteText.setBorder(null);
 365             // should consider better date formatting; is this i18n-ok?
 366             long remoteDate =  eluh.getRemoteURLLastModified();
 367             String remoteDateText = (remoteDate <= 0 ?
 368                                      uif.getI18NString("ch.elu.notAvailable")
 369                                      : new Date(remoteDate).toString());
 370             remoteText.setText(remoteDateText);
 371             remoteText.setColumns(remoteDateText.length());
 372             info.add(remoteText, fc);
 373 
 374             JLabel localLbl = uif.createLabel("ch.elu.local");
 375             info.add(localLbl, lc);
 376 
 377             JTextField localText = uif.createOutputField("ch.elu.local", localLbl);
 378             localText.setBorder(null);
 379             // should consider better date formatting; is this i18n-ok?
 380             long localDate =  eluh.getLocalFileLastModified();
 381             String localDateText = (localDate <= 0 ?
 382                                     uif.getI18NString("ch.elu.notAvailable")
 383                                     : new Date(localDate).toString());
 384             localText.setText(localDateText);
 385             localText.setColumns(localDateText.length());
 386             info.add(localText, fc);
 387 
 388             if (eluh.isUpdateAvailable()) {
 389                 String title = uif.getI18NString("ch.elu.update.title");
 390                 String head = uif.getI18NString("ch.elu.update.head");
 391                 String foot = uif.getI18NString("ch.elu.update.foot");
 392                 int rc = JOptionPane.showConfirmDialog(parent,
 393                                                        new Object[] { head, info, foot },
 394                                                        title,
 395                                                        JOptionPane.YES_NO_OPTION );
 396                 if (rc == JOptionPane.YES_OPTION)
 397                     eluh.update(); // should we show message if successful?
 398             }
 399             else {
 400                 String title = uif.getI18NString("ch.elu.noUpdate.title");
 401                 String head = uif.getI18NString("ch.elu.noUpdate.head");
 402                 JOptionPane.showMessageDialog(parent,
 403                                               new Object[] { head, info },
 404                                               title,
 405                                               JOptionPane.INFORMATION_MESSAGE );
 406             }
 407         }
 408         catch (IOException e) {
 409             workDir.log(uif.getI18NResourceBundle(), "ch.elu.logError", e);
 410             uif.showError("ch.elu.error", e);
 411         }
 412 
 413         // The following lines are to keep the i18N checks happy, because it is difficult
 414         // to invoke the various code paths that create the JOptionPanes
 415         //      getI18NString("ch.elu.local.lbl")
 416         //      getI18NString("ch.elu.local.tip")
 417         //      getI18NString("ch.elu.remote.lbl")
 418         //      getI18NString("ch.elu.remote.tip")
 419 
 420     }
 421 
 422 
 423     // arguably, this ought to be in InterviewParameters/BasicParameters
 424     protected boolean getNeedToAutoCheckExcludeList(Parameters params) {
 425         WorkDirectory workDir = params.getWorkDirectory();
 426         InterviewParameters.ExcludeListParameters elp = session.getParameters().getExcludeListParameters();
 427         if ( !(elp instanceof InterviewParameters.MutableExcludeListParameters))
 428             return false;
 429 
 430         InterviewParameters.MutableExcludeListParameters melp = (InterviewParameters.MutableExcludeListParameters) elp;
 431         if (melp.getExcludeMode() != InterviewParameters.MutableExcludeListParameters.LATEST_EXCLUDE_LIST)
 432             return false;
 433 
 434         // double check there is a URL to download from
 435         if (params.getTestSuite().getLatestExcludeList() == null)
 436             return false;
 437 
 438         if (!melp.isLatestExcludeAutoCheckEnabled())
 439             return false;
 440 
 441         if (melp.getLatestExcludeAutoCheckMode() == InterviewParameters.MutableExcludeListParameters.CHECK_EVERY_RUN)
 442             return true;
 443 
 444         File local = workDir.getSystemFile("latest.jtx");
 445         if (!local.exists())
 446             return true;
 447 
 448         long localLastModified = local.lastModified();
 449         long now = System.currentTimeMillis();
 450         int ageInDays = melp.getLatestExcludeAutoCheckInterval();
 451         long ageInMillis = 24L * 60 * 60 * 1000 * ageInDays;
 452 
 453         return (ageInDays > 0) && (now > (localLastModified + ageInMillis));
 454     }
 455 
 456 
 457     public JMenu getMenu() {
 458         JMenu menu = uif.createMenu("ch");
 459         // I hope some day workdir action will become a part
 460         // of "Configure" menu, not "File"
 461         //menu.add(uif.createMenuItem(newWorkDirAction));
 462         //menu.add(uif.createMenuItem(openWorkDirAction));
 463         //menu.addSeparator();
 464 
 465 
 466         // add Edit Configuration
 467         JMenuItem menuEdit = uif.createMenuItem(showFullConfigAction);
 468         menuEdit.setIcon(null);
 469         menuEdit.setAccelerator(configEditorAccelerator);
 470         menu.add(menuEdit);
 471 
 472 
 473         // add Edit Quick Set
 474         menu.add(changeMenu);
 475 
 476         menu.addSeparator();
 477         menu.add(uif.createMenuItem(newConfigAction));
 478         menu.add(uif.createMenuItem(loadConfigAction));
 479 
 480         // custom menu items
 481         // note: JavaTestMenuManager is deprecated mechanism
 482         // one should provide an alternative ET_ControlFactory implementation
 483         // instead.
 484         JavaTestMenuManager menuManager = null;
 485         if (cm != null) {
 486             menuManager = cm.getMenuManager();
 487             if (menuManager != null) {
 488                 JMenuItem[] items =
 489                     menuManager.getMenuItems(JavaTestMenuManager.CONFIG_PRIMARY);
 490                 if (items != null)
 491                     for (int i = 0; i < items.length; i++)
 492                         menu.add(items[i]);
 493             }
 494         }
 495 
 496 
 497 
 498         //menu.addMenuListener(configHistoryListener);
 499         menu.add(menuHistory);
 500 
 501         if (cm != null) {
 502             menuManager = cm.getMenuManager();
 503             if (menuManager != null) {
 504                 JMenuItem[] items =
 505                     menuManager.getMenuItems(JavaTestMenuManager.CONFIG_OTHER);
 506                 if (items != null) {
 507                     menu.addSeparator();
 508                     for (int i = 0; i < items.length; i++)
 509                         menu.add(items[i]);
 510                 }   // innerest if
 511             }
 512         }
 513         return menu;
 514     }
 515 
 516     /**
 517      * Initializes interviewEditor.
 518      * @return true if initialized successfully, false if failed.
 519      */
 520     protected boolean initEditor() {
 521         if (interviewEditor != null) {
 522             // already initialized
 523             return true;
 524         }
 525 
 526         InterviewParameters ip = session.getInterviewParameters();
 527         if (ip == null || ip.getWorkDirectory() == null) {
 528             return false;
 529         }
 530         interviewEditor = createInterviewEditor(ip);
 531         if (cm != null) {
 532             interviewEditor.setCustomRenderers(cm.getCustomRenderersMap());
 533             interviewEditor.setContextManager(cm);
 534         }
 535         interviewEditor.setCheckExcludeListListener(new ActionListener() {
 536                 public void actionPerformed(ActionEvent e) {
 537                     Object src = e.getSource();
 538                     JComponent p = (src instanceof JComponent ? (JComponent) src : parent);
 539                     checkExcludeListUpdate(p, false, session.getParameters());
 540                 }
 541             });
 542 
 543         interviewEditor.addObserver(this);
 544         return true;
 545 
 546     }
 547 
 548     /**
 549      * Creates an InterviewEditor instance. Subclasses might override this
 550      * method to create an alternative editor.
 551      *
 552      * @param ip parameters to be edited
 553      */
 554     protected InterviewEditor createInterviewEditor(InterviewParameters ip) {
 555         return new InterviewEditor(parent, getUIFactory(), ip);
 556     }
 557 
 558     /**
 559      * Method returning UIFactory to be used to create InterviewEditor instance.
 560      */
 561     protected UIFactory getUIFactory() {
 562         // this is workaround for template editor
 563         return uif;
 564     }
 565 
 566     /**
 567      * Action to create new configuration.
 568      */
 569     void newConfig() {
 570         if (!initEditor()) {
 571             return;
 572         }
 573         interviewEditor.newConfig();
 574     }
 575 
 576     /**
 577      * Action to load configuration.
 578      */
 579     void loadConfig() {
 580         if (!initEditor()) {
 581             return;
 582         }
 583         interviewEditor.loadConfig();
 584     }
 585 
 586     /**
 587      * Causes configuration editor to appear. If workdir is not set,
 588      * suggests to create one first.
 589      */
 590     public void edit() {
 591         if (session.getWorkDirectory() == null) {
 592             createWD();
 593             if (session.getWorkDirectory() == null) {
 594                 return;
 595             }
 596         }
 597         showConfig(InterviewEditor.FULL_MODE);
 598     }
 599 
 600     /**
 601      * Causes a series of actions to be performed to complete configuration:<br>
 602      * If session is already ready - does nothing.<br>
 603      * If work directory is not set - suggests creating or opening one<br>
 604      * Opens configuration editor.
 605      */
 606     public void configure() {
 607         doConfig = true;
 608         try {
 609             if (session.isReady()) {
 610                 return;
 611             }
 612             if (session.getWorkDirectory() == null) {
 613                 showWorkDirDialog();
 614             }
 615 
 616             if (session.getWorkDirectory() == null) {
 617                 return;
 618             }
 619             if (!session.isReady()) {
 620                 showConfigureDialog();
 621             }
 622         } finally {
 623             doConfig = false;
 624         }
 625     }
 626 
 627     /**
 628      * @return true if configure() method is running or configuration is editing.
 629      */
 630     public boolean isConfiguring() {
 631         return doConfig || isEditorVisible();
 632     }
 633 
 634     protected void showWorkDirDialog() {
 635         ActionListener optionListener = new ActionListener() {
 636             public void actionPerformed(ActionEvent e) {
 637                 Component c = (Component) (e.getSource());
 638                 JOptionPane op = (JOptionPane) SwingUtilities.getAncestorOfClass(JOptionPane.class, c);
 639                 op.setValue(c); // JOptionPane expects the value to be set to the selected button
 640                 op.setVisible(false);
 641             }
 642         };
 643 
 644         JTextArea msg = uif.createMessageArea("exec.wd.need");
 645         String title = uif.getI18NString("exec.wd.need.title");
 646         JButton[] options = {
 647                 uif.createButton("exec.wd.open", optionListener),
 648                 uif.createButton("exec.wd.new", optionListener),
 649                 uif.createCancelButton("exec.wd.cancel", optionListener)
 650         };
 651         int option = JOptionPane.showOptionDialog(parent,
 652                 msg,
 653                 title,
 654                 JOptionPane.YES_NO_CANCEL_OPTION,
 655                 JOptionPane.QUESTION_MESSAGE,
 656                 null,
 657                 options,
 658                 null);
 659 
 660         switch (option) {
 661             case JOptionPane.YES_OPTION:
 662                 setWD();
 663                 break;
 664             case JOptionPane.NO_OPTION:
 665                 createWD();
 666                 break;
 667             default:
 668                 return;
 669         }
 670     }
 671 
 672     protected void showConfigureDialog() {
 673         int option;
 674         if (session.getInterviewParameters().isStarted()) {
 675             String errorMessage = session.getInterviewParameters().getErrorMessage();
 676             if (errorMessage != null) {
 677                 option = uif.showOKCancelDialog("rh.configError", errorMessage);
 678             } else {
 679                 option = uif.showOKCancelDialog("rh.completeConfigure");
 680             }
 681         } else {
 682             option = uif.showOKCancelDialog("rh.startConfigure");
 683         }
 684         if (option == JOptionPane.OK_OPTION) {
 685             showConfig();
 686         } else {
 687             doConfig = false;
 688             session.notifyObservers(new E_EditorVisibility(isEditorVisible(), null));
 689         }
 690     }
 691 
 692     /**
 693      * Method to be invoked right after WD has been created/opened.
 694      */
 695     private void showConfig() {
 696         if (session.getInterviewParameters().getFile() == null) {
 697             newConfig();
 698         } else {
 699             showConfig(InterviewEditor.FULL_MODE);
 700         }
 701     }
 702 
 703     /**
 704      * Action to edit current configuration
 705      * @param mode
 706      */
 707     void showConfig(int mode) {
 708         if (!initEditor()) {
 709             return;
 710         }
 711         interviewEditor.edit(mode);
 712     }
 713 
 714     void showConfigEditor(ActionListener actionListener) {
 715         if (!initEditor()) {
 716             return;
 717         }
 718         interviewEditor.edit(InterviewEditor.FULL_MODE);
 719     }
 720     void checkUpdate() {
 721         System.err.println("Temporary not implemented...");
 722     }
 723     void ensureConfigEditorInitialized() {
 724         /*
 725         if (workDir == null)
 726             throw new IllegalStateException();
 727 
 728         if (configEditor == null) {
 729             configEditor = new ConfigEditor(parent, interviewParams, model, uif);
 730             configEditor.setCustomRenderers(customRenderersMap);
 731             configEditor.setCheckExcludeListListener(new ActionListener() {
 732                     public void actionPerformed(ActionEvent e) {
 733                         Object src = e.getSource();
 734                         JComponent p = (src instanceof JComponent ? (JComponent) src : parent);
 735                         checkExcludeListUpdate(p, false);
 736                     }
 737                 });
 738 
 739             configEditor.setObserver(new ConfigEditor.Observer() {
 740                     public void saved(InterviewParameters p) {
 741                         syncCurrentConfig(p);
 742                         updateGUI();
 743                     }
 744                     public void loaded(InterviewParameters p) {
 745                         syncCurrentConfig(p);
 746                         updateGUI();
 747                     }
 748             });
 749 
 750         }
 751          */
 752     }
 753 
 754     protected void initActions() {
 755         loadConfigAction = new ToolAction(uif, "ch.load") {
 756             public void actionPerformed(ActionEvent e) {
 757                 if (session.getWorkDirectory() == null) {
 758                     showWorkDirDialog();
 759                 }
 760                 loadConfig();
 761             }
 762         };
 763 
 764         newConfigAction = new ToolAction(uif, "ch.new") {
 765             public void actionPerformed(ActionEvent e) {
 766                 if (session.getWorkDirectory() == null) {
 767                     showWorkDirDialog();
 768                 }
 769                 newConfig();
 770             }
 771             @Override
 772             public Object getValue(String key) {
 773                 if (SessionView.ACTION_NAME.equals(key)){
 774                     return uif.getI18NString("ch.new2.act");
 775                 }
 776                 return super.getValue(key);
 777             }
 778         };
 779 
 780        showFullConfigAction = new ConfigAction(uif, "ch.full",
 781                InterviewEditor.FULL_MODE, true) {
 782             @Override
 783             public void actionPerformed(ActionEvent e) {
 784                 if (session.getWorkDirectory() == null) {
 785                     showWorkDirDialog();
 786                 }
 787                 showConfig(InterviewEditor.FULL_MODE);
 788             }
 789             @Override
 790             public Object getValue(String key) {
 791                 if (SessionView.ACTION_NAME.equals(key)){
 792                     return uif.getI18NString("ch.full2.act");
 793                 }
 794                 return super.getValue(key);
 795             }
 796        };
 797 
 798        showStdConfigAction = new ConfigAction(uif, "ch.std",
 799                InterviewEditor.STD_MODE, true) {
 800 
 801             @Override
 802             public void setEnabled(boolean newValue) {
 803                 super.setEnabled(newValue);
 804                 if (changeMenu != null) {
 805                     changeMenu.checkEnabled();
 806                 }
 807             }
 808             @Override
 809             public void actionPerformed(ActionEvent e) {
 810                 if (!isEnabled())
 811                     return;
 812 
 813                 Object control = e.getSource();
 814                 if (control instanceof JMenuItem) {
 815                     JMenuItem mi = (JMenuItem)control;
 816                     Integer miMode = (Integer)getValue(mi.getName());
 817                     performAction(miMode);
 818                 }
 819                 else {
 820                     performAction(mode);
 821                 }
 822             }
 823        };
 824 
 825        changeMenu = new ChangeConfigMenu();
 826 
 827        newWorkDirAction = createNewWorkDirAction();
 828        openWorkDirAction = createSetWorkDirAction();
 829 
 830     }
 831 
 832     protected ToolAction createNewWorkDirAction() {
 833         return new ToolAction(uif, "ch.newWorkDir") {
 834             public void actionPerformed(ActionEvent e) {
 835                 boolean editConfig = createWD();
 836                 if (editConfig) {
 837                     showConfig();
 838                 }
 839             };
 840             @Override
 841             public Object getValue(String key) {
 842                 if (SessionView.ACTION_NAME.equals(key)){
 843                     return uif.getI18NString("ch.newWorkDir.act");
 844                 }
 845                 return super.getValue(key);
 846             }
 847 
 848         };
 849     }
 850 
 851     protected ToolAction createSetWorkDirAction() {
 852         return new ToolAction(uif, "ch.setWorkDir") {
 853             public void actionPerformed(ActionEvent e) {
 854                 boolean editConfig = setWD();
 855                 if (editConfig) {
 856                     showConfig(InterviewEditor.FULL_MODE);
 857                 }
 858             }
 859             @Override
 860             public Object getValue(String key) {
 861                 if (SessionView.ACTION_NAME.equals(key)){
 862                     return uif.getI18NString("ch.setWorkDir.act");
 863                 }
 864                 return super.getValue(key);
 865             }
 866         };
 867     }
 868 
 869     protected void initHistoryListeners() {
 870         configHistoryListener = new FileHistory.Listener(new ActionListener() {
 871                 public void actionPerformed(ActionEvent e) {
 872                     JMenuItem mi = (JMenuItem) (e.getSource());
 873                     File f = (File) (mi.getClientProperty(FileHistory.FILE));
 874                     if (f != null) {
 875                         if (initEditor()) {
 876                             // ensureConfigEditorInitialized();
 877                             interviewEditor.loadAndEdit(f);
 878                         }
 879                     }
 880                 }
 881             });
 882         menuHistory = uif.createMenu("ch.history");
 883         menuHistory.addMenuListener(configHistoryListener);
 884 
 885     }
 886 
 887     protected JPanel createSessionView() {
 888         return new SessionView(session);
 889     }
 890 
 891     public void updateGUI() {
 892 
 893         Parameters params = session.getParameters();
 894 
 895         if (params != null)
 896             ensureInterviewUpToDate();
 897 
 898         boolean isWorkDirSet = session.getWorkDirectory() != null;
 899         boolean configCreated = session.getValue(BasicSession.CONFIG_NAME_PROP) != null;
 900         boolean editorNotVisible = !isEditorVisible();
 901         showFullConfigAction.setEnabled(params != null && configCreated && editorNotVisible);
 902         showStdConfigAction.setEnabled(params != null && configCreated && editorNotVisible);
 903         newWorkDirAction.setEnabled(!isWorkDirSet);
 904         openWorkDirAction.setEnabled(!isWorkDirSet);
 905 
 906         // you can only configure tests if the test suite is set
 907         newConfigAction.setEnabled(editorNotVisible);
 908         loadConfigAction.setEnabled(editorNotVisible);
 909         changeMenu.checkEnabled();
 910 
 911         menuHistory.setEnabled(editorNotVisible);
 912         if (isWorkDirSet) {
 913             FileHistory h;
 914             if (configHistoryListener.getFileHistory() == null) {
 915                 h = FileHistory.getFileHistory(session.getWorkDirectory(), InterviewEditor.CONFIG_HISTORY);
 916                 configHistoryListener.setFileHistory(h);
 917             } else {
 918                 h = configHistoryListener.getFileHistory();
 919             }
 920             if (h.getLatestEntry() == null) {
 921                 menuHistory.setEnabled(false);
 922             }
 923         } else {
 924             menuHistory.setEnabled(false);
 925         }
 926 
 927         /*
 928         showExcludeListAction.setEnabled(testSuiteSet);
 929         showEnvironmentAction.setEnabled(testSuiteSet);
 930         showQuestionLogAction.setEnabled(testSuiteSet);
 931         showChecklistAction.setEnabled(testSuiteSet
 932                                        && params != null
 933                                        && !params.isChecklistEmpty());
 934         checkUpdatesAction.setEnabled(false);
 935 
 936         menuHistory.setEnabled(testSuiteSet);
 937 
 938 
 939         if (workDir != null && configHistoryListener.getFileHistory() == null) {
 940             FileHistory h = FileHistory.getFileHistory(workDir, "configHistory.jtl");
 941             configHistoryListener.setFileHistory(h);
 942         }
 943 
 944         if (workDir != null && configTemplateHistoryListener.getFileHistory() == null) {
 945             FileHistory h = FileHistory.getFileHistory(workDir, "templateHistory.jtl");
 946             configTemplateHistoryListener.setFileHistory(h);
 947         }
 948 
 949         if (params != null && observer == null) {
 950             observer = new Interview.Observer() {
 951                     public void currentQuestionChanged(Question q) {
 952                     }
 953                     public void pathUpdated() {
 954                         showChecklistAction.setEnabled(!params.isChecklistEmpty());
 955                     }
 956                 };
 957             params.addObserver(observer);
 958         }
 959 */
 960 
 961     }
 962 
 963     /**
 964      * @return true if user has an interview editor open.
 965      */
 966     protected boolean isEditorVisible() {
 967         return interviewEditor != null && interviewEditor.isVisible();
 968     }
 969 
 970     /**
 971      * InterviewEditor.Observer method.
 972      * Invoked when current session has changed from InterviewEditor
 973      * @param p
 974      */
 975     public void changed(InterviewParameters p) {
 976         try {
 977             session.update(new BasicSession.U_NewConfig(p));
 978         } catch (Session.Fault e) {
 979             e.printStackTrace();
 980             System.err.println(i18n.getString("bcc.internalError.err"));
 981         }
 982     }
 983 
 984     /**
 985      * InterviewEditor.Observer method.
 986      * Invoked when InterviewEditor is made either visible or invisible.
 987      * Implementations call updateGUI() to enable/disable actions.
 988      * @param isVisible - true or false
 989      */
 990     public void changedVisibility(boolean isVisible, InterviewEditor editor) {
 991         updateGUI();
 992         session.notifyObservers(new E_EditorVisibility(isVisible, editor));
 993     }
 994 
 995     /**
 996      * Causes the dialog for new directory creating to appear.
 997      * Invoked from createNewWorkDirAction.
 998      * Subclasses might override this method to perform extra actions
 999      * associated with creating new work directory, like setting template.
1000      *
1001      * @return true if configuration editing is required after WorkDir created
1002      */
1003     protected boolean createWD() {
1004          applyWorkDir(WorkDirChooseTool.chooseWD(parent, null, testSuite, WorkDirChooser.NEW));
1005          return false;
1006     }
1007 
1008     /**
1009      * Causes the dialog for work directory selecting to appear.
1010      * Invoked from createSetWorkDirAction.
1011      * Subclasses might override this method to perform extra actions
1012      * associated with setting work directory, like setting template.
1013      *
1014      * @return true if configuration editing is required after WorkDir set
1015      */
1016     protected boolean setWD() {
1017         applyWorkDir(WorkDirChooseTool.chooseWD(parent, null, testSuite, WorkDirChooser.OPEN_FOR_GIVEN_TESTSUITE));
1018         return false;
1019     }
1020 
1021     /**
1022      * Applies value of the selected work directory.
1023      * @param wd
1024      */
1025     protected void applyWorkDir(WorkDirectory wd) {
1026         if (wd != null) {
1027             try {
1028                 session.update(new BasicSession.U_NewWD(wd));
1029             } catch (Exception ee) {
1030                 ee.printStackTrace();
1031             }
1032         }
1033     }
1034 
1035     /**
1036      * Tries to restore latest available configuration for the session.
1037      * @param wd
1038      */
1039     public void restoreConfigFromWD(WorkDirectory wd) throws Fault {
1040         // This code would better belong to BasicSession
1041         // but it uses some gui features :(
1042 
1043         FileHistory h = FileHistory.getFileHistory(wd, "configHistory.jtl");
1044         File latestConfigFile = h.getRelativeLatestEntry(wd.getRoot().getPath(), wd.getPrevWDPath());
1045 
1046         // validate location of session file if needed
1047         if (latestConfigFile != null) {
1048             if (!cm.getAllowConfigLoadOutsideDefault()) {
1049                 File defaultConfigLoadPath = InterviewEditor.checkLoadConfigFileDefaults(cm);
1050 
1051                 File dir = new File(latestConfigFile.getAbsolutePath().substring(
1052                         0, latestConfigFile.getAbsolutePath().
1053                         lastIndexOf(File.separator)));
1054 
1055                 boolean isMatch = true;
1056 
1057                 if (dir != null && defaultConfigLoadPath != null)
1058                     try {
1059                         isMatch = (dir.getCanonicalPath().indexOf
1060                                 ((defaultConfigLoadPath.getCanonicalPath())) == 0);
1061                     } catch (IOException ioe) {
1062                         // use logging subsystem instead when available
1063                         // Internal error in ExecToolManager: exception thrown:
1064                         uif.showError("exec.internalError", ioe);
1065                         return;
1066                     }
1067 
1068                 if (!isMatch) {
1069                     // resetWorkDirectory();
1070                     uif.showError("ce.load.notAllowedDir", defaultConfigLoadPath);
1071                     return;
1072                 }
1073             }
1074             loadInterviewFromFile(wd, latestConfigFile);
1075             h.add(latestConfigFile);
1076 
1077             // final long time = System.currentTimeMillis();
1078             // interviewParams.load(latestConfigFile);
1079             //logLoadTime("exec.log.iload",System.currentTimeMillis()-time,
1080             //        workDir, latestConfigFile.getAbsolutePath());
1081 
1082         }
1083     }
1084 
1085     void loadInterviewFromFile(WorkDirectory wd, File latestConfigFile) {
1086         try {
1087             session.loadInterviewFromFile(wd, latestConfigFile);
1088         } catch (Fault e) {
1089             uif.showError("exec.internalError", e);
1090         }
1091     }
1092 
1093     public void updated(Event ev) {
1094         if (ev instanceof BasicSession.E_NewWD) {
1095             E_NewWD e_WD = (BasicSession.E_NewWD)ev;
1096             if (e_WD.doRestoreConfig) {
1097                 try {
1098                     restoreConfigFromWD(e_WD.wd);
1099                 } catch (Fault f) {
1100                     f.printStackTrace();
1101                 }
1102             }
1103         }
1104     }
1105 
1106     /**
1107      * Event to be sent out when Editor become visible/invisible
1108      */
1109     protected class E_EditorVisibility implements Event {
1110         public final boolean isVisible;
1111         public final InterviewEditor source;
1112         E_EditorVisibility(boolean isVisible, InterviewEditor source) {
1113             this.isVisible = isVisible;
1114             this.source = source;
1115         }
1116     }
1117 
1118     protected class SessionView extends JPanel implements Session.Observer {
1119 
1120         protected Session session;
1121         protected JLabel wd_n;
1122         protected JLabel conf_n;
1123         protected JTextField wd_f;
1124         protected JTextField conf_f;
1125         public static final String ACTION_NAME = "actionName";
1126         protected final Color COLOR_NOT_READY = uif.getI18NColor("bcc.notready");
1127         protected final Color COLOR_READY = uif.getI18NColor("bcc.ready");
1128 
1129         protected SessionView(Session session) {
1130             super();
1131             this.session = session;
1132             this.session.addObserver(this);
1133             init();
1134             layoutComponents();
1135         }
1136 
1137         protected void init() {
1138 
1139             wd_n = uif.createLabel("bcc.WorkDir");
1140             wd_f = uif.createOutputField("bcc.WorkDir", wd_n, true);
1141             //wd_f.setFont(BOLD_FONT);
1142             wd_f.setBorder(BorderFactory.createEmptyBorder());
1143 
1144             conf_n = uif.createLabel("bcc.Configuration");
1145             conf_f = uif.createOutputField("bcc.Configuration", conf_n, true);
1146             //conf_f.setFont(BOLD_FONT);
1147             conf_f.setBorder(BorderFactory.createEmptyBorder());
1148         }
1149 
1150         protected void layoutComponents() {
1151             GridBagConstraints gridBagConstraints;
1152 
1153             setLayout(new GridBagLayout());
1154 
1155             gridBagConstraints = new GridBagConstraints();
1156             gridBagConstraints.gridx = 0;
1157             gridBagConstraints.gridy = 0;
1158             gridBagConstraints.insets = new Insets(0, 3, 0, 3);
1159             add(wd_n, gridBagConstraints);
1160 
1161             boolean wdReady = session.getParameters().getWorkDirectory() != null;
1162 
1163             updateWD(wd_f, wdReady);
1164             gridBagConstraints = new GridBagConstraints();
1165             gridBagConstraints.gridx = 1;
1166             gridBagConstraints.gridy = 0;
1167             gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
1168             gridBagConstraints.weightx = 0.1;
1169             gridBagConstraints.insets = new Insets(0, 3, 0, 3);
1170             add(wd_f, gridBagConstraints);
1171 
1172 
1173             conf_n.setHorizontalAlignment(SwingConstants.RIGHT);
1174             gridBagConstraints = new GridBagConstraints();
1175             gridBagConstraints.gridx = 2;
1176             gridBagConstraints.gridy = 0;
1177             gridBagConstraints.insets = new Insets(0, 3, 0, 3);
1178             add(conf_n, gridBagConstraints);
1179 
1180             updateCfg(conf_f, wdReady);
1181             gridBagConstraints = new java.awt.GridBagConstraints();
1182             gridBagConstraints.gridx = 3;
1183             gridBagConstraints.gridy = 0;
1184             gridBagConstraints.fill = GridBagConstraints.HORIZONTAL;
1185             gridBagConstraints.weightx = 0.1;
1186             gridBagConstraints.insets = new Insets(0, 3, 0, 3);
1187             add(conf_f, gridBagConstraints);
1188 
1189         }
1190 
1191         protected void updateField(JTextField fld, String text) {
1192             String tipText = null;
1193             if (text == null) {
1194                 text = "NONE";
1195                 tipText = "Not set yet";
1196             } else {
1197                 tipText = text;
1198                 int index = text.lastIndexOf(File.separator);
1199                 if (index >=0) {
1200                     text = text.substring(index + 1);
1201                 }
1202             }
1203             fld.setText(text);
1204             fld.setToolTipText(tipText);
1205             //fld.setFont(BOLD_FONT);
1206         }
1207         protected void updateWD(JTextField fld, boolean isReady) {
1208             String text = session.getValue(BasicSession.WD_PROP);
1209             updateField(fld, text);
1210             /*
1211             if (isReady) {
1212                 fld.setForeground(COLOR_READY);
1213                 fld.setFont(BOLD_FONT);
1214             } else {
1215                 fld.setForeground(COLOR_NOT_READY);
1216             }*/
1217         }
1218 
1219         protected void updateCfg(JTextField fld, boolean isWDReady) {
1220             String text = session.getValue(BasicSession.CONFIG_NAME_PROP);
1221             updateField(fld, text);
1222             /*
1223             if (!isWDReady || session.isReady()) {
1224                 fld.setForeground(COLOR_READY);
1225                 fld.setFont(BOLD_FONT);
1226             } else {
1227                 fld.setForeground(COLOR_NOT_READY);
1228             }*/
1229 
1230         }
1231 
1232         public void updated(Event ev) {
1233             boolean wdReady = session.getParameters().getWorkDirectory() != null;
1234             updateWD(wd_f, wdReady);
1235             updateCfg(conf_f, wdReady);
1236         }
1237     }
1238 
1239     private class ChangeConfigMenu extends JMenu implements MenuListener {
1240 
1241         ChangeConfigMenu() {
1242             uif.initMenu(this, "ch.change");
1243             tests       = addMenuItem(CHANGE_TESTS,             InterviewEditor.STD_TESTS_MODE);
1244             excludeList = addMenuItem(CHANGE_EXCLUDE_LIST,      InterviewEditor.STD_EXCLUDE_LIST_MODE);
1245             keywords    = addMenuItem(CHANGE_KEYWORDS,          InterviewEditor.STD_KEYWORDS_MODE);
1246             kfl         = addMenuItem(CHANGE_KFL,               InterviewEditor.STD_KFL_MODE);
1247             priorStatus = addMenuItem(CHANGE_PRIOR_STATUS,      InterviewEditor.STD_PRIOR_STATUS_MODE);
1248             environment = addMenuItem(CHANGE_ENVIRONMENT,       InterviewEditor.STD_ENVIRONMENT_MODE);
1249             concurrency = addMenuItem(CHANGE_CONCURRENCY,       InterviewEditor.STD_CONCURRENCY_MODE);
1250             timeoutFactor = addMenuItem(CHANGE_TIMEOUT_FACTOR,  InterviewEditor.STD_TIMEOUT_FACTOR_MODE);
1251             addMenuListener(this);
1252         }
1253 
1254         public void checkEnabled() {
1255             if (!(tests.isEnabled() || excludeList.isEnabled() ||
1256                     keywords.isEnabled() || priorStatus.isEnabled() ||
1257                     environment.isEnabled() || concurrency.isEnabled() ||
1258                     timeoutFactor.isEnabled() || kfl.isEnabled())) {
1259                 setEnabled(false);
1260             }
1261             else {
1262                 setEnabled(!isEditorVisible());
1263             }
1264         }
1265 
1266         private JMenuItem addMenuItem(String action, int configEditorMode) {
1267             JMenuItem mi = uif.createMenuItem(showStdConfigAction);
1268             mi.setIcon(null);
1269             mi.setName(action);
1270             mi.setText(uif.getI18NString("ch.change" + "." + action + ".mit"));
1271             mi.setMnemonic(uif.getI18NMnemonic("ch.change" + "." + action + ".mne"));
1272             showStdConfigAction.putValue(action, configEditorMode);
1273             add(mi);
1274             return mi;
1275         }
1276 
1277         // ---------- from MenuListener -----------
1278         public void menuSelected(MenuEvent e) {
1279             Parameters c = session.getParameters(); // alias, to save typing
1280             if (c == null) // if null, should not even be enabled
1281                 return;
1282 
1283             // Update the various menu items depending whether the corresponding parameters
1284             // can be handled by the Standard Values view -- ie whether the corresponding
1285             // parameters are mutable
1286             // Note: can't ask configEditor and hence stdView directly, since they
1287             // may not have been initialized yet
1288 
1289             update(tests,       c.getTestsParameters(),         MutableTestsParameters.class);
1290             update(excludeList, c.getExcludeListParameters(),   MutableExcludeListParameters.class);
1291             update(keywords,    c.getKeywordsParameters(),      MutableKeywordsParameters.class);
1292             update(priorStatus, c.getPriorStatusParameters(),   MutablePriorStatusParameters.class);
1293             update(environment, c.getEnvParameters(),           LegacyEnvParameters.class);
1294             update(concurrency, c.getConcurrencyParameters(),   MutableConcurrencyParameters.class);
1295             update(timeoutFactor, c.getTimeoutFactorParameters(), MutableTimeoutFactorParameters.class);
1296         }
1297 
1298         private void update(JMenuItem mi, Object o, Class c) {
1299             mi.setVisible(o != null && c.isAssignableFrom(o.getClass()));
1300         }
1301 
1302         public void menuDeselected(MenuEvent e) {
1303         }
1304 
1305         public void menuCanceled(MenuEvent e) {
1306         }
1307 /*
1308         void loadInterview(File file) {
1309             if (initEditor()) {
1310                 interviewEditor.load(file);
1311             }
1312         }
1313 */
1314 
1315         // ----------
1316 
1317         private JMenuItem tests;
1318         private JMenuItem excludeList;
1319         private JMenuItem keywords;
1320         private JMenuItem kfl;
1321         private JMenuItem priorStatus;
1322         private JMenuItem environment;
1323         private JMenuItem concurrency;
1324         private JMenuItem timeoutFactor;
1325 
1326         private static final String CHANGE_TESTS = "test";
1327         private static final String CHANGE_EXCLUDE_LIST = "excl";
1328         private static final String CHANGE_KEYWORDS = "keyw";
1329         private static final String CHANGE_KFL = "kfl";
1330         private static final String CHANGE_PRIOR_STATUS = "stat";
1331         private static final String CHANGE_ENVIRONMENT = "envt";
1332         private static final String CHANGE_CONCURRENCY = "conc";
1333         private static final String CHANGE_TIMEOUT_FACTOR = "time";
1334     };
1335 
1336 
1337     private class ConfigAction extends ToolAction {
1338         public int mode;
1339 
1340         public ConfigAction(UIFactory uif, String key, int mode, boolean needIcon) {
1341             super(uif, key, needIcon);
1342             this.mode = mode;
1343         }
1344 
1345         public void actionPerformed(ActionEvent e) {
1346             if (!isEnabled())
1347                 return;
1348 
1349             performAction(mode);
1350         }
1351 
1352         protected void performAction(Integer mode) {
1353             showConfig(mode);
1354         }
1355 
1356     }
1357 
1358 }