1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2002, 2011, Oracle and/or its affiliates. All rights reserved. 5 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 6 * 7 * This code is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License version 2 only, as 9 * published by the Free Software Foundation. Oracle designates this 10 * particular file as subject to the "Classpath" exception as provided 11 * by Oracle in the LICENSE file that accompanied this code. 12 * 13 * This code is distributed in the hope that it will be useful, but WITHOUT 14 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 * version 2 for more details (a copy is included in the LICENSE file that 17 * accompanied this code). 18 * 19 * You should have received a copy of the GNU General Public License version 20 * 2 along with this work; if not, write to the Free Software Foundation, 21 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 22 * 23 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 24 * or visit www.oracle.com if you need additional information or have any 25 * questions. 26 */ 27 package com.sun.javatest.exec; 28 29 import java.awt.BorderLayout; 30 import java.awt.GridBagLayout; 31 import java.awt.GridBagConstraints; 32 import java.awt.event.ActionEvent; 33 import java.awt.event.ActionListener; 34 import java.awt.event.ComponentAdapter; 35 import java.awt.event.ComponentEvent; 36 import java.io.File; 37 import java.util.Arrays; 38 import java.util.Map; 39 40 import javax.swing.Box; 41 import javax.swing.ButtonGroup; 42 import javax.swing.BorderFactory; 43 import javax.swing.DefaultListModel; 44 import javax.swing.JCheckBox; 45 import javax.swing.JComboBox; 46 import javax.swing.JComponent; 47 import javax.swing.JPanel; 48 import javax.swing.JLabel; 49 import javax.swing.JList; 50 import javax.swing.JRadioButton; 51 import javax.swing.JScrollPane; 52 import javax.swing.JTabbedPane; 53 import javax.swing.JTextField; 54 import javax.swing.SwingConstants; 55 import javax.swing.event.ChangeEvent; 56 import javax.swing.event.ChangeListener; 57 58 import com.sun.interview.Interview; 59 import com.sun.interview.Question; 60 import com.sun.javatest.InterviewParameters; 61 import com.sun.javatest.InitialUrlFilter; 62 import com.sun.javatest.Keywords; 63 import com.sun.javatest.KeywordsFilter; 64 import com.sun.javatest.Parameters.ExcludeListParameters; 65 import com.sun.javatest.Parameters.MutableExcludeListParameters; 66 import com.sun.javatest.Status; 67 import com.sun.javatest.StatusFilter; 68 import com.sun.javatest.TestFilter; 69 import com.sun.javatest.TestDescription; 70 import com.sun.javatest.TestResultTable; 71 import com.sun.javatest.TestSuite; 72 import com.sun.javatest.ObservableTestFilter; 73 import com.sun.javatest.ObservableTestFilter.Observer; 74 import com.sun.javatest.util.DynamicArray; 75 import com.sun.javatest.util.StringArray; 76 import com.sun.javatest.tool.TestTreeSelectionPane; 77 import com.sun.javatest.tool.UIFactory; 78 import java.util.HashSet; 79 80 /** 81 * This filter allows the user to configure the filter using 82 * the filtering attributes normally found in the parameter 83 * section of an interview: 84 * <ul> 85 * <li>Initial URLs 86 * <li>Status 87 * <li>Exclude List 88 * <li>Keywords 89 * </ul> 90 * 91 *<p> 92 * The settings for this panel are global, so any changes made affect all 93 * exec tool instances. 94 */ 95 class BasicCustomTestFilter extends ConfigurableTestFilter { 96 // UIFactory parameter assume this class stays in the exec package 97 98 BasicCustomTestFilter(String name, ExecModel e, UIFactory uif) { 99 super(name, e); 100 this.uif = uif; 101 init(null); 102 } 103 104 BasicCustomTestFilter(Map map, ExecModel e, UIFactory uif) { 105 super(map, e); 106 this.uif = uif; 107 init(map); 108 } 109 110 BasicCustomTestFilter(ExecModel e, UIFactory uif) { 111 super(uif.getI18NString("basicTf.namePrefix"), e); 112 this.uif = uif; 113 114 init(null); 115 } 116 117 ConfigurableTestFilter cloneInstance() { 118 return new BasicCustomTestFilter(uif.getI18NString("basicTf.namePrefix") + 119 instanceCount, execModel, uif); 120 } 121 122 // override superclass methods 123 // observers must be static data since all exec tool instances 124 // must be notified of changes 125 @Override 126 public void addObserver(Observer o) { 127 obs = DynamicArray.append(obs, o); 128 } 129 130 @Override 131 public void removeObserver(Observer o) { 132 obs = DynamicArray.remove(obs, o); 133 } 134 135 @Override 136 protected void notifyUpdated(ObservableTestFilter filter) { 137 // obs will be null if called indirectly via load(map) from the 138 // superclass constructor, because super(...) is defined to be 139 // called before instance variables are initialized. 140 // (Hence the danger of overriding methods called from a superclass 141 // constructor.) 11/12/02 142 if (obs == null) { 143 return; 144 } 145 146 for (int i = 0; i < obs.length; i++) { 147 obs[i].filterUpdated(filter); 148 } 149 } 150 151 @Override 152 boolean load(Map map) { 153 boolean result = super.load(map); 154 activeSettings = new SettingsSnapshot(map); 155 putSettings(activeSettings); 156 activateSettings(activeSettings); 157 158 notifyUpdated(this); 159 160 return result; 161 } 162 163 @Override 164 boolean save(Map<String, String> map) { 165 boolean result = super.save(map); 166 activeSettings.save(map); 167 168 return result; 169 } 170 171 void update(InterviewParameters ip) { 172 activateSettings(activeSettings); 173 } 174 175 synchronized JComponent getEditorPane() { 176 if (editorPane == null) { 177 editorPane = uif.createTabbedPane("basicTf.tabs", createTabPanels()); 178 editorPane.setTabPlacement(SwingConstants.TOP); 179 180 try { 181 if (activeSettings == null) { 182 activeSettings = grabSettings(); 183 } else { 184 putSettings(activeSettings); 185 } 186 } catch (IllegalStateException e) { 187 throw new IllegalStateException("Illegal state of BCTF GUI on startup."); 188 } // catch 189 190 editorPane.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5)); 191 } 192 193 return editorPane; 194 } 195 196 String commitEditorSettings() { 197 SettingsSnapshot nowSettings = null; 198 199 try { 200 nowSettings = grabSettings(); 201 } catch (IllegalStateException e) { 202 // indicates that the GUI settings are not valid 203 return e.getMessage(); 204 } // catch 205 206 if (!activeSettings.equals(nowSettings)) { 207 return activateSettings(nowSettings); 208 } else { 209 return null; 210 } 211 } 212 213 void resetEditorSettings() { 214 // set GUI to match live settings 215 putSettings(activeSettings); 216 } 217 218 boolean isEditorChanged() { 219 SettingsSnapshot nowSettings = null; 220 221 try { 222 nowSettings = grabSettings(); 223 } catch (IllegalStateException e) { 224 // indicates that the GUI settings are not valid 225 return true; 226 } // catch 227 if (activeSettings.equals(nowSettings)) { 228 return false; 229 } else { 230 return true; 231 } 232 } 233 234 // TestFilter interface 235 public boolean accepts(TestDescription td) 236 throws TestFilter.Fault { 237 return accepts(td, null); 238 } 239 240 public boolean accepts(TestDescription td, TestFilter.Observer o) 241 throws TestFilter.Fault { 242 if (statusFilterNeedsUpdate) 243 updateStatusFilter(); 244 245 for (int i = 0; i < activeFilters.length; i++) { 246 if (activeFilters[i] != null && 247 !activeFilters[i].accepts(td)) { 248 if (o != null) { 249 o.rejected(td, activeFilters[i]); 250 } else { 251 } 252 253 return false; 254 } // outer if 255 } // for 256 257 return true; 258 } 259 260 public String getBaseName() { 261 return NAME; 262 } 263 264 public String getName() { 265 return instanceName; 266 } 267 268 public String getReason() { 269 return REASON; 270 } 271 272 public String getDescription() { 273 return DESCRIPTION; 274 } 275 276 // ----- PRIVATE ----- 277 private void init(Map map) { 278 if (NAME == null) { 279 NAME = uif.getI18NString("basicTf.name"); 280 } 281 282 if (REASON == null) { 283 REASON = uif.getI18NString("basicTf.reason"); 284 } 285 286 if (DESCRIPTION == null) { 287 DESCRIPTION = uif.getI18NString("basicTf.description"); 288 } 289 290 if (map != null) { 291 activeSettings = new SettingsSnapshot(map); 292 } else { 293 activeSettings = new SettingsSnapshot(); 294 } 295 296 instanceCount++; 297 298 // not using this from superclass 299 observers = null; 300 activateSettings(activeSettings); 301 } 302 303 /** 304 * Make the given settings the active ones. 305 * Except under exceptional conditions, the filters are recreated and 306 * an update message is sent. 307 */ 308 private String activateSettings(SettingsSnapshot nowSettings) { 309 KeywordsFilter newKeyFilter = null; 310 InitialUrlFilter newUrlFilter = null; 311 TestFilter newJtxFilter = null; 312 StatusFilter newStatusFilter = null; 313 TestFilter newTsfFilter = null; 314 315 InterviewParameters ip = execModel.getInterviewParameters(); 316 TestSuite ts = execModel.getTestSuite(); 317 updateInterviewObserver(ip); 318 319 // recreate filters 320 if (nowSettings.urlsEnabled) { 321 // converting to strings to avoid any confusion 322 // files vs urls 323 if (nowSettings.initialUrls != null) { 324 newUrlFilter = new InitialUrlFilter(nowSettings.initialUrls); 325 } 326 } 327 328 if (nowSettings.keywordsEnabled) { 329 try { 330 String[] validKeywords = ts.getKeywords(); 331 HashSet<String> validKeywordsSet; 332 if (validKeywords == null) { 333 validKeywordsSet = null; 334 } else { 335 validKeywordsSet = new HashSet<>(Arrays.asList(validKeywords)); 336 } 337 338 Keywords kw = Keywords.create(kwModeToType(nowSettings.keyChoice), 339 nowSettings.keyString, validKeywordsSet); 340 newKeyFilter = new KeywordsFilter(kw); 341 } catch (Keywords.Fault f) { 342 return f.getMessage(); 343 } 344 345 } 346 347 if (nowSettings.statusEnabled) { 348 // this filter won't work without a TRT 349 TestResultTable trt = execModel.getActiveTestResultTable(); 350 if (trt != null) { 351 newStatusFilter = new StatusFilter( 352 nowSettings.statusFields, 353 trt); 354 statusFilterNeedsUpdate = false; 355 } else { 356 statusFilterNeedsUpdate = true; 357 } 358 } else { 359 // to clear any old status 360 statusFilterNeedsUpdate = false; 361 } 362 363 if (nowSettings.jtxEnabled) { 364 // we only support copying exclude list from interview 365 // right now 366 if (ip != null) { 367 // may set var. to null, but that's okay 368 newJtxFilter = ip.getExcludeListFilter(); 369 } 370 } 371 372 if (nowSettings.tsfEnabled) { 373 // we only support copying exclude list from interview 374 // right now 375 if (ip != null && ts != null) { 376 // may set filter to null, but that's okay 377 newTsfFilter = ts.createTestFilter(ip.getEnv()); 378 } 379 } 380 381 // can abort anytime before this 382 // commit now 383 keyFilter = newKeyFilter; 384 urlFilter = newUrlFilter; 385 jtxFilter = newJtxFilter; 386 statusFilter = newStatusFilter; 387 tsfFilter = newTsfFilter; 388 389 // initialize the array if not yet done so 390 if (activeFilters == null) { 391 activeFilters = new TestFilter[NUM_FILTERS]; 392 } 393 394 activeFilters[KEY_FILTER] = keyFilter; 395 activeFilters[URL_FILTER] = urlFilter; 396 activeFilters[JTX_FILTER] = jtxFilter; 397 activeFilters[STATUS_FILTER] = statusFilter; 398 activeFilters[TSS_FILTER] = tsfFilter; 399 400 activeSettings = nowSettings; 401 updateExcludeInfo(); 402 403 // notify observers 404 notifyUpdated(this); 405 return null; 406 } 407 408 private void updateStatusFilter() { 409 if (!statusFilterNeedsUpdate) 410 return; 411 412 TestResultTable trt = execModel.getActiveTestResultTable(); 413 if (trt != null) { 414 activeFilters[STATUS_FILTER] = new StatusFilter( 415 activeSettings.statusFields, 416 trt); 417 statusFilterNeedsUpdate = false; 418 } 419 } 420 421 /** 422 * Attach observer to the given interview. 423 * Automatically detaches from other interviews being observed. 424 * @param ip The interview to observe. For convenience, if this param 425 * is null, any current observers will be detached. 426 */ 427 private void updateInterviewObserver(InterviewParameters ip) { 428 if (ip == null && intObs != null) { 429 intObs.getInterview().removeObserver(intObs); 430 } else if (intObs == null || intObs.getInterview() != ip) { 431 if (intObs != null) { 432 intObs.getInterview().removeObserver(intObs); 433 } 434 435 if (ip != null) { 436 intObs = new InterviewObserver(ip); 437 ip.addObserver(intObs); 438 } 439 } 440 } 441 442 private void updateExcludeInfo() { 443 // check to see if GUI is init-ed 444 if (jtxMode == null) { 445 return; 446 } 447 448 InterviewParameters ip = execModel.getInterviewParameters(); 449 450 if (ip == null) // nothing to do 451 { 452 return; 453 } 454 455 boolean isUnknown = true; 456 ExcludeListParameters elp = ip.getExcludeListParameters(); 457 458 if (ip != null) { 459 elp = ip.getExcludeListParameters(); 460 if (elp instanceof MutableExcludeListParameters) { 461 MutableExcludeListParameters melp = (MutableExcludeListParameters) elp; 462 int mode = melp.getExcludeMode(); 463 switch (mode) { 464 case MutableExcludeListParameters.NO_EXCLUDE_LIST: 465 jtxMode.setText(uif.getI18NString("basicTf.exclude.mode.none")); 466 setExcludeFiles(null); 467 isUnknown = false; 468 break; 469 case MutableExcludeListParameters.INITIAL_EXCLUDE_LIST: 470 jtxMode.setText(uif.getI18NString("basicTf.exclude.mode.initial")); 471 setExcludeFiles(melp.getExcludeFiles()); 472 isUnknown = false; 473 break; 474 case MutableExcludeListParameters.LATEST_EXCLUDE_LIST: 475 jtxMode.setText(uif.getI18NString("basicTf.exclude.mode.latest")); 476 setExcludeFiles(null); 477 isUnknown = false; 478 break; 479 case MutableExcludeListParameters.CUSTOM_EXCLUDE_LIST: 480 jtxMode.setText(uif.getI18NString("basicTf.exclude.mode.custom")); 481 setExcludeFiles(melp.getCustomExcludeFiles()); 482 isUnknown = false; 483 break; 484 } // switch 485 486 } 487 } 488 489 // done here to avoid duplicating code above 490 if (isUnknown) { 491 jtxMode.setText(uif.getI18NString("basicTf.exclude.mode.unknown")); 492 jtxFiles.removeAllElements(); 493 } 494 } 495 496 /** 497 * Adds exclude list files to the list. 498 * If null or zero length, the list is cleared. 499 * @param files The files to add. Null ok. 500 */ 501 private void setExcludeFiles(File[] files) { 502 jtxFiles.removeAllElements(); 503 504 if (files == null || files.length == 0) { 505 return; 506 } else { 507 for (int i = 0; i < files.length; i++) { 508 jtxFiles.addElement(files[i].getPath()); 509 } 510 } 511 } 512 513 private JComponent[] createTabPanels() { 514 JComponent[] items = {createTestsPanel(), createKeywordPanel(), 515 createStatusPanel(), createExcludePanel(), 516 createSpecialPanel()}; 517 518 return items; 519 } 520 521 // KEYWORD PANEL 522 private JComponent createKeywordPanel() { 523 JPanel p = uif.createPanel( 524 "basicTf.keywords.mainPanel", new GridBagLayout(), false); 525 p.setName("keywords"); 526 527 GridBagConstraints c = new GridBagConstraints(); 528 c.gridwidth = GridBagConstraints.REMAINDER; 529 c.fill = GridBagConstraints.HORIZONTAL; 530 c.weightx = 1; 531 532 keyBtnGrp = new ButtonGroup(); 533 keyAllBtn = uif.createRadioButton("basicTf.keywords.all", keyBtnGrp); 534 keyAllBtn.setMnemonic(uif.getI18NString("basicTf.keywords.all.mne").charAt(0)); 535 p.add(keyAllBtn, c); 536 537 keyMatchBtn = uif.createRadioButton("basicTf.keywords.match", keyBtnGrp); 538 keyMatchBtn.setMnemonic(uif.getI18NString("basicTf.keywords.match.mne").charAt(0)); 539 keyMatchBtn.addChangeListener(new ChangeListener() { 540 541 public void stateChanged(ChangeEvent e) { 542 enableKeywordFields(); 543 } 544 }); 545 c.weightx = 0; 546 c.gridwidth = 1; 547 p.add(keyMatchBtn, c); 548 549 String[] kc = {ANY_OF, ALL_OF, EXPR}; 550 keywordsChoice = uif.createChoice("basicTf.keywords.choice", kc); 551 p.add(keywordsChoice, c); 552 553 keywordsField = uif.createInputField("basicTf.keywords.field", 20); 554 keywordsField.setEditable(true); 555 uif.setAccessibleInfo(keywordsField, "basicTf.keywords.field"); 556 c.fill = GridBagConstraints.HORIZONTAL; 557 c.gridwidth = GridBagConstraints.REMAINDER; 558 c.weightx = 1; 559 p.add(keywordsField, c); 560 561 keyAllBtn.setSelected(true); 562 enableKeywordFields(); 563 return p; 564 } 565 566 private void enableKeywordFields() { 567 boolean b = keyMatchBtn.isSelected(); 568 keywordsChoice.setEnabled(b); 569 keywordsField.setEnabled(b); 570 } 571 572 // STATUS PANEL 573 private JComponent createStatusPanel() { 574 JPanel p = uif.createPanel( 575 "basicTf.status.mainPanel", new GridBagLayout(), false); 576 p.setName("status"); 577 578 GridBagConstraints c = new GridBagConstraints(); 579 c.anchor = GridBagConstraints.WEST; 580 c.gridwidth = GridBagConstraints.REMAINDER; 581 582 statusBtnGrp = new ButtonGroup(); 583 statusAllBtn = uif.createRadioButton("basicTf.status.all", statusBtnGrp); 584 statusAllBtn.setMnemonic(uif.getI18NString("basicTf.status.all.mne").charAt(0)); 585 p.add(statusAllBtn, c); 586 587 statusAnyOfBtn = uif.createRadioButton("basicTf.status.anyOf", statusBtnGrp); 588 statusAnyOfBtn.setMnemonic(uif.getI18NString("basicTf.status.anyOf.mne").charAt(0)); 589 statusAnyOfBtn.addChangeListener(new ChangeListener() { 590 591 public void stateChanged(ChangeEvent e) { 592 enableStatusFields(); 593 } 594 }); 595 c.gridwidth = 1; 596 c.weightx = 0; 597 p.add(statusAnyOfBtn, c); 598 599 JPanel row = new JPanel(new GridBagLayout()); 600 row.setBorder(BorderFactory.createEtchedBorder()); 601 GridBagConstraints rc = new GridBagConstraints(); 602 rc.insets.left = 10; 603 604 statusChecks[Status.PASSED] = 605 uif.createCheckBox("basicTf.status.prev.passed", false); 606 row.add(statusChecks[Status.PASSED], rc); 607 608 statusChecks[Status.FAILED] = 609 uif.createCheckBox("basicTf.status.prev.failed", true); 610 row.add(statusChecks[Status.FAILED], rc); 611 612 statusChecks[Status.ERROR] = 613 uif.createCheckBox("basicTf.status.prev.error", true); 614 row.add(statusChecks[Status.ERROR], rc); 615 616 rc.insets.right = 10; 617 statusChecks[Status.NOT_RUN] = 618 uif.createCheckBox("basicTf.status.prev.notRun", true); 619 row.add(statusChecks[Status.NOT_RUN], rc); 620 uif.setToolTip(row, "basicTf.status.prev"); 621 622 statusAllBtn.setSelected(true); 623 enableStatusFields(); 624 p.add(row, c); 625 626 return p; 627 } 628 629 private void enableStatusFields() { 630 boolean enable = statusAnyOfBtn.isEnabled() && statusAnyOfBtn.isSelected(); 631 for (int i = 0; i < statusChecks.length; i++) { 632 statusChecks[i].setEnabled(enable); 633 } 634 } 635 636 // INIT URLS 637 private JComponent createTestsPanel() { 638 final JPanel p = uif.createPanel( 639 "basicTf.tests.mainPanel", new BorderLayout(), false); 640 p.setName("tests"); 641 642 // more configure ... 643 lastTrt = execModel.getActiveTestResultTable(); 644 testsField = new TestTreeSelectionPane(lastTrt); 645 646 p.add(testsField, BorderLayout.CENTER); 647 648 p.addComponentListener(new ComponentAdapter() { 649 650 public void componentShown(ComponentEvent e) { 651 TestResultTable nowTrt = execModel.getActiveTestResultTable(); 652 // replaces widget with an updated one 653 // only really important if the test suite contents (structure) 654 // changes 655 // this code basically keeps it in sync with the main tree, 656 // otherwise it might be left behind watching a temporary TRT 657 if (nowTrt != lastTrt) { 658 TestTreeSelectionPane newTree = new TestTreeSelectionPane(nowTrt); 659 String[] paths = testsField.getSelection(); // save 660 p.remove(testsField); 661 testsField = newTree; 662 testsField.setSelection(paths); // restore 663 p.add(testsField, BorderLayout.CENTER); 664 lastTrt = nowTrt; 665 } 666 } 667 }); 668 669 return p; 670 } 671 672 // JTX lists 673 private JComponent createExcludePanel() { 674 JPanel p = new JPanel(new GridBagLayout()); 675 p.setName("exclude"); 676 677 GridBagConstraints c = new GridBagConstraints(); 678 c.anchor = GridBagConstraints.NORTHWEST; 679 c.ipadx = 10; 680 c.gridwidth = 1; 681 c.gridx = 0; 682 c.gridy = 0; 683 c.fill = GridBagConstraints.NONE; 684 685 // column 1 686 c.gridwidth = 3; 687 jtxCheckBox = uif.createCheckBox("basicTf.exclude", false); 688 jtxCheckBox.setMnemonic(uif.getI18NString("basicTf.exclude.mne").charAt(0)); 689 p.add(jtxCheckBox, c); 690 691 // create some margins 692 c.gridy = 1; 693 p.add(Box.createVerticalStrut(5), c); 694 695 c.gridy = 2; 696 c.gridwidth = 1; 697 698 c.gridheight = 2; 699 p.add(Box.createHorizontalStrut(8), c); 700 701 c.gridheight = 1; 702 c.gridx = 2; 703 704 // labels 705 final JLabel modeLab = uif.createLabel("basicTf.exclude.mode"); 706 modeLab.setDisplayedMnemonic(uif.getI18NString("basicTf.exclude.mode.mne").charAt(0)); 707 modeLab.setEnabled(jtxCheckBox.isSelected()); 708 p.add(modeLab, c); 709 710 c.gridy = 3; 711 final JLabel fileLab = uif.createLabel("basicTf.exclude.file"); 712 fileLab.setDisplayedMnemonic(uif.getI18NString("basicTf.exclude.file.mne").charAt(0)); 713 fileLab.setEnabled(jtxCheckBox.isSelected()); 714 p.add(fileLab, c); 715 716 // column 2 717 c.gridy = 2; 718 c.gridx = 3; 719 c.fill = GridBagConstraints.HORIZONTAL; 720 jtxMode = uif.createOutputField("basicTf.exclude.mode", modeLab); 721 jtxMode.setBorder(BorderFactory.createEmptyBorder()); 722 jtxMode.setEditable(false); 723 jtxMode.setEnabled(jtxCheckBox.isSelected()); 724 uif.setAccessibleInfo(jtxMode, "basicTf.exclude.mode"); 725 p.add(jtxMode, c); 726 727 c.gridy = 3; 728 c.weightx = 2; 729 c.weighty = 2; 730 c.fill = GridBagConstraints.BOTH; 731 jtxFiles = new DefaultListModel<String>(); 732 jtxFileList = uif.createList("basicTf.exclude.file", jtxFiles); 733 jtxFileList.setEnabled(jtxCheckBox.isSelected()); 734 uif.setAccessibleInfo(jtxFileList, "basicTf.exclude.file"); 735 fileLab.setLabelFor(jtxFileList); 736 737 // might need to add a scroll panel here 738 p.add(uif.createScrollPane(jtxFileList, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 739 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED), c); 740 741 jtxCheckBox.addActionListener(new ActionListener() { 742 743 public void actionPerformed(ActionEvent e) { 744 jtxFileList.setEnabled(jtxCheckBox.isSelected()); 745 jtxMode.setEnabled(jtxCheckBox.isSelected()); 746 modeLab.setEnabled(jtxCheckBox.isSelected()); 747 fileLab.setEnabled(jtxCheckBox.isSelected()); 748 } 749 }); 750 751 return p; 752 } 753 754 // test suite specific filter 755 private JComponent createSpecialPanel() { 756 String k = "basicTf.tsf"; 757 JPanel p = uif.createPanel("basicTf.tsf", new BorderLayout(), false); 758 p.setName("special"); 759 760 tsfCheckBox = uif.createCheckBox("basicTf.tsf", false); 761 tsfCheckBox.setMnemonic(uif.getI18NString("basicTf.tsf.mne").charAt(0)); 762 p.add(tsfCheckBox, BorderLayout.CENTER); 763 764 return p; 765 } 766 767 /** 768 * Capture the settings in the current GUI. 769 * @return A snapshot of the settings currently entred into the GUI. 770 * @throws IllegalStateException If any part of the GUI has a state which 771 * does not produce a consistent setting. The message of this 772 * exception will contain an internationalized message to help the 773 * user resolve the problem. 774 */ 775 private SettingsSnapshot grabSettings() { 776 SettingsSnapshot shot = new SettingsSnapshot(); 777 778 // grad top level togggle state of each type 779 shot.keywordsEnabled = !keyAllBtn.isSelected(); 780 //shot.urlsEnabled = !allTestsBtn.isSelected(); 781 shot.urlsEnabled = true; // always enabled in current impl. 782 shot.statusEnabled = statusAnyOfBtn.isSelected(); 783 shot.jtxEnabled = jtxCheckBox.isSelected(); 784 shot.tsfEnabled = tsfCheckBox.isSelected(); 785 786 // grab status checkbox state 787 boolean oneSelected = false; 788 shot.statusFields = new boolean[statusChecks.length]; 789 for (int i = 0; i < statusChecks.length; i++) { 790 shot.statusFields[i] = statusChecks[i].isSelected(); 791 oneSelected = oneSelected || shot.statusFields[i]; 792 } 793 794 if (shot.statusEnabled && !oneSelected) { 795 throw new IllegalStateException(uif.getI18NString("basicTf.badStatus")); 796 } 797 798 // init. urls 799 shot.initialUrls = testsField.getSelection(); 800 801 // special case post processing for root selection 802 // if length is one and that string is zero length, that indicates 803 // a root selection 804 if (shot.initialUrls != null && 805 shot.initialUrls.length == 1 && 806 shot.initialUrls[0].length() == 0) { 807 shot.initialUrls = null; 808 } 809 810 // keywords 811 shot.keyChoice = (String) (keywordsChoice.getSelectedItem()); 812 shot.keyString = keywordsField.getText(); 813 814 return shot; 815 } 816 817 /** 818 * Put a set of settings into the GUI. 819 */ 820 private void putSettings(SettingsSnapshot s) { 821 // no GUI, don't do anything 822 if (editorPane == null) { 823 return; 824 } 825 826 keyAllBtn.setSelected(!s.keywordsEnabled); 827 keyMatchBtn.setSelected(s.keywordsEnabled); 828 829 statusAllBtn.setSelected(!s.statusEnabled); 830 statusAnyOfBtn.setSelected(s.statusEnabled); 831 832 jtxCheckBox.setSelected(s.jtxEnabled); 833 tsfCheckBox.setSelected(s.tsfEnabled); 834 835 for (int i = 0; i < statusChecks.length; i++) { 836 statusChecks[i].setSelected(s.statusFields[i]); 837 } 838 839 testsField.setSelection(s.initialUrls); 840 841 keywordsChoice.setSelectedItem(s.keyChoice); 842 keywordsField.setText(s.keyString); 843 844 updateExcludeInfo(); 845 } 846 847 // Utility methods 848 private static String kwModeToType(String mode) { 849 if (mode == ALL_OF) { 850 return "all of"; 851 } else if (mode == ANY_OF) { 852 return "any of"; 853 } else { 854 return EXPR; 855 } 856 } 857 858 private Observer[] obs = new Observer[0]; 859 private static int instanceCount; 860 private TestResultTable lastTrt; 861 private InterviewObserver intObs; 862 863 private static int NUM_FILTERS = 5; 864 private static int KEY_FILTER = 0; 865 private static int URL_FILTER = 1; 866 private static int JTX_FILTER = 2; 867 private static int STATUS_FILTER = 3; 868 private static int TSS_FILTER = 4; 869 870 private SettingsSnapshot activeSettings; 871 private TestFilter[] activeFilters; // for convenience 872 private KeywordsFilter keyFilter; 873 private InitialUrlFilter urlFilter; 874 private TestFilter jtxFilter; 875 private StatusFilter statusFilter; 876 private TestFilter tsfFilter; // test suite filter 877 private final UIFactory uif; 878 private JTabbedPane editorPane; 879 880 private boolean statusFilterNeedsUpdate; 881 882 // keyword info 883 private ButtonGroup keyBtnGrp; 884 private JRadioButton keyAllBtn; 885 private JRadioButton keyMatchBtn; 886 private JComboBox keywordsChoice; 887 private JTextField keywordsField; 888 private static final String ALL_OF = "allOf"; 889 private static final String ANY_OF = "anyOf"; 890 private static final String EXPR = "expr"; 891 892 // status info 893 private ButtonGroup statusBtnGrp; 894 private JRadioButton statusAllBtn; 895 private JRadioButton statusAnyOfBtn; 896 private JCheckBox[] statusChecks = new JCheckBox[Status.NUM_STATES]; 897 898 // tests info 899 private ButtonGroup testsBtnGrp; 900 //private JRadioButton allTestsBtn; 901 //private JRadioButton selectTestsBtn; 902 private TestTreeSelectionPane testsField; 903 904 // checkboxes to enable exclude list from interview and test suite filter 905 private JCheckBox jtxCheckBox; 906 private JCheckBox tsfCheckBox; 907 908 // jtx info fields 909 private JTextField jtxMode; 910 private JList jtxFileList; 911 private DefaultListModel<String> jtxFiles; 912 private static String NAME, REASON, DESCRIPTION; 913 914 /** 915 * Necessary to track changes which occur in the active interview. 916 */ 917 private class InterviewObserver implements Interview.Observer { 918 919 InterviewObserver(InterviewParameters i) { 920 interview = i; 921 } 922 923 InterviewParameters getInterview() { 924 return interview; 925 } 926 927 public void currentQuestionChanged(Question q) { 928 // ignore 929 } 930 931 public void pathUpdated() { 932 TestFilter underTest; 933 boolean needsUpdate = false; 934 updateExcludeInfo(); 935 936 // determine if jtx and tsf filters were updated 937 if (activeSettings.jtxEnabled) { 938 // we only support copying exclude list from interview 939 // right now 940 InterviewParameters ip = execModel.getInterviewParameters(); 941 942 if (ip != null) { 943 // may set var. to null, but that's okay 944 underTest = ip.getExcludeListFilter(); 945 if (underTest != null && 946 (jtxFilter == null || !underTest.equals(jtxFilter))) { 947 needsUpdate = true; 948 } else if (jtxFilter != null) // jtx filter now null 949 { 950 needsUpdate = true; 951 } 952 } 953 } 954 955 if (needsUpdate) { 956 activateSettings(activeSettings); 957 return; // rest of checking no longer needed 958 } 959 960 if (activeSettings.tsfEnabled) { 961 // we only support copying exclude list from interview 962 // right now 963 InterviewParameters ip = execModel.getInterviewParameters(); 964 TestSuite ts = execModel.getTestSuite(); 965 966 if (ip != null && ts != null) { 967 underTest = ts.createTestFilter(ip.getEnv()); 968 if (underTest != null) { 969 if (tsfFilter == null || !underTest.equals(tsfFilter)) { 970 needsUpdate = true; 971 } else { 972 } 973 } else if (tsfFilter != null) // tsf filter now null 974 { 975 needsUpdate = true; 976 } else { 977 } 978 } else { 979 } 980 } 981 982 if (needsUpdate) { 983 activateSettings(activeSettings); 984 return; // rest of checking no longer needed 985 } 986 } 987 private InterviewParameters interview; 988 } 989 990 private class SettingsSnapshot { 991 992 SettingsSnapshot() { 993 statusFields = new boolean[Status.NUM_STATES]; 994 urlsEnabled = true; 995 keyChoice = EXPR; 996 keyString = ""; 997 } 998 999 SettingsSnapshot(Map m) { 1000 this(); 1001 load(m); 1002 } 1003 1004 public boolean equals(Object settings) { 1005 1006 if (settings == null) { 1007 return false; 1008 } 1009 1010 SettingsSnapshot incoming = (SettingsSnapshot) settings; 1011 1012 if (!Arrays.equals(initialUrls, incoming.initialUrls)) { 1013 return false; 1014 } 1015 1016 if (keywordsEnabled != incoming.keywordsEnabled) { 1017 return false; 1018 } else { 1019 if (keyChoice != incoming.keyChoice) { 1020 return false; 1021 } 1022 1023 // destination of structure is to handle null values 1024 if (keyString == null) { 1025 if (keyString != incoming.keyString) { 1026 return false; 1027 } else { 1028 } 1029 } else { 1030 if (!keyString.equals(incoming.keyString)) { 1031 return false; 1032 } else { 1033 } 1034 } 1035 } // outer else 1036 1037 if (statusEnabled != incoming.statusEnabled) { 1038 return false; 1039 } else if (!Arrays.equals(statusFields, incoming.statusFields)) { 1040 return false; 1041 } 1042 1043 if (jtxEnabled != incoming.jtxEnabled) { 1044 return false; 1045 } 1046 1047 if (tsfEnabled != incoming.tsfEnabled) { 1048 return false; 1049 } 1050 1051 return true; 1052 } // equals() 1053 1054 void save(Map<String, String> map) { 1055 map.put(MAP_URL_ENABLE, booleanToInt(urlsEnabled)); 1056 map.put(MAP_KEY_ENABLE, booleanToInt(keywordsEnabled)); 1057 map.put(MAP_STATUS_ENABLE, booleanToInt(statusEnabled)); 1058 map.put(MAP_JTX_ENABLE, booleanToInt(jtxEnabled)); 1059 map.put(MAP_TSF_ENABLE, booleanToInt(tsfEnabled)); 1060 1061 for (int i = 0; i < statusFields.length; i++) { 1062 map.put(MAP_STATUS_PREFIX + i, booleanToInt(statusFields[i])); 1063 } 1064 1065 map.put(MAP_URLS, StringArray.join(initialUrls)); 1066 1067 map.put(MAP_KEY_CHOICE, keyChoice); 1068 map.put(MAP_KEY_STRING, keyString); 1069 } 1070 1071 void load(Map map) { 1072 urlsEnabled = intToBoolean((String) (map.get(MAP_URL_ENABLE))); 1073 keywordsEnabled = intToBoolean((String) (map.get(MAP_KEY_ENABLE))); 1074 statusEnabled = intToBoolean((String) (map.get(MAP_STATUS_ENABLE))); 1075 jtxEnabled = intToBoolean((String) (map.get(MAP_JTX_ENABLE))); 1076 tsfEnabled = intToBoolean((String) (map.get(MAP_TSF_ENABLE))); 1077 1078 for (int i = 0; i < Status.NUM_STATES; i++) { 1079 statusFields[i] = intToBoolean((String) (map.get(MAP_STATUS_PREFIX + i))); 1080 } // for 1081 1082 initialUrls = StringArray.split((String) (map.get(MAP_URLS))); 1083 1084 keyChoice = (String) (map.get(MAP_KEY_CHOICE)); 1085 keyString = (String) (map.get(MAP_KEY_STRING)); 1086 1087 validate(); 1088 } 1089 1090 private void validate() { 1091 // conserve strings, but also sync with the actual 1092 // objects in the choice list for easy use 1093 if (keyChoice.equals(ALL_OF)) { 1094 keyChoice = ALL_OF; 1095 } else if (keyChoice.equals(ANY_OF)) { 1096 keyChoice = ANY_OF; 1097 } else if (keyChoice.equals(EXPR)) { 1098 keyChoice = EXPR; 1099 } else { 1100 keyChoice = ALL_OF; // unknown, use default 1101 } 1102 } 1103 1104 String booleanToInt(boolean val) { 1105 if (val) { 1106 return "1"; 1107 } else { 1108 return "0"; 1109 } 1110 } 1111 1112 boolean intToBoolean(String num) { 1113 if (num == null) { 1114 return false; 1115 } 1116 1117 if (num.equals("1")) { 1118 return true; 1119 } else { 1120 return false; 1121 } 1122 } 1123 boolean urlsEnabled; 1124 boolean keywordsEnabled; 1125 boolean statusEnabled; 1126 boolean jtxEnabled; 1127 boolean tsfEnabled; 1128 boolean[] statusFields; 1129 String[] initialUrls; 1130 String keyChoice; 1131 String keyString; 1132 private static final String MAP_URL_ENABLE = "urlsEnabled"; 1133 private static final String MAP_KEY_ENABLE = "keyEnabled"; 1134 private static final String MAP_STATUS_ENABLE = "statusEnable"; 1135 private static final String MAP_JTX_ENABLE = "jtxEnable"; 1136 private static final String MAP_TSF_ENABLE = "tsfEnable"; 1137 private static final String MAP_URLS = "urls"; 1138 private static final String MAP_KEY_CHOICE = "keyChoice"; 1139 private static final String MAP_KEY_STRING = "keyString"; 1140 private static final String MAP_STATUS_PREFIX = "status"; 1141 } 1142 }