1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 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.Component;
  31 import java.awt.CardLayout;
  32 import java.awt.Dimension;
  33 import java.awt.Frame;
  34 import java.awt.GridBagConstraints;
  35 import java.awt.GridBagLayout;
  36 import java.awt.event.ComponentAdapter;
  37 import java.awt.event.ComponentEvent;
  38 import java.util.Hashtable;
  39 import java.awt.event.ActionEvent;
  40 import java.awt.event.ActionListener;
  41 
  42 import javax.swing.BorderFactory;
  43 import javax.swing.DefaultListModel;
  44 import javax.swing.JButton;
  45 import javax.swing.JComponent;
  46 import javax.swing.JLabel;
  47 import javax.swing.JList;
  48 import javax.swing.JPanel;
  49 import javax.swing.JSplitPane;
  50 import javax.swing.JTextArea;
  51 import javax.swing.JTextField;
  52 import javax.swing.ListModel;
  53 import javax.swing.SwingConstants;
  54 import javax.swing.event.ListSelectionEvent;
  55 import javax.swing.event.ListSelectionListener;
  56 
  57 import com.sun.javatest.ObservableTestFilter;
  58 import com.sun.javatest.TestFilter;
  59 import com.sun.javatest.TestSuite;
  60 import com.sun.javatest.tool.ToolDialog;
  61 import com.sun.javatest.tool.UIFactory;
  62 import com.sun.javatest.util.Debug;
  63 import com.sun.javatest.util.DynamicArray;
  64 
  65 /**
  66  * The primary purpose is to hold the a variety of named filter sets from
  67  * which the user will select one (the "active" one).
  68  */
  69 public class FilterConfig {
  70      /**
  71       * Observe changes to the state of the view.  The changes to the view state
  72       * will generally be the result of user actions.
  73       */
  74     public interface Observer {
  75        /**
  76         * The state of the given filter has changed.
  77         */
  78         public void filterUpdated(TestFilter f);
  79 
  80         public void filterAdded(TestFilter f);
  81 
  82        /**
  83         * Removing the active filter will result in an exception.
  84         */
  85         public void filterRemoved(TestFilter f);
  86     }
  87 
  88     public FilterConfig(ExecModel e, JComponent parent, UIFactory uif) {
  89         // load default filters here instead of ExecTool to avoid instantiating
  90         // them
  91         execModel = e;
  92         this.parentComponent = parent;
  93         this.uif = uif;
  94     }
  95 
  96     /**
  97      * Add a test filter to the list of possible filters.
  98      * Care should be taken not to add a filter more than once.
  99      */
 100     synchronized void add(TestFilter f) {
 101         if (f == null)
 102             return;
 103 
 104         // record this filter officially
 105         filters = (TestFilter[])DynamicArray.append(filters, f);
 106 
 107         // register as change observer if possible
 108         if (f instanceof ObservableTestFilter) {
 109             ((ObservableTestFilter)f).addObserver(listener);
 110         }
 111 
 112         if (f instanceof ConfigurableTestFilter && fep != null) {
 113             fep.addConfigurableFilter((ConfigurableTestFilter)f);
 114         }
 115 
 116         // tell people about the addition
 117         // obs should never be null
 118         for (int i = 0; i < obs.length; i++)
 119             obs[i].filterAdded(f);
 120 
 121         if (fep != null)
 122             fep.listModel.addElement(f);
 123     }
 124 
 125     /**
 126      * Remove a test filter from the list of possible filters.
 127      * You cannot remove the active filter.
 128      *
 129      * @param f Should not be null.  Should also be a filter which was previously
 130      *        added to this object.
 131      * @throws FilterInUseFault Thrown if you try to remove the active filter.
 132      */
 133     synchronized void remove(TestFilter f) {
 134         if (f == null)
 135             return;
 136 
 137         // remove this filter officially
 138         filters = (TestFilter[])DynamicArray.remove(filters, f);
 139 
 140         if (f instanceof ObservableTestFilter)
 141             ((ObservableTestFilter)f).removeObserver(listener);
 142 
 143         if (f instanceof ConfigurableTestFilter && fep != null) {
 144             fep.removeConfigurableFilter((ConfigurableTestFilter)f);
 145         }
 146 
 147         // tell people about the removal
 148         // obs should never be null
 149         for (int i = 0; i < obs.length; i++)
 150             obs[i].filterRemoved(f);
 151 
 152         if (fep != null)
 153             fep.listModel.removeElement(f);
 154     }
 155 
 156     synchronized String[] getFilterNames() {
 157         int count = filters.length;
 158         String[] names = new String[count];
 159 
 160         for (int i = 0; i < count; i++)
 161             names[i] = filters[i].getName();
 162 
 163         return names;
 164     }
 165 
 166     synchronized TestFilter[] getFilters() {
 167         int count = filters.length;
 168         TestFilter[] copy = new TestFilter[count];
 169         System.arraycopy(filters, 0, copy, 0, count);
 170 
 171         return copy;
 172     }
 173 
 174     /**
 175      * Get a filter by name.
 176      *
 177      * @return Null if no match.
 178      */
 179     synchronized TestFilter getFilter(String name) {
 180         int count = filters.length;
 181 
 182         for (int i = 0; i < count; i++)
 183             if (name.equals(filters[i].getName()))
 184                 return filters[i];
 185 
 186         // not found
 187         return null;
 188     }
 189 
 190     /**
 191      * Does the view contain the given filter.
 192      * Done by reference compare.
 193      */
 194     synchronized boolean contains(TestFilter f) {
 195         for (int i = 0; i < filters.length; i++)
 196             if (filters[i] == f)
 197                 return true;
 198 
 199         // not found
 200         return false;
 201     }
 202 
 203     synchronized FilterSelectionHandler createFilterSelectionHandler() {
 204         FilterSelectionHandler fsh = new FilterSelectionHandler(this, uif);
 205         handlers = (FilterSelectionHandler[])DynamicArray.append(handlers, fsh);
 206 
 207         return fsh;
 208     }
 209 
 210     public synchronized void addObserver(Observer o) {
 211         if (o == null)
 212             return;
 213 
 214         if (obs == null)
 215             obs = new Observer[0];
 216 
 217         obs = (Observer[])DynamicArray.append(obs, o);
 218     }
 219 
 220     public synchronized void removeObserver(Observer o) {
 221         obs = (Observer[])DynamicArray.remove(obs, o);
 222     }
 223 
 224     /**
 225      * Notify all observers that a filter has changed state.
 226      * This call has no effect if the given filter is not the active
 227      * view filter.
 228      */
 229     synchronized void notifyUpdated(TestFilter f) {
 230         if (obs == null)    // this really should not happen
 231             return;
 232 
 233         for (int i = 0; i < obs.length; i++) {
 234             obs[i].filterUpdated(f);
 235         }   // for
 236     }
 237 
 238     /**
 239      * Show the filter editor.
 240      */
 241     synchronized void showEditorDialog() {
 242         if (fep == null)
 243             fep = new FilterEditorPanel(parentComponent, uif);
 244 
 245         fep.setVisible(true);
 246     }
 247 
 248     /**
 249      * Show the filter editor, with the given filter selected.
 250      * @param f the filter to show the user initially
 251      */
 252     synchronized void showEditorDialog(TestFilter f) {
 253         if (fep == null)
 254             fep = new FilterEditorPanel(parentComponent, uif);
 255 
 256         fep.setSelectedFilter(f);
 257         fep.setVisible(true);
 258     }
 259 
 260     /**
 261      * Hide the editor dialog.  No effect if the dialog isn't visible or
 262      * initialized.
 263      */
 264     synchronized void hideEditorDialog(Frame parent) {
 265         fep.setVisible(false);
 266     }
 267 
 268     private class Listener
 269         extends ComponentAdapter
 270         implements ObservableTestFilter.Observer
 271     {
 272         public void filterUpdated(ObservableTestFilter otf) {
 273             notifyUpdated(otf);
 274         }
 275 
 276         // ComponentListener
 277         public void componentHidden(ComponentEvent e) {
 278             fep.doReset();
 279         }
 280     }
 281 
 282     // too much overhead to impl. all the methods if we use a Vector
 283     // we'll accept the hit when we add a new filter, which isn't that
 284     // often
 285     private TestFilter[] filters = new TestFilter[0];
 286     private UIFactory uif;
 287     private ExecModel execModel;
 288     private Listener listener = new Listener();
 289     private Observer[] obs = new Observer[0];
 290     private FilterSelectionHandler[] handlers;
 291 
 292     //private JDialog editDialog;
 293     private FilterEditorPanel fep;
 294     private JComponent parentComponent;
 295 
 296     private static boolean debug = Debug.getBoolean(FilterConfig.class);
 297 
 298     private class FilterEditorPanel
 299         extends ToolDialog
 300         implements ListSelectionListener, ActionListener
 301     {
 302         FilterEditorPanel(Component parent, UIFactory uif) {
 303             super(parent, uif, "fconfig");
 304         }
 305 
 306         // ActionListener
 307         public void actionPerformed(ActionEvent e) {
 308             Object source = e.getSource();
 309             String result = null;
 310 
 311             if (source == doneBut) {
 312 
 313                 if (mode == EDITABLE) {
 314                     //Debug.println("FC - in edit mode, attempting to save.");
 315                     result = doApply();
 316                 }
 317                 else {
 318                     //Debug.println("FC - not in edit mode, not attempting to save.");
 319                 }
 320 
 321                 if (result == null)
 322                     //OLD editDialog.hide();
 323                     setVisible(false);
 324                 else {
 325                     // save failed...
 326                 }
 327             }
 328             else if (source == applyBut) {
 329                 result = doApply();
 330             }
 331             else if (source == resetBut) {
 332                 if (mode == EDITABLE)
 333                     doReset();
 334             }
 335             else if (source == cancelBut) {
 336                 if (mode == EDITABLE)
 337                     doReset();
 338 
 339                 //OLD editDialog.hide();
 340                 setVisible(false);
 341             }
 342             /*
 343             else if (source == createBut) {
 344                 Object tf = (TestFilter)(leftList.getSelectedValue());
 345                 if (!(tf instanceof ConfigurableTestFilter))
 346                     throw new IllegalStateException("");
 347 
 348                 ConfigurableTestFilter ctf = (ConfigurableTestFilter)tf;
 349 
 350                 FilterConfig.this.add(ctf.cloneInstance());
 351             }
 352             else if (source == deleteBut) {
 353                 Object tf = (TestFilter)(leftList.getSelectedValue());
 354                 if (!(tf instanceof ConfigurableTestFilter))
 355                     throw new IllegalStateException("");
 356 
 357                 ConfigurableTestFilter ctf = (ConfigurableTestFilter)tf;
 358 
 359                 FilterConfig.this.remove(ctf);
 360             }
 361             */
 362 
 363             if (result != null) {       // error occurred
 364                 uif.showError("fconfig.commit", result);
 365             }
 366         }
 367 
 368         void setSelectedFilter(TestFilter f) {
 369             if (listModel != null) {
 370                 int ind = listModel.indexOf(f);
 371                 if (ind >= 0)
 372                     selectIndex(ind);
 373             }
 374             else {
 375                 // necessary for correct initialization, since the ToolDialog
 376                 // does lazy initialization
 377                 // initGUI() will process this later
 378                 selectedFilter = f;
 379             }
 380         }
 381 
 382         // ListSelectionListener
 383         public void valueChanged(ListSelectionEvent e) {
 384             //int newSelected = e.getLastIndex();
 385             int newSelected = leftList.getSelectedIndex();
 386             // list selection has changed
 387             if (newSelected < 0) {
 388                 selectIndex(0);
 389                 lastSelected = 0;
 390             }
 391             else if (newSelected != lastSelected) {
 392                 selectIndex(newSelected);
 393                 lastSelected = newSelected;
 394             }
 395         }
 396 
 397         /**
 398          * Process a list selection change.  It is assumed that the selection
 399          * does not equal the current/last selection.  This should always be
 400          * called on the event thread.
 401          */
 402         private void selectIndex(int index) {
 403             leftList.setSelectedIndex(index);
 404 
 405             // update right panel
 406             selectedFilter = (TestFilter)(listModel.elementAt(index));
 407             if (selectedFilter instanceof ConfigurableTestFilter) {
 408                 if (mode == -1 || mode == UNEDITABLE) {
 409                     nameCards.show(namePanel, NAMING_ACTIVE);
 410                     //deleteBut.setEnabled(true);
 411                     //createBut.setEnabled(true);
 412                     applyBut.setEnabled(true);
 413                     resetBut.setEnabled(true);
 414                     mode = EDITABLE;
 415                 }
 416 
 417                 ConfigurableTestFilter ctf = (ConfigurableTestFilter)selectedFilter;
 418                 namingName.setText(ctf.getName());
 419 
 420                 String cardKey = configPanelHash.get(ctf);
 421                 configCards.show(configPanel, cardKey);
 422             }
 423             else if (selectedFilter instanceof TestFilter) {
 424                 if (mode == -1 || mode == EDITABLE) {
 425                     nameCards.show(namePanel, NAMING_EMPTY);
 426                     configCards.show(configPanel, CONFIG_EMPTY);
 427                     //createBut.setEnabled(false);
 428                     //deleteBut.setEnabled(false);
 429                     applyBut.setEnabled(false);
 430                     resetBut.setEnabled(false);
 431                     mode = UNEDITABLE;
 432                 }
 433             }
 434             else {
 435                 // hummm
 436             }
 437 
 438             fillInfo(selectedFilter);
 439             leftList.requestFocus();
 440         }
 441 
 442         protected void initGUI() {
 443             setHelp("execFilters.dialog.csh");
 444 
 445             TestSuite ts = execModel.getTestSuite();
 446             String tsName = ((ts == null ? uif.getI18NString("fconfig.dTitle.unknown") : ts.getName()));
 447             setI18NTitle("fconfig.dTitle", tsName);
 448 
 449             JPanel body = uif.createPanel("fe.body", false);
 450             body.setLayout(new GridBagLayout());
 451 
 452             GridBagConstraints gbc = new GridBagConstraints();
 453             gbc.gridx = 0;
 454             gbc.gridy = 0;
 455             gbc.fill = GridBagConstraints.VERTICAL;
 456             gbc.anchor = GridBagConstraints.NORTHWEST;
 457             gbc.insets.left = 10;
 458             gbc.insets.right = 10;
 459             gbc.weighty = 1;
 460             gbc.weightx = 0;
 461             gbc.gridwidth = 1;
 462             gbc.gridheight = 1;
 463 
 464             leftList = uif.createList("fconfig.list");
 465             leftList.setModel(createListModel());
 466             leftList.setCellRenderer(RenderingUtilities.createFilterListRenderer());
 467             leftList.addListSelectionListener(this);
 468             leftList.setBorder(BorderFactory.createEtchedBorder());
 469             leftList.getInsets().left = 5;
 470             leftList.getInsets().right = 5;
 471             uif.setAccessibleInfo(leftList, "fconfig.list");
 472 
 473             JPanel spacer = new JPanel();
 474             spacer.setBorder(uif.createTitledBorder("fconfig.list"));
 475             spacer.setLayout(new BorderLayout());
 476             spacer.add(leftList, BorderLayout.CENTER);
 477 
 478             body.add(spacer, gbc);
 479 
 480             gbc.weightx = 1;
 481             gbc.fill = GridBagConstraints.BOTH;
 482             gbc.gridx = 1;
 483             JComponent rightPanel = createRightPanel();
 484             body.add(rightPanel, gbc);
 485 
 486             int dpi = uif.getDotsPerInch();
 487             body.setPreferredSize(new Dimension(7 * dpi, 5 * dpi));
 488             setBody(body);
 489 
 490             initButtons();
 491 
 492             setComponentListener(listener);
 493 
 494             //leftList.setNextFocusableComponent(rightPanel.getNextFocusableComponent());
 495             //rightPanel.setNextFocusableComponent(applyBut);
 496             //helpBut.setNextFocusableComponent(leftList);
 497 
 498             mode = -1;
 499 
 500             // process any stored state
 501             if (selectedFilter != null)
 502                 setSelectedFilter(selectedFilter);
 503             else
 504                 selectIndex(0);     // the default
 505         }
 506 
 507         private ListModel<TestFilter> createListModel() {
 508             listModel = new DefaultListModel<>();
 509 
 510             for (int i = 0; i < filters.length; i++)
 511                 listModel.addElement(filters[i]);
 512 
 513             return listModel;
 514         }
 515 
 516         private JComponent createRightPanel() {
 517             EMPTY_CONFIG = createEmptyItem("fconfig.empt.conf");
 518             EMPTY_NAMING = createEmptyItem("fconfig.empt.name");
 519 
 520             EMPTY_CONFIG.setName("config");
 521             EMPTY_NAMING.setName("naming");
 522 
 523             JPanel pan = new JPanel(new GridBagLayout());
 524             pan.setName("rightFilter");
 525             GridBagConstraints gbc = new GridBagConstraints();
 526             gbc.gridx = 0;
 527             gbc.gridy = GridBagConstraints.RELATIVE;
 528             gbc.fill = GridBagConstraints.BOTH;
 529             gbc.anchor = GridBagConstraints.NORTH;
 530             gbc.insets.left = 10;
 531             gbc.insets.right = 10;
 532             gbc.weighty = 0;
 533             gbc.weightx = 1;
 534 
 535             JComponent nextPanel = createInfoPanel();
 536             nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.info"));
 537             pan.add(nextPanel, gbc);
 538 
 539             nextPanel = createNamingPanel();
 540             nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.naming"));
 541             pan.add(nextPanel, gbc);
 542 
 543             nextPanel = createConfigPanel();
 544             nextPanel.setBorder(uif.createTitledBorder("fconfig.panel.config"));
 545             gbc.weighty = 1;
 546             pan.add(nextPanel, gbc);
 547 
 548             return pan;
 549         }
 550 
 551         /**
 552          * ui key should have uikey.txt, uikey.desc, and uikey values in
 553          * the bundle.  these are for the text itself, a11y description and
 554          * a11y name respectively.
 555          */
 556         private JComponent createEmptyItem(String uikey) {
 557             JTextField item = uif.createHeading(uikey);
 558             uif.setAccessibleInfo(item, uikey);
 559             item.setHorizontalAlignment(SwingConstants.CENTER);
 560 
 561             return item;
 562         }
 563 
 564         private JComponent createInfoPanel() {
 565             JPanel pan = new JPanel(new GridBagLayout());
 566             pan.setName("info");
 567             GridBagConstraints gbc = new GridBagConstraints();
 568             gbc.weightx = 5;
 569             gbc.gridx = 0;
 570             gbc.gridy = 0;
 571             gbc.fill = GridBagConstraints.NONE;
 572             gbc.anchor = GridBagConstraints.EAST;
 573 
 574             gbc.insets.left = 15;
 575             gbc.insets.right = 15;
 576 
 577             JLabel lab = uif.createLabel("fconfig.info.name");
 578             infoName = uif.createOutputField("fconfig.info.name", lab);
 579             infoName.setEditable(false);
 580             infoName.setBorder(BorderFactory.createEmptyBorder());
 581             lab.setDisplayedMnemonic(uif.getI18NString("fconfig.info.name.mne").charAt(0));
 582             lab.setHorizontalAlignment(SwingConstants.RIGHT);
 583 
 584             // row 1
 585             // label in first column
 586             pan.add(lab, gbc);
 587 
 588             // add text field in second column
 589             gbc.gridx = 1;
 590             gbc.fill = GridBagConstraints.HORIZONTAL;
 591             gbc.anchor = GridBagConstraints.WEST;
 592             pan.add(infoName, gbc);
 593 
 594             lab = uif.createLabel("fconfig.info.desc");
 595             lab.setHorizontalAlignment(SwingConstants.RIGHT);
 596             infoDesc = uif.createTextArea("fconfig.info.desc", lab);
 597             infoDesc.setRows(3);
 598             infoDesc.setEditable(false);
 599             infoDesc.setBorder(BorderFactory.createEmptyBorder());
 600             infoDesc.setLineWrap(true);
 601             infoDesc.setWrapStyleWord(true);
 602             infoDesc.setBackground(UIFactory.Colors.TRANSPARENT.getValue());
 603             infoDesc.setOpaque(false);
 604             lab.setDisplayedMnemonic(uif.getI18NString("fconfig.info.desc.mne").charAt(0));
 605 
 606             // row 2
 607             // label in first column
 608             gbc.gridx = 0;
 609             gbc.gridy = 1;
 610             gbc.fill = GridBagConstraints.NONE;
 611             gbc.anchor = GridBagConstraints.NORTHEAST;
 612             pan.add(lab, gbc);
 613 
 614             // add text area in second column
 615             gbc.gridx = 1;
 616             gbc.fill = GridBagConstraints.HORIZONTAL;
 617             gbc.anchor = GridBagConstraints.WEST;
 618             pan.add(infoDesc, gbc);
 619 
 620             /*
 621             // NOTE intentional space added below to defeat
 622             //  i18n check in build while this is commented out
 623             lab = uif.createLabel ("fconfig.info.reason");
 624             lab.setHorizontalAlignment(SwingConstants.RIGHT);
 625             infoReason = uif.createTextArea("fconfig.info.reason");
 626             infoReason.setRows(2);
 627             infoReason.setEditable(false);
 628             infoReason.setBorder(BorderFactory.createEmptyBorder());
 629             infoReason.setLineWrap(true);
 630             infoReason.setWrapStyleWord(true);
 631             infoReason.setOpaque(false);
 632             lab.setLabelFor(infoReason);
 633 
 634             // row 3
 635             // label in first column
 636             gbc.gridx = 0;
 637             gbc.gridy = 2;
 638             gbc.fill = GridBagConstraints.NONE;
 639             gbc.anchor = GridBagConstraints.NORTHEAST;
 640             pan.add(lab, gbc);
 641 
 642             // add text area in second column
 643             gbc.gridx = 1;
 644             gbc.fill = GridBagConstraints.HORIZONTAL;
 645             gbc.anchor = GridBagConstraints.WEST;
 646             pan.add(infoReason, gbc);
 647             */
 648             return pan;
 649         }
 650 
 651         private JPanel createNamingPanel() {
 652             nameCards = new CardLayout();
 653             namePanel = new JPanel(nameCards);
 654 
 655             JPanel pan = new JPanel(new GridBagLayout());
 656             GridBagConstraints gbc = new GridBagConstraints();
 657             gbc.weightx = 5;
 658             gbc.gridx = 0;
 659             gbc.gridy = 0;
 660             gbc.fill = GridBagConstraints.NONE;
 661             gbc.anchor = GridBagConstraints.EAST;
 662 
 663             gbc.insets.left = 15;
 664             gbc.insets.right = 15;
 665 
 666             JLabel lab = uif.createLabel("fconfig.naming.name");
 667             namingName = uif.createOutputField("fconfig.naming.name", lab);
 668             namingName.setEditable(true);
 669             namingName.setEnabled(true);
 670             lab.setDisplayedMnemonic(uif.getI18NString("fconfig.naming.name.mne").charAt(0));
 671             lab.setHorizontalAlignment(SwingConstants.RIGHT);
 672 
 673             // row 1
 674             // label in first column
 675             pan.add(lab, gbc);
 676 
 677             gbc.gridx = 1;
 678             gbc.fill = GridBagConstraints.HORIZONTAL;
 679             pan.add(namingName, gbc);
 680 
 681             namePanel.add(NAMING_ACTIVE, pan);
 682             namePanel.add(NAMING_EMPTY, EMPTY_NAMING);
 683             nameCards.show(namePanel, NAMING_EMPTY);
 684 
 685             return namePanel;
 686         }
 687 
 688         private JPanel createConfigPanel() {
 689             configCards = new CardLayout();
 690             configPanel = new JPanel(configCards);
 691             configPanelHash = new Hashtable<>();
 692 
 693             // insert panels?
 694             configPanel.add(CONFIG_EMPTY, EMPTY_CONFIG);
 695 
 696             for (int i = 0; i < listModel.getSize(); i++) {
 697                 if (listModel.getElementAt(i) instanceof ConfigurableTestFilter) {
 698                     ConfigurableTestFilter ctf =
 699                         (ConfigurableTestFilter)listModel.getElementAt(i);
 700                     addConfigurableFilter(ctf);
 701                 }
 702             }   // for
 703 
 704             return configPanel;
 705         }
 706 
 707         private void initButtons() {
 708             applyBut = uif.createButton("fconfig.edit.apply", this);
 709             resetBut = uif.createButton("fconfig.edit.reset", this);
 710             cancelBut = uif.createCancelButton("fconfig.edit.cancel", this);
 711             doneBut = uif.createButton("fconfig.edit.done", this);
 712             helpBut = uif.createHelpButton("fconfig.edit.help", "execFilters.dialog.csh");
 713             setButtons(new JButton[] { applyBut, resetBut, cancelBut, doneBut, helpBut },
 714                        doneBut);
 715         }
 716 
 717         private void addConfigurableFilter(ConfigurableTestFilter ctf) {
 718             JComponent comp = ctf.getEditorPane();
 719             String thisName = "ctf" + ++configCounter;
 720 
 721             if (comp != null)
 722                 configPanel.add(thisName, comp);
 723             else
 724                 configPanel.add(thisName, EMPTY_CONFIG);
 725 
 726             // to lookup later
 727             configPanelHash.put(ctf, thisName);
 728         }
 729 
 730         private void removeConfigurableFilter(ConfigurableTestFilter ctf) {
 731             configPanelHash.remove(ctf);
 732         }
 733 
 734         private void fillInfo(TestFilter f) {
 735             if (f == null)
 736                 return;
 737 
 738             if (f instanceof ConfigurableTestFilter) {
 739                 infoName.setText(((ConfigurableTestFilter)(f)).getBaseName());
 740             }
 741             else
 742                 infoName.setText(f.getName());
 743 
 744             infoDesc.setText(f.getDescription());
 745             //infoReason.setText(f.getReason());
 746         }
 747 
 748         private void fillNaming(ConfigurableTestFilter f) {
 749             namingName.setText(f.getName());
 750         }
 751 
 752         /**
 753          * Attempt the apply operation.
 754          * @return Non-null if the apply was successful, null otherwise.  If non-null
 755          *         the value is a localized error message for the user.
 756          */
 757         private String doApply() {
 758             if (mode == UNEDITABLE)
 759                 throw new IllegalStateException("filter is uneditable, cannot apply changes");
 760 
 761             ConfigurableTestFilter ctf = (ConfigurableTestFilter)selectedFilter;
 762 
 763             // should check to see if it's changed
 764             String newName = namingName.getText();
 765             if (validateName(newName) != -1) {
 766                 return uif.getI18NString("fconfig.edit.badName", newName);
 767             }
 768             else if (newName != null)
 769                 ctf.setInstanceName(newName);
 770 
 771             String status = ctf.commitEditorSettings();
 772 
 773             if (handlers != null)
 774                 for (int i = 0; i < handlers.length; i++)
 775                     handlers[i].updateFilterMetaInfo(ctf);
 776 
 777             return status;
 778         }
 779 
 780         void doReset() {
 781             // reset all known configurable filters
 782             for (int i = 0; i < listModel.getSize(); i++) {
 783                 if (listModel.elementAt(i) instanceof
 784                     ConfigurableTestFilter) {
 785                     ConfigurableTestFilter ctf =
 786                         (ConfigurableTestFilter)listModel.elementAt(i);
 787                     ctf.resetEditorSettings();
 788                 }
 789             }   // for
 790         }
 791 
 792         /**
 793          * @return The position of the invalid character.
 794          */
 795         private int validateName(String text) {
 796             for (int i = 0; i < text.length(); i++) {
 797                 char c = text.charAt(i);
 798                 if (Character.isLetterOrDigit(c) ||
 799                     c == '-' ||
 800                     c == '_' ||
 801                     c == '.' ||
 802                     c == ' ' ||
 803                     c == ',')
 804                     continue;
 805                 else
 806                     return i;
 807             }   // for
 808 
 809             return -1;
 810         }
 811 
 812         private JSplitPane split;
 813         private JList<TestFilter> leftList;
 814         private DefaultListModel<TestFilter> listModel;
 815         private int lastSelected = -1;
 816         private TestFilter selectedFilter;
 817 
 818         // just to help track current state
 819         private int mode;
 820         //private boolean focusSet;
 821         private static final int EDITABLE = 0;
 822         private static final int UNEDITABLE = 1;
 823 
 824         // dialog buttons
 825         private JButton applyBut;
 826         private JButton helpBut;
 827         private JButton doneBut;
 828         private JButton cancelBut;
 829         private JButton createBut;
 830         private JButton deleteBut;
 831         private JButton resetBut;
 832 
 833         // info panel components
 834         private JTextArea infoDesc;
 835         private JTextField infoName;
 836         //private JTextArea infoReason;
 837 
 838         // naming panel
 839         private CardLayout nameCards;
 840         private JPanel namePanel;
 841         private JTextField namingName;
 842 
 843         // config panel
 844         private CardLayout configCards;
 845         private JPanel configPanel;
 846         private Hashtable<ConfigurableTestFilter, String> configPanelHash;
 847         private int configCounter;          // to make a unique string
 848 
 849         private JComponent EMPTY_CONFIG;
 850         private JComponent EMPTY_NAMING;
 851         private JComponent EMPTY_INFO;
 852 
 853         private int NUMBER;
 854 
 855         private static final String CONFIG_ACTIVE = "configa";
 856         private static final String CONFIG_EMPTY = "confige";
 857         private static final String NAMING_ACTIVE = "naminga";
 858         private static final String NAMING_EMPTY = "naminge";
 859         private static final String INFO_ACTIVE = "infoa";
 860         private static final String INFO_EMPTY = "infoe";
 861     }
 862 
 863 }