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.Component;
  31 import java.awt.Dimension;
  32 import java.awt.Graphics;
  33 import java.awt.GridBagConstraints;
  34 import java.awt.GridBagLayout;
  35 import java.awt.GridLayout;
  36 import java.awt.event.ActionEvent;
  37 import java.awt.event.ActionListener;
  38 import java.awt.event.ItemEvent;
  39 import java.awt.event.ItemListener;
  40 import java.util.Arrays;
  41 import java.util.HashSet;
  42 import javax.swing.BorderFactory;
  43 import javax.swing.Icon;
  44 import javax.swing.JButton;
  45 import javax.swing.JCheckBox;
  46 import javax.swing.JComboBox;
  47 import javax.swing.JComponent;
  48 import javax.swing.JLabel;
  49 import javax.swing.JList;
  50 import javax.swing.JPanel;
  51 import javax.swing.JPopupMenu;
  52 import javax.swing.JScrollPane;
  53 import javax.swing.JTextField;
  54 import javax.swing.event.ChangeEvent;
  55 import javax.swing.event.ChangeListener;
  56 import javax.swing.event.ListSelectionEvent;
  57 import javax.swing.event.ListSelectionListener;
  58 import javax.swing.text.Caret;
  59 
  60 import com.sun.javatest.InterviewParameters;
  61 import com.sun.javatest.Keywords;
  62 import com.sun.javatest.TestSuite;
  63 import com.sun.javatest.Parameters.KeywordsParameters;
  64 import com.sun.javatest.Parameters.MutableKeywordsParameters;
  65 import com.sun.javatest.tool.UIFactory;
  66 import com.sun.javatest.tool.jthelp.ContextHelpManager;
  67 import java.awt.Container;
  68 import java.awt.Dialog;
  69 import java.awt.Frame;
  70 import java.awt.Insets;
  71 import java.awt.Point;
  72 import java.awt.Toolkit;
  73 import javax.swing.JDialog;
  74 import javax.swing.WindowConstants;
  75 
  76 /**
  77  * Standard values, keyword pane.
  78  */
  79 class CE_KeywordsPane extends CE_StdPane {
  80     CE_KeywordsPane(UIFactory uif, InterviewParameters config) {
  81         super(uif, config, "keywords");
  82 
  83         updateConfig();
  84         initGUI();
  85     }
  86 
  87     boolean isOKToClose() {
  88         if (mutableKeywordsParameters == null)
  89             return true;
  90 
  91         if (!selectCheck.isSelected())
  92             return true;
  93 
  94         try {
  95             TestSuite ts = config.getTestSuite();
  96             String[] validKeywords = ts.getKeywords();
  97             HashSet<String> validKeywordsSet;
  98             if (validKeywords == null)
  99                 validKeywordsSet = null;
 100             else
 101                 validKeywordsSet = new HashSet<String>(Arrays.asList(validKeywords));
 102 
 103             String kc = (String) (keywordsChoice.getSelectedItem());
 104             String type;
 105             if (kc.equals(ANY_OF))
 106                 type = Keywords.ANY_OF;
 107             else if (kc.equals(ALL_OF))
 108                 type = Keywords.ALL_OF;
 109             else
 110                 type = Keywords.EXPR;
 111             Keywords k = Keywords.create(type, keywordsField.getText(),
 112                     validKeywordsSet);
 113             return true;
 114         } catch (Keywords.Fault e) {
 115             uif.showError("ce.keywords.invalid", e.getMessage());
 116             return false;
 117         }
 118     }
 119 
 120     void updateConfig() {
 121         // track interview changes
 122         keywordsParameters = config.getKeywordsParameters();
 123         if (keywordsParameters != null
 124                 && keywordsParameters instanceof MutableKeywordsParameters)
 125             mutableKeywordsParameters = (MutableKeywordsParameters) keywordsParameters;
 126         else
 127             mutableKeywordsParameters = null;
 128     }
 129 
 130     void load() {
 131         updateConfig();
 132 
 133         // update GUI
 134         if (mutableKeywordsParameters != null) {
 135             selectCheck.setEnabled(true);
 136             setEnabled(true);
 137             int km = mutableKeywordsParameters.getKeywordsMode();
 138             selectCheck.setSelected(km == MutableKeywordsParameters.MATCH_KEYWORDS);
 139 
 140             int kmm = mutableKeywordsParameters.getMatchKeywordsMode();
 141             switch (kmm) {
 142                 case MutableKeywordsParameters.ANY_OF:
 143                     keywordsChoice.setSelectedItem(ANY_OF);
 144                     break;
 145 
 146                 case MutableKeywordsParameters.ALL_OF:
 147                     keywordsChoice.setSelectedItem(ALL_OF);
 148                     break;
 149 
 150                 case MutableKeywordsParameters.EXPR:
 151                     keywordsChoice.setSelectedItem(EXPR);
 152                     break;
 153             }
 154 
 155             String kmv = mutableKeywordsParameters.getMatchKeywordsValue();
 156             keywordsField.setText(kmv == null ? "" : kmv);
 157         } else if (keywordsParameters != null) {
 158             setEnabled(true);
 159             String expr = keywordsParameters.getKeywords().toString();
 160             selectCheck.setSelected(expr.length() == 0);
 161             selectCheck.setEnabled(false);
 162 
 163             keywordsChoice.setSelectedItem(EXPR);
 164             keywordsField.setText(expr);
 165             keywordsChoice.setEnabled(false);
 166         } else {
 167             setEnabled(false); // may be too late to hide tab
 168             selectCheck.setEnabled(false);
 169 
 170             keywordsChoice.setSelectedItem(EXPR);
 171             keywordsField.setText("");
 172             keywordsChoice.setEnabled(false);
 173         }
 174 
 175         enableKeywordFields();
 176     }
 177 
 178     void save() {
 179         if (mutableKeywordsParameters != null) {
 180             int km = (selectCheck.isSelected()
 181             ? MutableKeywordsParameters.MATCH_KEYWORDS
 182                     : MutableKeywordsParameters.NO_KEYWORDS);
 183             mutableKeywordsParameters.setKeywordsMode(km);
 184 
 185             String kc = (String) (keywordsChoice.getSelectedItem());
 186             int kmm;
 187             if (kc.equals(ANY_OF))
 188                 kmm = MutableKeywordsParameters.ANY_OF;
 189             else if (kc.equals(ALL_OF))
 190                 kmm = MutableKeywordsParameters.ALL_OF;
 191             else
 192                 kmm = MutableKeywordsParameters.EXPR;
 193             mutableKeywordsParameters.setMatchKeywords(kmm, keywordsField.getText());
 194         }
 195     }
 196 
 197     private void initGUI() {
 198         ContextHelpManager.setHelpIDString(this, "confEdit.keywordsTab.csh");
 199 
 200         JPanel p = uif.createPanel("ce.keywords", new BorderLayout(), false);
 201 
 202         // ----- body -----
 203         JPanel body = uif.createPanel("ce.keywords.body",
 204                 new GridBagLayout(),
 205                 false);
 206         body.setBorder(BorderFactory.createEmptyBorder(5, 5, 0, 5));
 207 
 208         GridBagConstraints c = new GridBagConstraints();
 209         c.gridwidth = GridBagConstraints.REMAINDER;
 210         c.fill = GridBagConstraints.HORIZONTAL;
 211         c.weightx = 1;
 212 
 213         selectCheck = uif.createCheckBox("ce.keywords.select");
 214         selectCheck.addChangeListener(listener);
 215         body.add(selectCheck, c);
 216 
 217         String[] kc = {ANY_OF, ALL_OF, EXPR};
 218         keywordsChoice = uif.createChoice("ce.keywords.choice", kc);
 219         keywordsChoice.addItemListener(listener);
 220         c.gridwidth = 1;
 221         c.insets.left = 17;
 222         c.weightx = 0;
 223         body.add(keywordsChoice, c);
 224 
 225         keywordsField = uif.createInputField("ce.keywords.field", 20);
 226         uif.setAccessibleName(keywordsField, "ce.keywords.field");
 227         c.fill = GridBagConstraints.HORIZONTAL;
 228         c.gridwidth = GridBagConstraints.REMAINDER;
 229         c.insets.left = 0;
 230         c.weightx = 1;
 231         body.add(keywordsField, c);
 232 
 233         p.add(body, BorderLayout.CENTER);
 234 
 235         // ----- foot -----
 236         JPanel foot = uif.createPanel("ce.keywords.foot",
 237                 new GridBagLayout(),
 238                 false);
 239         foot.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 240 
 241         Icon dropDownIcon = new DropDownIcon();
 242 
 243         c.anchor = GridBagConstraints.EAST;
 244         c.fill = GridBagConstraints.NONE;
 245         c.insets.left = 5;
 246         c.gridwidth = 1;
 247         keywordBtn = uif.createButton("ce.keywords.keyword", listener);
 248         keywordBtn.setIcon(dropDownIcon);
 249         keywordBtn.setHorizontalTextPosition(JLabel.LEADING);
 250         foot.add(keywordBtn, c);
 251 
 252         c.weightx = 0;
 253         opBtn = uif.createButton("ce.keywords.op", listener);
 254         opBtn.setIcon(dropDownIcon);
 255         opBtn.setHorizontalTextPosition(JLabel.LEADING);
 256         foot.add(opBtn, c);
 257         p.add(foot, BorderLayout.SOUTH);
 258 
 259         addBody(p);
 260 
 261         String[] opItems = { AND, OR, NOT, PARENS };
 262         opPopup = uif.createPopupMenu("ce.keywords.op", opItems, listener);
 263 
 264         keywords = config.getTestSuite().getKeywords();
 265 
 266         if (keywords != null) {
 267             if (keywords.length == 0) {
 268                 // this test suite explicitly does not support keywords,
 269                 // so disable the entire pane
 270                 setEnabled(false);
 271             } else {
 272                 // this test suite specifies valid keywords,
 273                 // so create a popup menu for them
 274                 keywordPopup = uif.createPopupMenu("ce.keywords.keyword");
 275                 keywordChooser = false;
 276                 for (int i = 0; i < keywords.length; i++)
 277                     keywordPopup.add(uif.createLiteralMenuItem(keywords[i], listener));
 278                 if (keywordPopup.getPreferredSize().getHeight() > (Toolkit.getDefaultToolkit().getScreenSize().height - 50)) {
 279                     keywordPopup = null;
 280                     keywordChooser = true;
 281                 }
 282             }
 283         }
 284     }
 285 
 286     private class KeywordChooser extends JDialog {
 287 
 288         private JScrollPane sp;
 289         private JList<String> lst;
 290         private JButton ok, cancel;
 291 
 292         KeywordChooser(Dialog parent, String [] keywords, Listener listener ) {
 293             super(parent);
 294             initUI(keywords, listener);
 295         }
 296 
 297         KeywordChooser(Frame parent, String [] keywords, Listener listener ) {
 298             super(parent);
 299             initUI(keywords, listener);
 300         }
 301 
 302         KeywordChooser(String [] keywords, Listener listener ) {
 303             super();
 304             initUI(keywords, listener);
 305         }
 306 
 307         private void initUI(String [] keywords, final Listener listener ) {
 308             GridBagConstraints gbc;
 309 
 310             sp = new JScrollPane();
 311             lst = new JList<>(keywords);
 312 
 313             ok = uif.createButton("keywordChooser.insert", new ActionListener() {
 314                 public void actionPerformed(ActionEvent e) {
 315                     Object[] sels = lst.getSelectedValues();
 316                     String inserted = "";
 317                     for (int i = 0; i < sels.length; i++) {
 318                         inserted += sels[i] + " ";
 319                     }
 320                     listener.insert(inserted.trim());
 321                     lst.clearSelection();
 322                     setVisible(false);
 323                     dispose();
 324                 }
 325             });
 326 
 327 
 328             cancel = uif.createButton("keywordChooser.cancel", new ActionListener() {
 329                 public void actionPerformed(ActionEvent e) {
 330                     lst.clearSelection();
 331                     setVisible(false);
 332                     dispose();
 333                 }
 334             }) ;
 335 
 336             JPanel btnP = new JPanel();
 337             btnP.setLayout(new GridLayout(1,2,5,0));
 338             btnP.add(cancel);
 339             btnP.add(ok);
 340 
 341             getContentPane().setLayout(new GridBagLayout());
 342 
 343             setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
 344 
 345             setModal(true);
 346             setUndecorated(true);
 347             JPopupMenu samplePopup = new JPopupMenu();
 348             getRootPane().setBorder(samplePopup.getBorder());
 349 
 350             sp.setViewportView(lst);
 351             lst.setBackground(samplePopup.getBackground());
 352 
 353             gbc = new GridBagConstraints();
 354             gbc.gridwidth = 2;
 355             gbc.fill = GridBagConstraints.BOTH;
 356             gbc.weightx = 1.0;
 357             gbc.weighty = 1.0;
 358             gbc.insets = new Insets(5, 5, 5, 5);
 359             getContentPane().add(sp, gbc);
 360             gbc = new GridBagConstraints();
 361             gbc.gridx = 1;
 362             gbc.gridy = 1;
 363             gbc.anchor = GridBagConstraints.SOUTHEAST;
 364             gbc.insets = new Insets(0, 5, 5, 5);
 365             getContentPane().add(btnP, gbc);
 366             pack();
 367             Dimension s = getPreferredSize();
 368             s.height = (int) (Toolkit.getDefaultToolkit().getScreenSize().height * 0.75);
 369             ok.setEnabled(false);
 370             lst.addListSelectionListener(new ListSelectionListener() {
 371                 public void valueChanged(ListSelectionEvent e) {
 372                     ok.setEnabled(lst.getSelectedIndex() != -1);
 373                 }
 374             });
 375 
 376             setSize(s);
 377         }
 378 
 379         private void setLocationRelativeToXY(Component xC, Component yC) {
 380             setLocationRelativeTo(xC);
 381             Point xP = getLocation();
 382             setLocationRelativeTo(yC);
 383             Point yP = getLocation();
 384             setLocation(new Point(xP.x, yP.y));
 385         }
 386 
 387     }
 388 
 389 
 390     private void enableKeywordFields() {
 391         boolean b = selectCheck.isEnabled() && selectCheck.isSelected();
 392         keywordsChoice.setEnabled(b);
 393         keywordsField.setEnabled(b);
 394         opBtn.setEnabled(b && keywordsChoice.getSelectedItem().equals(EXPR));
 395         keywordBtn.setEnabled(b && (keywordPopup != null || keywordChooser));
 396     }
 397 
 398     private KeywordsParameters keywordsParameters;
 399     private MutableKeywordsParameters mutableKeywordsParameters;
 400     private JCheckBox selectCheck;
 401     private JComboBox keywordsChoice;
 402     private JTextField keywordsField;
 403     private JButton keywordBtn;
 404     private JPopupMenu keywordPopup;
 405     private JButton opBtn;
 406     private JPopupMenu opPopup;
 407     private Listener listener = new Listener();
 408 
 409     private static final String ALL_OF = "allOf";
 410     private static final String ANY_OF = "anyOf";
 411     private static final String EXPR   = "expr";
 412     private static final String IGNORE = "ignore";
 413 
 414     private static final String AND = "and";
 415     private static final String OR = "or";
 416     private static final String NOT = "not";
 417     private static final String PARENS = "parens";
 418 
 419     private boolean keywordChooser;
 420     private String[] keywords;
 421 
 422     private class Listener
 423             implements ActionListener, ChangeListener, ItemListener {
 424         // ---------- ActionListener -----------------------------------
 425 
 426         public void actionPerformed(ActionEvent e) {
 427             Component src = (Component) (e.getSource());
 428             String cmd = e.getActionCommand();
 429             if (src == keywordBtn) {
 430                 if (keywordPopup != null) {
 431                     show(keywordBtn, keywordPopup);
 432                 } else if (keywordChooser) {
 433                     KeywordChooser kc;
 434                     Container parent = toolDialog.getDialogParent();
 435                     if (parent instanceof Dialog) {
 436                         kc = new KeywordChooser((Dialog)parent, keywords, listener);
 437                     }
 438                     else if (parent instanceof Frame) {
 439                         kc = new KeywordChooser((Frame)parent, keywords, listener);
 440                     }
 441                     else {
 442                         kc = new KeywordChooser(keywords, listener);
 443                     }
 444                     kc.setLocationRelativeToXY(keywordBtn, CE_KeywordsPane.this);
 445                     kc.setVisible(true);
 446                 }
 447             }
 448             else if (src == opBtn)
 449                 show(opBtn, opPopup);
 450             else if (cmd.equals(AND))
 451                 insert("&");
 452             else if (cmd.equals(OR))
 453                 insert("|");
 454             else if (cmd.equals(NOT))
 455                 insert("!");
 456             else if (cmd.equals(PARENS)) {
 457                 insert("()");
 458                 keywordsField.setCaretPosition(keywordsField.getCaretPosition() - 1);
 459             } else if (src.getParent() == keywordPopup)
 460                 insert(cmd);
 461         }
 462 
 463         // show a popup menu relative to its invoking button
 464         private void show(Component ref, JPopupMenu menu) {
 465             menu.show(ref, 0, ref.getHeight());
 466         }
 467 
 468         // insert text into the keywords field
 469         void insert(String s) {
 470             if (s.length() == 0)
 471                 return;
 472 
 473             String t = keywordsField.getText();
 474 
 475             Caret caret = keywordsField.getCaret();
 476             int p1 = Math.min(caret.getDot(), caret.getMark());
 477             int p2 = Math.max(caret.getDot(), caret.getMark());
 478 
 479             boolean needSpaceBefore = Character.isLetterOrDigit(s.charAt(0))
 480             && (p1 > 0) && Character.isLetterOrDigit(t.charAt(p1 - 1));
 481             if (needSpaceBefore)
 482                 s = " " + s;
 483 
 484             boolean needSpaceAfter = Character.isLetterOrDigit(s.charAt(s.length() - 1))
 485             && (p2 < t.length()) && Character.isLetterOrDigit(t.charAt(p2));
 486             if (needSpaceAfter)
 487                 s = s + " ";
 488 
 489             keywordsField.replaceSelection(s);
 490         }
 491 
 492         // ---------- ChangeListener -----------------------------------
 493 
 494         public void stateChanged(ChangeEvent e) {
 495             enableKeywordFields();
 496         }
 497 
 498         // ---------- ItemListener -----------------------------------
 499 
 500         public void itemStateChanged(ItemEvent e) {
 501             enableKeywordFields();
 502         }
 503     }
 504 
 505     private static class DropDownIcon implements Icon {
 506 
 507         public void paintIcon(Component c, Graphics g, int x, int y) {
 508             JComponent component = (JComponent)c;
 509             int iconWidth = getIconWidth();
 510 
 511             g.translate( x, y );
 512             g.setColor( component.isEnabled() ?
 513                 UIFactory.Colors.CONTROL_INFO.getValue() :
 514                 UIFactory.Colors.CONTROL_SHADOW.getValue() );
 515             g.drawLine( 0, 0, iconWidth - 1, 0 );
 516             g.drawLine( 1, 1, 1 + (iconWidth - 3), 1 );
 517             g.drawLine( 2, 2, 2 + (iconWidth - 5), 2 );
 518             g.drawLine( 3, 3, 3 + (iconWidth - 7), 3 );
 519             g.drawLine( 4, 4, 4 + (iconWidth - 9), 4 );
 520 
 521             g.translate( -x, -y );
 522         }
 523 
 524         public int getIconWidth() { return 10; }
 525 
 526         public int getIconHeight()  { return 5; }
 527 
 528     }
 529 }