1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 1996, 2009, 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.interview.wizard;
  28 
  29 import java.awt.BorderLayout;
  30 import java.awt.Component;
  31 import java.awt.Container;
  32 import java.awt.Dialog;
  33 import java.awt.Frame;
  34 import java.awt.GridBagConstraints;
  35 import java.awt.GridBagLayout;
  36 import java.awt.event.ActionEvent;
  37 import java.awt.event.ActionListener;
  38 import java.util.Hashtable;
  39 import java.util.Map;
  40 import javax.accessibility.AccessibleContext;
  41 import javax.swing.BorderFactory;
  42 import javax.swing.DefaultListCellRenderer;
  43 import javax.swing.JButton;
  44 import javax.swing.JCheckBox;
  45 import javax.swing.JComboBox;
  46 import javax.swing.JComponent;
  47 import javax.swing.JDialog;
  48 import javax.swing.JLabel;
  49 import javax.swing.JList;
  50 import javax.swing.JPanel;
  51 import javax.swing.JTextField;
  52 import javax.swing.KeyStroke;
  53 import javax.swing.SwingUtilities;
  54 import com.sun.interview.Interview;
  55 import com.sun.interview.Question;
  56 import com.sun.javatest.tool.jthelp.HelpBroker;
  57 
  58 class SearchDialog extends JDialog
  59 {
  60     static SearchDialog create(Component parent, Interview i,
  61                                HelpBroker helpBroker, String helpPrefix) {
  62         Dialog d = (Dialog)(SwingUtilities.getAncestorOfClass(Dialog.class, parent));
  63         if (d != null)
  64             return new SearchDialog(d, i, helpBroker, helpPrefix);
  65         else {
  66             Frame f = (Frame)(SwingUtilities.getAncestorOfClass(Frame.class, parent));
  67             return new SearchDialog(f, i, helpBroker, helpPrefix);
  68         }
  69     }
  70 
  71     SearchDialog(Frame parent, Interview i, HelpBroker helpBroker, String helpPrefix) {
  72         super(parent);
  73         init(parent, i, helpBroker, helpPrefix);
  74     }
  75 
  76     SearchDialog(Dialog parent, Interview i, HelpBroker helpBroker, String helpPrefix) {
  77         super(parent);
  78         init(parent, i, helpBroker, helpPrefix);
  79     }
  80 
  81     private void init(Component parent, Interview i, HelpBroker helpBroker, String helpPrefix) {
  82         interview = i;
  83         this.helpBroker = helpBroker;
  84         this.helpPrefix = helpPrefix;
  85 
  86         setName("find");
  87         setTitle(i18n.getString("find.title"));
  88         AccessibleContext ac = getAccessibleContext();
  89         ac.setAccessibleName(i18n.getString("find.name"));
  90         ac.setAccessibleDescription(i18n.getString("find.desc"));
  91 
  92         Container contentPane = getContentPane();
  93         contentPane.setName("content");
  94         contentPane.setFocusable(false);
  95         contentPane.setLayout(new BorderLayout());
  96 
  97         JPanel p = new JPanel(new GridBagLayout());
  98         p.setName("main");
  99         p.setFocusable(false);
 100 
 101         GridBagConstraints lc = new GridBagConstraints();
 102         lc.anchor = GridBagConstraints.EAST;
 103         lc.insets.right = 10;
 104 
 105         GridBagConstraints c = new GridBagConstraints();
 106         c.fill = GridBagConstraints.HORIZONTAL;
 107         c.gridwidth = GridBagConstraints.REMAINDER;
 108         c.weightx = 1;
 109 
 110         JLabel textLbl = createLabel("find.field", true);
 111         p.add(textLbl, lc);
 112 
 113         textField = new JTextField("", 32);
 114         textField.setName("find.text");
 115         textField.addActionListener(listener);
 116         textField.setActionCommand(FIND);
 117         textField.setToolTipText(textLbl.getAccessibleContext().getAccessibleDescription());
 118         textLbl.setLabelFor(textField);
 119         c.insets.bottom = 10;
 120         p.add(textField, c);
 121 
 122         JLabel whereLbl = createLabel("find.where", true);
 123         p.add(whereLbl, lc);
 124 
 125         String[] choices = {TITLE, QUESTION, ANSWER, ANYWHERE};
 126         whereChoice = createChoice("find.where", choices);
 127         whereLbl.setLabelFor(whereChoice);
 128         c.anchor = GridBagConstraints.WEST;
 129         c.fill = GridBagConstraints.NONE;
 130         c.insets.bottom = 0;
 131         p.add(whereChoice, c);
 132 
 133         JLabel optionsLbl = createLabel("find.options", false);
 134         p.add(optionsLbl, lc);
 135 
 136         JPanel p2 = new JPanel();
 137         p2.setName("options");
 138         p2.setFocusable(false);
 139 
 140         caseChk = createCheckBox("find.case");
 141         p2.add(caseChk);
 142         wordChk = createCheckBox("find.word");
 143         p2.add(wordChk);
 144         p.add(p2, c);
 145 
 146         p.registerKeyboardAction(listener, CLOSE, escapeKey,
 147                                  JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
 148         p.setBorder(BorderFactory.createEmptyBorder(/*top*/12, /*left*/12, /*bottom*/0, /*right*/11));
 149 
 150         contentPane.add(p, BorderLayout.CENTER);
 151 
 152         JPanel btns = new JPanel(new GridBagLayout());
 153         btns.setName("btns");
 154         btns.setFocusable(false);
 155         c = new GridBagConstraints();
 156         c.weightx = 1;
 157         c.anchor = GridBagConstraints.EAST;
 158         btns.add(createButton("find.find", FIND, listener), c);
 159         c.insets.left = 5;
 160         c.weightx = 0;
 161         btns.add(createButton("find.close", CLOSE, listener), c);
 162         if (helpBroker != null)
 163             btns.add(createButton("find.help", HELP, listener), c);
 164 
 165         btns.setBorder(BorderFactory.createEmptyBorder(/*top*/11, /*left*/12, /*bottom*/11, /*right*/11));
 166 
 167         contentPane.add(btns, BorderLayout.SOUTH);
 168 
 169         if (helpBroker != null)
 170             helpBroker.enableHelpKey(getRootPane(), helpPrefix + "search.csh");
 171 
 172         pack();
 173         setLocationRelativeTo(parent);
 174     }
 175 
 176     public void setVisible(boolean b) {
 177         super.setVisible(b);
 178         if (b)
 179             textField.requestFocus();
 180     }
 181 
 182     public void find() {
 183         if (textField.getText().length() == 0)
 184             setVisible(true);
 185         else {
 186             // just get this once for the query
 187             Map<String, String> answers = new Hashtable<>();
 188             interview.save(answers);
 189             Question[] path = interview.getPath();
 190             Question curr = interview.getCurrentQuestion();
 191             for (int i = 0; i < path.length; i++) {
 192                 if (path[i] == curr) {
 193                     for (int j = 0; j < path.length; j++) {
 194                         Question q = path[(i + 1 + j)%path.length];
 195                         String answer = answers.get(q.getTag());
 196                         if (matches(q, answer, caseChk.isSelected(), wordChk.isSelected())) {
 197                             try {
 198                                 interview.setCurrentQuestion(q);
 199                             }
 200                             catch (Interview.Fault e) {
 201                             }
 202                             return;
 203                         }
 204                     }
 205                     getToolkit().beep();
 206                     return;
 207                 }
 208             }
 209         }
 210     }
 211 
 212     private boolean matches(Question q, String answer, boolean considerCase, boolean word) {
 213         String text = textField.getText();
 214         String where = (String)(whereChoice.getSelectedItem());
 215         if (where.equals(TITLE))
 216             return match(text, q.getSummary(), considerCase, word);
 217         else if (where.equals(QUESTION))
 218             return match(text, q.getText(), considerCase, word);
 219         else if (where.equals(ANSWER))
 220             return (answer != null && match(text, answer, considerCase, word));
 221         else
 222             return ( match(text, q.getSummary(), considerCase, word) ||
 223                      match(text, q.getText(), considerCase, word) ||
 224                      (answer != null && match(text, answer, considerCase, word)) );
 225     }
 226 
 227     private static boolean match(String s1, String s2, boolean considerCase, boolean word) {
 228         int s1len = s1.length();
 229         int s2len = s2.length();
 230         for (int i = 0; i <= s2len - s1len; i++) {
 231             if (s1.regionMatches(!considerCase, 0, s2, i, s1len)) {
 232                 if (word)
 233                     return ( (i == 0 || isBoundaryCh(s2.charAt(i-1)))
 234                              && (i+s1len == s2.length() || isBoundaryCh(s2.charAt(i+s1len))) );
 235                 else
 236                     return true;
 237             }
 238         }
 239         return false;
 240     }
 241 
 242     private static boolean isBoundaryCh(char c) {
 243         return !(Character.isUnicodeIdentifierStart(c)
 244                  || Character.isUnicodeIdentifierPart(c));
 245     }
 246 
 247     private JButton createButton(String uiKey, String actionCommand, ActionListener l) {
 248         JButton b = new JButton(i18n.getString(uiKey + ".btn"));
 249         b.setName(uiKey);
 250         b.setMnemonic(getMnemonic(uiKey));
 251         b.setActionCommand(actionCommand);
 252         b.addActionListener(l);
 253         setToolTipText(b, uiKey);
 254         //b.registerKeyboardAction(listener, actionCommand, enterKey, JComponent.WHEN_FOCUSED);
 255         return b;
 256     }
 257 
 258     private JCheckBox createCheckBox(String uiKey) {
 259         JCheckBox b = new JCheckBox(i18n.getString(uiKey + ".ckb"));
 260         b.setName(uiKey);
 261         b.setMnemonic(getMnemonic(uiKey));
 262         setToolTipText(b, uiKey);
 263         return b;
 264     }
 265 
 266     private JComboBox<String> createChoice(final String uiKey, final String[] choiceKeys) {
 267         // create a cache of the presentation string, for use when
 268         // rendering, but otherwise, let the JComboBox work in terms of the
 269         // choiceKeys
 270         final String[] choices = new String[choiceKeys.length];
 271         for (int i = 0; i < choices.length; i++)
 272             choices[i] = i18n.getString(uiKey + "." + choiceKeys[i] + ".chc");
 273 
 274         JComboBox<String> choice = new JComboBox<>(choiceKeys);
 275         choice.setName(uiKey);
 276         AccessibleContext ac = choice.getAccessibleContext();
 277         ac.setAccessibleName(i18n.getString(uiKey + ".tip"));
 278 
 279         choice.setRenderer(new DefaultListCellRenderer() {
 280             public Component getListCellRendererComponent(JList<?> list, Object o, int index, boolean isSelected, boolean cellHasFocus) {
 281                 Object c = o;
 282                 for (int i = 0; i < choiceKeys.length; i++) {
 283                     if (choiceKeys[i] == o) {
 284                         c = choices[i];
 285                         break;
 286                     }
 287                 }
 288                 return super.getListCellRendererComponent(list, c, index, isSelected, cellHasFocus);
 289             }
 290         });
 291 
 292         setToolTipText(choice, uiKey);
 293         ac.setAccessibleDescription(choice.getToolTipText());
 294         return choice;
 295     }
 296 
 297     private JLabel createLabel(String uiKey, boolean needMnemonic) {
 298         JLabel l = new JLabel(i18n.getString(uiKey + ".lbl"));
 299         l.setName(uiKey);
 300         if (needMnemonic)
 301             l.setDisplayedMnemonic(getMnemonic(uiKey));
 302         setToolTipText(l, uiKey);
 303         return l;
 304     }
 305 
 306     private char getMnemonic(String uiKey) {
 307         return i18n.getString(uiKey + ".mne").charAt(0);
 308     }
 309 
 310     private void setToolTipText(JComponent c, String uiKey) {
 311         c.setToolTipText(i18n.getString(uiKey + ".tip"));
 312     }
 313 
 314     private ActionListener listener = new ActionListener() {
 315         public void actionPerformed(ActionEvent e) {
 316             String cmd = e.getActionCommand();
 317             if (cmd.equals(FIND))
 318                 find();
 319             else if (cmd.equals(CLOSE))
 320                 setVisible(false);
 321             else if (cmd.equals(HELP)) {
 322                 helpBroker.displayCurrentID(helpPrefix + "search.csh");
 323             }
 324         }
 325     };
 326 
 327     private Interview interview;
 328     private Question currentQuestion;
 329     private HelpBroker helpBroker;
 330     private String helpPrefix;
 331     private JTextField textField;
 332     private JComboBox<String> whereChoice;
 333     private JCheckBox caseChk;
 334     private JCheckBox wordChk;
 335 
 336     private static final String ANSWER = "answer";
 337     private static final String ANYWHERE = "anywhere";
 338     private static final String CLOSE = "close";
 339     private static final String FIND = "find";
 340     private static final String HELP = "help";
 341     private static final String QUESTION = "question";
 342     private static final String TITLE = "title";
 343     private static final KeyStroke escapeKey = KeyStroke.getKeyStroke("ESCAPE");
 344 
 345     private static final I18NResourceBundle i18n = I18NResourceBundle.getDefaultBundle();
 346 }