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 }