1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2006, 2012, 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.mrep;
  28 
  29 import com.sun.javatest.CompositeFilter;
  30 import com.sun.javatest.InterviewParameters;
  31 import com.sun.javatest.TestFilter;
  32 import java.awt.BorderLayout;
  33 import java.awt.CardLayout;
  34 import java.awt.Color;
  35 import java.awt.Component;
  36 import java.awt.Container;
  37 import java.awt.GridBagConstraints;
  38 import java.awt.GridBagLayout;
  39 import java.awt.GridLayout;
  40 import java.awt.Insets;
  41 import java.awt.Toolkit;
  42 import java.awt.event.ActionListener;
  43 import java.awt.event.KeyEvent;
  44 import java.awt.event.KeyListener;
  45 import java.awt.event.MouseEvent;
  46 import java.beans.PropertyChangeEvent;
  47 import java.beans.PropertyChangeListener;
  48 import java.util.*;
  49 
  50 import javax.swing.BorderFactory;
  51 import javax.swing.DefaultListModel;
  52 import javax.swing.JButton;
  53 import javax.swing.JCheckBox;
  54 import javax.swing.JComponent;
  55 import javax.swing.JLabel;
  56 import javax.swing.JList;
  57 import javax.swing.JPanel;
  58 import javax.swing.JTabbedPane;
  59 import javax.swing.JTextArea;
  60 import javax.swing.ListCellRenderer;
  61 import javax.swing.ListModel;
  62 import javax.swing.ListSelectionModel;
  63 import javax.swing.event.ListSelectionEvent;
  64 import javax.swing.event.ListSelectionListener;
  65 import javax.swing.event.MouseInputAdapter;
  66 
  67 import com.sun.javatest.exec.ContextManager;
  68 import com.sun.javatest.exec.ExecTool;
  69 import com.sun.javatest.report.CustomReport;
  70 import com.sun.javatest.report.CustomReport.ReportConfigPanel;
  71 import com.sun.javatest.report.Report;
  72 import com.sun.javatest.report.ReportSettings;
  73 import com.sun.javatest.tool.Desktop;
  74 import com.sun.javatest.tool.Tool;
  75 import com.sun.javatest.tool.UIFactory;
  76 import java.awt.Font;
  77 
  78 class OptionsPane extends JPanel {
  79 
  80     OptionsPane(UIFactory uif, Desktop desktop, ActionListener chTabListener,
  81             ActionListener okListener) {
  82         this.uif = uif;
  83         this.desktop = desktop;
  84         this.chTabListener = chTabListener;
  85         this.okListener = okListener;
  86         initGUI();
  87     }
  88 
  89     boolean resolveByRecent() {
  90         return resolveAsRecentBox.isSelected();
  91     }
  92 
  93     boolean isXmlReport() {
  94         return cbXml.isSelected();
  95     }
  96 
  97     CustomReport[] getCustomSelected() {
  98         return getActiveCustomReports().toArray(new CustomReport[0]);
  99     }
 100     protected void initGUI() {
 101         setName("opts");
 102         setFocusable(false);
 103         setLayout(new GridBagLayout());
 104         setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
 105 
 106         JLabel title = uif.createLabel("opts.title");
 107         GridBagConstraints lc = new GridBagConstraints();
 108         lc.gridwidth = GridBagConstraints.REMAINDER;
 109         lc.anchor = GridBagConstraints.WEST;
 110         lc.insets = new Insets(5,5,15,5);
 111         lc.fill = GridBagConstraints.HORIZONTAL;
 112         lc.weightx = 1.0;
 113         this.add(title, lc);
 114 
 115         lc = new GridBagConstraints();
 116         lc.anchor = GridBagConstraints.NORTHEAST;
 117         lc.gridheight = 2;
 118         lc.insets.right = 10;
 119         JLabel conflictLabel = uif.createLabel("opts.conflict", true);
 120         this.add(conflictLabel, lc);
 121 
 122         handleConfilctsBox = uif.createCheckBox("opts.handleconflict", true);
 123         lc = new GridBagConstraints();
 124         lc.anchor = GridBagConstraints.NORTHEAST;
 125         lc.fill = GridBagConstraints.HORIZONTAL;
 126         lc.gridwidth = GridBagConstraints.REMAINDER;
 127         handleConfilctsBox.setEnabled(false);
 128         this.add(handleConfilctsBox, lc);
 129 
 130         resolveAsRecentBox = uif.createCheckBox("opts.resolverecent", true);
 131         lc = new GridBagConstraints();
 132         lc.anchor = GridBagConstraints.NORTHEAST;
 133         lc.fill = GridBagConstraints.HORIZONTAL;
 134         this.add(resolveAsRecentBox, lc);
 135 
 136 // --------------------------------------------------------------------------------
 137         JPanel bottom = uif.createPanel("opts.bottom", false);
 138         bottom.setLayout(new BorderLayout());
 139         bottom.setBorder(BorderFactory.createCompoundBorder(
 140                         uif.createTitledBorder("opts.bottom"),
 141                         BorderFactory.createEmptyBorder(12,12,12,12)));
 142 
 143 
 144         listModel = new DefaultListModel<>();
 145 
 146         // populate list and card panel
 147         final CardLayout cards = new CardLayout();
 148         final JPanel p = uif.createPanel("opts.typecards", cards, false);
 149 
 150         // standard report
 151         cbXml = uif.createCheckBox("opts.type.xml", false);
 152         listModel.addElement(cbXml);
 153         p.add("opts.type.xml", uif.createPanel("opts.blank", false));
 154 
 155         // custom entries
 156         getCustomReports(p);
 157 
 158         list = uif.createList("opts.typel", listModel);
 159         list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 160         SelectListener sl = new SelectListener(list, p, cards);
 161         list.addMouseListener(sl);
 162         list.addKeyListener(sl);
 163         list.addListSelectionListener(sl);
 164         list.setCellRenderer(new CheckBoxListCellRenderer());
 165         list.setBorder(BorderFactory.createCompoundBorder(
 166             BorderFactory.createEtchedBorder(),
 167             BorderFactory.createEmptyBorder(0,3,0,3)));
 168 
 169 
 170 
 171         descriptionArea = uif.createMessageArea("opts.type.desc");
 172         descriptionArea.setRows(3);
 173         Font f = descriptionArea.getFont();
 174         f = f.deriveFont(Font.PLAIN, f.getSize2D()-1);
 175         descriptionArea.setFont(f);
 176 
 177 
 178         if (customBoxes != null && list != null) {
 179             CustomReport val = customBoxes.get(list.getSelectedValue());
 180             if (val != null)
 181                 descriptionArea.setText(val.getDescription());
 182         }
 183 
 184         JPanel rightCenter = uif.createPanel("opts.blank", false);
 185         rightCenter.setLayout(new BorderLayout());
 186         //rightCenter.setBackground(Color.magenta);
 187         rightCenter.add(descriptionArea, BorderLayout.PAGE_START);
 188         rightCenter.add(p, BorderLayout.CENTER);
 189         bottom.add(rightCenter, BorderLayout.CENTER);
 190 
 191         bottom.add(list, BorderLayout.WEST);
 192 
 193         lc.insets.left = 0;
 194         lc.gridwidth = 1;
 195         lc.gridy = 3;
 196         lc.anchor = GridBagConstraints.NORTHWEST;
 197         lc.gridwidth = GridBagConstraints.REMAINDER;
 198         lc.fill = GridBagConstraints.BOTH;
 199         lc.weighty = 1.0;
 200 
 201         add(bottom, lc);
 202 
 203 //---------------------------------------------------------------------------------
 204 
 205         okBtn = uif.createButton("opts.ok", okListener);
 206         cancelBtn = uif.createCancelButton("opts.cancel");
 207         backBtn = uif.createButton("opts.back", chTabListener);
 208         helpBtn = uif.createHelpButton("opts.help",
 209                         "mergeReports.window.csh");
 210         JButton[] buttons = new JButton[] { okBtn, cancelBtn, helpBtn };
 211 
 212         JPanel buttonsPanel = uif.createPanel("opts.but");
 213         GridBagConstraints co = new GridBagConstraints();
 214         co.anchor = GridBagConstraints.EAST;
 215         co.weightx = 1;
 216         co.gridwidth = 3;
 217         co.insets = new Insets(10,0,0,0);
 218 
 219         GridBagConstraints bb = new GridBagConstraints();
 220         bb.anchor = GridBagConstraints.WEST;
 221         bb.insets = new Insets(10,0,0,0);
 222         this.add(backBtn, bb);
 223 
 224         this.add(buttonsPanel, co);
 225         buttonsPanel.setLayout(new GridLayout(1, 3, 5, 5));
 226 
 227         GridBagConstraints b = new GridBagConstraints();
 228         b.anchor = GridBagConstraints.EAST;
 229         co.insets = new Insets(10,0,0,0);
 230         for (int i = 0; i < buttons.length; i++) {
 231             buttonsPanel.add(buttons[i]);
 232 
 233         }
 234 
 235         list.setSelectedIndex(0);
 236     }
 237 
 238     /**
 239      * @return number of custom reports added
 240      */
 241     private int getCustomReports(JPanel p) {
 242         int result = 0;
 243         Tool[] tools = desktop.getTools();
 244         List<CustomReport> customReportsList = new ArrayList<>();
 245         for (int i = 0; i < tools.length; i++) {
 246             if (tools[i] instanceof ExecTool) {
 247                 // should not be using report types from ExecTool
 248                 // should have a separate list available for this tool
 249                 ExecTool tool = (ExecTool) tools[i];
 250                 InterviewParameters ip = tool.getInterviewParameters();
 251                 TestFilter tf = new CompositeFilter(ip.getFilters());
 252                 ReportSettings rs = new ReportSettings(ip);
 253                 rs.setFilter(tf);
 254                 ContextManager cm = tool.getContextManager();
 255                 if (cm != null && cm.getCustomReports() != null) {
 256                     for (CustomReport cr : cm.getCustomReports()) {
 257                         cr.setEnviroment(rs);
 258                         customReportsList.add(cr);
 259                     }
 260                 }
 261             }
 262         }   // for
 263 
 264         customReports = customReportsList
 265                 .toArray(new CustomReport[0]);
 266         if (customReports == null || customReports.length == 0) {
 267             customReports = null;
 268             return 0;
 269         }
 270 
 271         customBoxes = new HashMap<>();
 272 
 273         for (int i = 0; i < customReports.length; i++) {
 274             JCheckBox cb = new JCheckBox(customReports[i].getName());
 275             cb.setName(customReports[i].getReportId());
 276             listModel.addElement(cb);
 277             customBoxes.put(cb, customReports[i]);
 278 
 279             ReportConfigPanel[] ops = customReports[i].getOptionPanes();
 280             if (ops == null || ops.length == 0) {
 281                 // no config panels, use blank
 282                 p.add(customReports[i].getReportId(), uif.createPanel(
 283                         "opts.blank", false));
 284             } else {
 285                 // tabbed pane for all supplied panels
 286                 JTabbedPane tp = uif.createTabbedPane("opts.custom.tabs");
 287                 for (int j = 0; j < ops.length; j++)
 288                     tp.addTab(ops[j].getPanelName(), ops[j]);
 289 
 290                 p.add(customReports[i].getReportId(), tp);
 291             }
 292             result++;
 293         } // for
 294 
 295         return result;
 296     }
 297 
 298     private ArrayList<CustomReport> getActiveCustomReports() {
 299 
 300         ArrayList<CustomReport> customReps = new ArrayList<>();
 301         if (customBoxes != null && customBoxes.size() > 0) {
 302             Iterator<JCheckBox> it = customBoxes.keySet().iterator();
 303             while (it.hasNext()) {
 304                 JCheckBox box = it.next();
 305                 if (box.isSelected()) {
 306                     customReps.add(customBoxes.get(box));
 307                 }
 308             }
 309         }
 310         return customReps;
 311     }
 312 
 313 
 314     /**
 315      * This listener changes options state against checkboxes
 316      */
 317     private class SelectListener extends MouseInputAdapter implements
 318             KeyListener, ListSelectionListener {
 319 
 320         /**
 321          * @param lst JList of checkboxes
 322          * @param p parent Panel
 323          * @param cardLayout The CardLayout for options
 324          */
 325         SelectListener(JList<JCheckBox> lst, JPanel p, CardLayout cardLayout) {
 326             list = lst;
 327             listModel = list.getModel();
 328             lastSelected = listModel.getElementAt(0);
 329             panel = p;
 330             cards = cardLayout;
 331         }
 332 
 333         public void keyTyped(KeyEvent e) {
 334             if (e.getKeyChar() == ' ') {
 335                 process(list.getSelectedIndex());
 336             }
 337         }
 338 
 339         public void mouseClicked(MouseEvent e) {
 340             if (e.getPoint().getX() <= emptyCBW) {
 341                 process(list.locationToIndex(e.getPoint()));
 342             }
 343         }
 344 
 345         public void valueChanged(ListSelectionEvent e) {
 346             int index = list.getSelectedIndex();
 347             JCheckBox box = (listModel.getElementAt(index));
 348 
 349             if (lastSelected != box) {
 350                 cards.show(panel, box.getName());
 351                 lastSelected = box;
 352             }
 353             enablePanel(box);
 354         }
 355 
 356         private void enablePanel(final JCheckBox box) {
 357             for (int i = 0; i < panel.getComponentCount(); i++) {
 358                 JComponent tab = (JComponent) panel.getComponent(i);
 359                 tab.setEnabled(box.isSelected());
 360             }
 361 
 362             if (box == cbXml) {
 363                 descriptionArea.setText(uif.getI18NString("opts.xmlDesc.txt"));
 364                 return;
 365             }
 366 
 367             if (customBoxes != null) {
 368                 CustomReport rep = customBoxes.get(box);
 369                 if(rep != null) {
 370                     if (rep.getOptionPanes() != null) {
 371                         for (int i = 0; i < rep.getOptionPanes().length; i++) {
 372                             rep.getOptionPanes()[i].setEnabled(box.isSelected());
 373                         }   // for
 374                     }
 375 
 376                     descriptionArea.setText(rep.getDescription());
 377                 }
 378             }
 379         }
 380 
 381         private void process(final int index) {
 382             JCheckBox box = (listModel.getElementAt(index));
 383 
 384             if (lastSelected == box) {
 385                 box.doClick();
 386                 list.repaint(); // important!
 387                 enablePanel(box);
 388             }
 389             lastSelected = box;
 390         }
 391 
 392         public void keyReleased(KeyEvent e) {
 393         }
 394 
 395         public void keyPressed(KeyEvent e) {
 396         }
 397 
 398         Object lastSelected;
 399         JList<JCheckBox> list;
 400         ListModel<JCheckBox> listModel;
 401         JPanel panel;
 402         CardLayout cards;
 403         double emptyCBW = new JCheckBox("").getPreferredSize().getWidth() + 2;
 404     }
 405 
 406     /*
 407      * PropertyChangeListener for enabling/disabling container's content
 408      */
 409     private class PanelEnableListener implements PropertyChangeListener {
 410         /**
 411          * @param container Container for controlling
 412          */
 413         PanelEnableListener(Container container) {
 414             theContainer = container;
 415         }
 416 
 417         /**
 418          * Catches changes of "enabled" property
 419          * and changes enabled status for all child components
 420          */
 421         public void propertyChange(PropertyChangeEvent evt) {
 422             if ("enabled".equals(evt.getPropertyName())) {
 423                 boolean oldV = ((Boolean) evt.getOldValue()).booleanValue();
 424                 boolean newV = ((Boolean) evt.getNewValue()).booleanValue();
 425                 if (oldV && !newV) {
 426                     // disable
 427                     Iterator<Component> chIt = collectChildren(theContainer,
 428                             new ArrayList<Component>()).iterator();
 429                     enabledComp = new HashSet<>();
 430                     while (chIt.hasNext()) {
 431                         Component c = chIt.next();
 432                         if (c.isEnabled()) {
 433                             enabledComp.add(c);
 434                             c.setEnabled(false);
 435                         }
 436                     }
 437 
 438                 } else if (!oldV && newV && enabledComp != null) {
 439                     // enable
 440                     Iterator<Component> chIt = collectChildren(theContainer,
 441                             new ArrayList<Component>()).iterator();
 442                     while (chIt.hasNext()) {
 443                         Component c = chIt.next();
 444                         if (enabledComp.contains(c)) {
 445                             c.setEnabled(true);
 446                         }
 447                     }
 448                 }
 449             }
 450         }
 451 
 452         /**
 453          * Recursively gathers all children components
 454          */
 455         private Collection<Component> collectChildren(Container comp, Collection<Component> c) {
 456             Component[] ch = comp.getComponents();
 457             for (int i = 0; i < ch.length; i++) {
 458                 c.add(ch[i]);
 459                 if (ch[i] instanceof Container) {
 460                     collectChildren((Container) ch[i], c);
 461                 }
 462             }
 463             return c;
 464         }
 465 
 466         private Container theContainer;
 467 
 468         private Set<Component> enabledComp;
 469     }
 470 
 471     private class CheckBoxListCellRenderer implements ListCellRenderer<JCheckBox> {
 472         public Component getListCellRendererComponent(JList<? extends JCheckBox> list, JCheckBox comp,
 473                 int index, boolean isSelected, boolean cellHasFocus) {
 474             // assert: value is a JCheckBox
 475             if (isSelected) {
 476                 comp.setOpaque(true);
 477                 comp.setBackground(UIFactory.Colors.TEXT_HIGHLIGHT_COLOR.getValue());
 478             } else {
 479                 comp.setOpaque(false);
 480                 comp.setForeground(Color.black);
 481             }
 482 
 483             return comp;
 484         }
 485     }
 486 
 487     JButton[] getButtons() {
 488         return new JButton[] { backBtn, okBtn, cancelBtn, helpBtn };
 489     }
 490 
 491     private DefaultListModel<JCheckBox> listModel;
 492     private JList<JCheckBox> list;
 493     private CustomReport[] customReports;
 494     private JTextArea descriptionArea;
 495     private Map<JCheckBox, CustomReport> customBoxes;
 496     private JCheckBox cbXml;
 497     private JButton backBtn;
 498     private JButton okBtn;
 499     private JButton cancelBtn;
 500     private JCheckBox handleConfilctsBox;
 501     private JCheckBox resolveAsRecentBox;
 502     private ActionListener chTabListener;
 503     private ActionListener okListener;
 504     private JButton helpBtn;
 505 
 506     private Desktop desktop;
 507     private UIFactory uif;
 508     private static final int DOTS_PER_INCH = Toolkit.getDefaultToolkit().getScreenResolution();
 509 }