1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2002, 2013, 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.tool;
  28 
  29 import java.awt.Component;
  30 import java.awt.Dimension;
  31 import java.awt.event.ActionEvent;
  32 import java.awt.event.ActionListener;
  33 import java.text.DateFormat;
  34 import java.util.*;
  35 
  36 import javax.swing.JButton;
  37 import javax.swing.JComponent;
  38 import javax.swing.JDialog;
  39 import javax.swing.JMenu;
  40 import javax.swing.JMenuItem;
  41 import javax.swing.JOptionPane;
  42 import javax.swing.JPopupMenu;
  43 import javax.swing.JPopupMenu.Separator;
  44 import javax.swing.ScrollPaneConstants;
  45 import javax.swing.JTextArea;
  46 import javax.swing.JTextField;
  47 import javax.swing.event.MenuEvent;
  48 import javax.swing.event.MenuListener;
  49 
  50 import com.sun.interview.Help;
  51 import com.sun.javatest.Harness;
  52 import com.sun.javatest.ProductInfo;
  53 import com.sun.javatest.TestSuite;
  54 import com.sun.javatest.tool.jthelp.HelpBroker;
  55 import com.sun.javatest.tool.jthelp.HelpSet;
  56 import com.sun.javatest.tool.jthelp.JTHelpBroker;
  57 
  58 
  59 class HelpMenu extends JMenu
  60 {
  61     HelpMenu(Component parent, Desktop desktop, UIFactory uif) {
  62         this.parent = parent;
  63         this.desktop = desktop;
  64         this.uif = uif;
  65 
  66         listener = new Listener();
  67 
  68         String[] items = {
  69             HELP,
  70             null,
  71             // test suite items will be dynamically added here
  72             // (after the last separator)
  73             ABOUT_JAVATEST,
  74             ABOUT_JAVA
  75         };
  76         uif.initMenu(this, "hm", items, listener);
  77         addMenuListener(listener);
  78     }
  79 
  80     private void addTestSuiteItems() {
  81         Tool[] tools = desktop.getTools();
  82         if (tools == null || tools.length == 0) {
  83             return;
  84         }
  85 
  86         // first, collect the set of active test suites
  87         Set<TestSuite> loadedTestSuites = new TreeSet<>(new Comparator<TestSuite>() {
  88             @Override
  89                 public int compare(TestSuite o1, TestSuite o2) {
  90                     TestSuite ts1 = o1;
  91                     TestSuite ts2 = o2;
  92                     return ts1.getName().compareTo(ts2.getName());
  93                 }
  94             });
  95         Tool selTool = desktop.getSelectedTool();
  96         if (selTool != null) {
  97             TestSuite[] tss = selTool.getLoadedTestSuites();
  98             if (tss != null){
  99                 loadedTestSuites.addAll(Arrays.asList(tss));
 100             }
 101         }
 102         else {
 103             for (int i = 0; i < tools.length; i++) {
 104                 TestSuite[] tss = tools[i].getLoadedTestSuites();
 105                 if (tss != null) {
 106                     loadedTestSuites.addAll(Arrays.asList(tss));
 107                 }
 108             }
 109         }
 110 
 111 
 112         // locate insert point after last separator
 113         int insertPoint = getItemCount() - 1;
 114         while (insertPoint > 0 && (getItem(insertPoint - 1) != null)) {
 115             insertPoint--;
 116         }
 117 
 118         // for the active test suites, add any available help sets to the menu
 119         // e.g. those specified in the testsuite.jtt
 120         int count = 0;
 121         for (Iterator<TestSuite> iter = loadedTestSuites.iterator(); iter.hasNext(); ) {
 122             TestSuite ts = (iter.next());
 123             JMenuItem[] menuItems = getMenuItems(ts, count);
 124             if (menuItems != null && menuItems.length > 0) {
 125                 for (int i = 0; i < menuItems.length; i++) {
 126                     JMenuItem mi = menuItems[i];
 127                     // mark the entry as a dynamic entry
 128                     mi.putClientProperty(getClass(), this);
 129                     insert(mi, insertPoint++);
 130                 }
 131 
 132                 Separator sep = new Separator();
 133                 sep.putClientProperty(getClass(), this);
 134                 JPopupMenu p = getPopupMenu();
 135                 p.insert(sep, insertPoint++);
 136                 count += menuItems.length + 1;
 137             }
 138         }
 139 
 140         // add custom menus (as GUI components)
 141         // e.g. those that come from exec tool
 142         // this is suboptimal/wrong if the test suite uses both
 143         // custom GUI menus and help from the testsuite.jtt
 144         ToolManager[] mgrs = desktop.getToolManagers();
 145         for (int i = 0; i < mgrs.length; i++) {
 146             JMenuItem[] jmi = mgrs[i].getHelpPrimaryMenus();
 147             if (jmi != null) {
 148                 for (int j = 0; j < jmi.length; j++)  {
 149                     jmi[j].putClientProperty(getClass(), this);
 150                     insert(jmi[j], insertPoint++);
 151                 }   // inner for
 152             }
 153         }   // for
 154 
 155         // add secondary test suite help items
 156         for (int i = 0; i < mgrs.length; i++) {
 157             JMenuItem[] jmi = mgrs[i].getHelpTestSuiteMenus();
 158             if (jmi != null) {
 159                 for (int j = 0; j < jmi.length; j++)  {
 160                     jmi[j].putClientProperty(getClass(), this);
 161                     insert(jmi[j], insertPoint++);
 162                 }   // inner for (j)
 163             }
 164         }   // for
 165 
 166         // add test suite specified About items
 167         for (int i = 0; i < mgrs.length; i++) {
 168             JMenuItem[] jmi = mgrs[i].getHelpAboutMenus();
 169             if (jmi != null) {
 170                 for (int j = 0; j < jmi.length; j++)  {
 171                     jmi[j].putClientProperty(getClass(), this);
 172                     add(jmi[j]);
 173                 }   // inner for (j)
 174             }
 175         }   // for
 176     }
 177 
 178     private void removeTestSuiteItems() {
 179         for (Component c : getMenuComponents()) {
 180             if (c instanceof JComponent) {
 181                 JComponent comp = (JComponent) c;
 182                 if (comp.getClientProperty(getClass()) == this) {
 183                     remove(comp);
 184                 }
 185             }
 186         }
 187     }
 188 
 189     /**
 190      * Display a multi-line string in a dialog window, in response
 191      * to a Help>About.... menu item.
 192      * @param contKey i18n bundle key for getting accessibility name and desc
 193      *        for the container
 194      * @param filedKey i18n bundle key for getting accessibility name and desc
 195      *        for each of the fields holding the "about" text
 196      */
 197     private void showAbout(String title, String s, String contKey, String fieldKey) {
 198         List<String> v = new ArrayList<>();
 199         int start = 0;
 200         int end   = 0;
 201 
 202         while ((end = s.indexOf('\n', start)) != -1) {
 203             v.add(s.substring(start, end));
 204             start = end+1;
 205         }
 206         v.add(s.substring(start));
 207 
 208         //JTextField[] tfs = new JTextField[v.size()];
 209         ArrayList<JComponent> tfs = new ArrayList<>();
 210         for (int i = 0; i < v.size(); i++) {
 211             JTextField tf = new JTextField(v.get(i));
 212             tf.setBorder(null);
 213             tf.setHorizontalAlignment(JTextField.CENTER);
 214             tf.setOpaque(false);
 215             tf.setBackground(UIFactory.Colors.TRANSPARENT.getValue());
 216             tf.setEditable(false);
 217             uif.setAccessibleInfo(tf, fieldKey);
 218             tfs.add(tf);
 219         }
 220 
 221         JTextArea ta = uif.createMessageArea("hm.aboutJavaTest.copy");
 222         ta.setRows(15);
 223         tfs.add(uif.createScrollPane(ta,
 224                 ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED,
 225                 ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED));
 226         Object[] fields = tfs.toArray();
 227 
 228         /*
 229         JOptionPane.showMessageDialog(parent,
 230                                       tfs,
 231                                       title,
 232                                       JOptionPane.INFORMATION_MESSAGE,
 233                                       desktop.getLogo());
 234         */
 235         JOptionPane pane = new JOptionPane(fields, JOptionPane.INFORMATION_MESSAGE);
 236         pane.setIcon(desktop.getLogo());
 237         pane.setOptionType(JOptionPane.OK_OPTION);
 238         uif.setAccessibleInfo(pane, contKey);
 239         JButton okBtn = uif.createCloseButton("hm.about.ok", false);
 240         pane.setOptions(new Object[] { okBtn });
 241         JDialog d = pane.createDialog(parent, title);
 242         d.getRootPane().setDefaultButton(okBtn);
 243         d.setVisible(true);
 244     }
 245 
 246     private void showHelpSet(HelpSet hs) {
 247         HelpBroker hb = getHelpBroker(hs);
 248         if (hb != null) {
 249             //hb.setDisplayed(true);
 250             //if (hb instanceof DefaultHelpBroker)
 251             //    ((DefaultHelpBroker) hb).getWindowPresentation().getHelpWindow().toFront();
 252         }
 253         else {
 254             // could internationalize this, but the error isn't that helpful because a
 255             // end-user probably can't fix the problem
 256             System.err.println("Unable to display help, the help set isn't available.");
 257         }
 258     }
 259 
 260     private HelpBroker getHelpBroker(HelpSet hs) {
 261         HelpBroker hb = helpBrokerTable.get(hs);
 262         if (hb == null) {
 263             //hb = hs.createHelpBroker();   // pres. attributes work with this on JH 2.0_02
 264             hb = new JTHelpBroker();
 265             helpBrokerTable.put(hs, hb);
 266         }
 267         return hb;
 268     }
 269 
 270     private JMenuItem[] getMenuItems(TestSuite ts, int count) {
 271         HelpSet[] docs = docTable.get(ts);
 272         if (docs == null) {
 273             try {
 274                 docs = Help.getAdditionalDocs(ts);
 275             }
 276             catch (Help.Fault e) {
 277                 String msg = uif.getI18NString("hm.cantLoadDocs",
 278                                                new Object[] { ts.getName(), e.getMessage() });
 279                 System.err.println(msg);
 280             }
 281             if (docs == null)
 282                 docs = new HelpSet[0];
 283             docTable.put(ts, docs);
 284         }
 285 
 286         if (docs.length == 0) {
 287             return null;
 288         }
 289 
 290         ArrayList<JMenuItem> v = new ArrayList<>();
 291         for (int i = 0; i < docs.length; i++) {
 292             final HelpSet doc = docs[i];
 293 
 294             JMenuItem mi;
 295             if (count + i < 10) {
 296                 mi = new JMenuItem((count + i) + " " + doc.getTitle());
 297                 mi.setMnemonic('0' + count + i);
 298             }
 299             else {
 300                 mi = new JMenuItem("  " + doc.getTitle());
 301             }
 302 
 303             mi.addActionListener(new ActionListener() {
 304                 @Override
 305                     public void actionPerformed(ActionEvent e) {
 306                         showHelpSet(doc);
 307                     }
 308                 });
 309 
 310             v.add(mi);
 311         }
 312 
 313         JMenuItem[]items = new JMenuItem[v.size()];
 314         v.toArray(items);
 315         return items;
 316     }
 317 
 318     private Component parent;
 319     private Desktop desktop;
 320     private UIFactory uif;
 321 
 322     private Listener listener;
 323 
 324     private static Map<TestSuite, HelpSet[]> docTable = new WeakHashMap<>();  // gives HelpSet[] for TestSuite
 325     private static Map<HelpSet, HelpBroker> helpBrokerTable = new WeakHashMap<>(); // gives HelpBroker for HelpSet
 326 
 327     private static final String HELP = "help";
 328     private static final String ABOUT_JAVA = "aboutJava";
 329     private static final String ABOUT_JAVATEST = "aboutJavaTest";
 330 
 331     private class Listener
 332         implements MenuListener, ActionListener
 333     {
 334         @Override
 335         public void menuSelected(MenuEvent e) {
 336             // remove any prior items
 337             removeTestSuiteItems();
 338             // add current ones
 339             addTestSuiteItems();
 340         }
 341 
 342         @Override
 343         public void menuDeselected(MenuEvent e) {
 344         }
 345 
 346         @Override
 347         public void menuCanceled(MenuEvent e) {
 348         }
 349 
 350         @Override
 351         public void actionPerformed(ActionEvent e) {
 352             String cmd = e.getActionCommand();
 353             if (cmd.equals(ABOUT_JAVATEST)) {
 354                 JMenuItem src = (JMenuItem)(e.getSource());
 355 
 356                 // read en_US date, and prepare to emit it using the
 357                 // current locale
 358                 DateFormat df = DateFormat.getDateInstance(DateFormat.LONG);
 359                 String date = null;
 360                 Date dt = ProductInfo.getBuildDate();
 361                 if (dt != null) {
 362                     date = df.format(dt);
 363                 }
 364                 else {
 365                     date = uif.getI18NString("hm.aboutBadDate");
 366                 }
 367 
 368                 String aboutJavaTest =
 369                     uif.getI18NString("hm.aboutJavaTest", new Object[] {
 370                         ProductInfo.getName(),
 371                         ProductInfo.getVersion(),
 372                         ProductInfo.getMilestone(),
 373                         ProductInfo.getBuildNumber(),
 374                         Harness.getClassDir().getPath(),
 375                         ProductInfo.getBuildJavaVersion(),
 376                         date
 377                 });
 378                 showAbout(src.getText(), aboutJavaTest, "hm.aboutJavaTest",
 379                             "hm.aboutJavaTest.text");
 380             }
 381             else if (cmd.equals(ABOUT_JAVA)) {
 382                 JMenuItem src = (JMenuItem)(e.getSource());
 383                 String aboutJava =
 384                     uif.getI18NString("hm.aboutJava", new Object[] {
 385                         System.getProperty("java.version"),
 386                         System.getProperty("java.vendor"),
 387                         System.getProperty("java.home"),
 388                         System.getProperty("java.vendor.url")
 389                 });
 390                 showAbout(src.getText(), aboutJava, "hm.aboutJava", "hm.aboutJava.text");
 391             }
 392             else if (cmd.equals(HELP)) {
 393                 HelpBroker helpBroker = desktop.getHelpBroker();
 394                 if (helpBroker != null) {
 395                     helpBroker.displayCurrentID("jthelp.csh");
 396                 }
 397                 else {
 398                     // could internationalize this, but the error isn't that helpful because a
 399                     // end-user probably can't fix the problem
 400                     System.err.println("Unable to display help, the help system isn't available.");
 401                 }
 402             }
 403         }
 404 
 405     }
 406 }