1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 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.javatest.exec;
  28 
  29 import java.awt.BorderLayout;
  30 import java.awt.CardLayout;
  31 import java.awt.Component;
  32 import java.awt.EventQueue;
  33 import java.awt.GridBagLayout;
  34 import java.awt.GridBagConstraints;
  35 import java.awt.event.ActionEvent;
  36 import java.awt.event.ActionListener;
  37 import java.awt.event.ComponentEvent;
  38 import java.awt.event.ComponentListener;
  39 import java.util.ResourceBundle;
  40 
  41 import javax.swing.JButton;
  42 import javax.swing.JComboBox;
  43 import javax.swing.JComponent;
  44 import javax.swing.JLabel;
  45 import javax.swing.JList;
  46 import javax.swing.JMenuItem;
  47 import javax.swing.JPanel;
  48 import javax.swing.JSplitPane;
  49 import javax.swing.JPopupMenu;
  50 import javax.swing.JTextField;
  51 import javax.swing.JToolBar;
  52 import javax.swing.Timer;
  53 import javax.swing.plaf.basic.BasicComboBoxRenderer;
  54 import javax.swing.text.JTextComponent;
  55 
  56 import com.sun.javatest.Harness;
  57 import com.sun.javatest.Parameters;
  58 import com.sun.javatest.TestResult;
  59 import com.sun.javatest.tool.Preferences;
  60 import com.sun.javatest.tool.UIFactory;
  61 import com.sun.javatest.tool.jthelp.ContextHelpManager;
  62 
  63 /**
  64  * The panel at the bottom of exec tool.
  65  * This class manages the insertion, deletion, and rearrangement of any small
  66  * monitors.  It also forwards informational text messages to the user.
  67  */
  68 
  69 class MessageStrip extends JSplitPane
  70     implements Harness.Observer, ComponentListener
  71 {
  72     MessageStrip(UIFactory uif, Monitor[] monitors, MonitorState state,
  73                  ActionListener zoomListener) {
  74         this.uif = uif;
  75         this.monitors = monitors;
  76         this.state = state;
  77         this.zoomListener = zoomListener;
  78 
  79         setOrientation(JSplitPane.HORIZONTAL_SPLIT);
  80 
  81         // left side is a simple text field
  82         leftField = uif.createOutputField("strip.msg");
  83         leftField.setOpaque(false);
  84 
  85         setLeftComponent(leftField);
  86         setRightComponent(createRightPanel());
  87 
  88         setDividerSize(5);
  89         setEnabled(true);
  90         addComponentListener(this);
  91         uif.setAccessibleInfo(this, "strip");
  92         setDividerLocation(0.60d);
  93     }
  94 
  95     // which to display while running tests
  96     void setRunningMonitor(Monitor m) {
  97         for (int i = 0; i < monitors.length; i++)
  98             if (monitors[i] == m) {
  99                 runningMonitor = i;
 100                 break;
 101             }
 102     }
 103 
 104     // which to display while not running tests
 105     // these are not currently intended to be called after initialization
 106     void setIdleMonitor(Monitor m) {
 107         for (int i = 0; i < monitors.length; i++)
 108             if (monitors[i] == m) {
 109                 idleMonitor = i;
 110                 break;
 111             }
 112 
 113         setMonitor(idleMonitor);
 114     }
 115 
 116     void setMonitor(final int index) {
 117         if (index < 0)
 118             return;
 119 
 120         if (!EventQueue.isDispatchThread()) {
 121             EventQueue.invokeLater(new Runnable() {
 122                 public void run() {
 123                     setMonitor(index);
 124                 }
 125             });
 126             return;
 127         }
 128 
 129         if (index < monitors.length) {
 130             currMonitor = index;
 131             monitorCards.show(rightPanel, monitors[index].getSmallMonitorName());
 132             selector.setSelectedItem(monitors[index]);
 133             validate();     // required for correct repaint
 134 
 135             // write to preferences
 136             Preferences p = Preferences.access();
 137             p.setPreference(MINI_PREF, monitors[index].getClass().getName());
 138         }
 139     }
 140 
 141     // Harness.Observer ...
 142     // anything that happens here must be switched on to the event thread
 143 
 144     public void startingTestRun(Parameters params) {
 145         setText(leftField, uif.getI18NString("strip.start"));
 146         setMonitor(runningMonitor);
 147 
 148         if (clearTimer == null)
 149             clearTimer = new Timer(CLEAR_TIMEOUT, new ActionListener() {
 150                 public void actionPerformed(ActionEvent evt) {
 151                     setText(leftField, "");
 152                 }
 153             });
 154         clearTimer.start();
 155     }
 156 
 157     public void startingTest(TestResult tr) {
 158         setText(leftField, uif.getI18NString("strip.running", tr.getTestName()));
 159     }
 160 
 161     public void finishedTest(TestResult tr) {
 162     }
 163 
 164     public void stoppingTestRun() {
 165         setText(leftField, uif.getI18NString("strip.stop"));
 166     }
 167 
 168     public void finishedTesting() {
 169         setText(leftField, uif.getI18NString("strip.cleanup"));
 170         setMonitor(idleMonitor);
 171     }
 172 
 173     public void finishedTestRun(boolean allOk) {
 174         setText(leftField, uif.getI18NString("strip.finish"));
 175         if (clearTimer != null)
 176             clearTimer.stop();
 177     }
 178 
 179     public void error(String msg) {
 180     }
 181 
 182     void showMessage(ResourceBundle msgs, String key) {
 183         setText(leftField, msgs.getString(key));
 184     }
 185 
 186     private void setText(JTextComponent comp, String text) {
 187         if (EventQueue.isDispatchThread())
 188             comp.setText(text);
 189         else
 190             EventQueue.invokeLater(new BranchPanel.TextUpdater(comp, text, uif));
 191     }
 192 
 193     private JPopupMenu createMenu() {
 194         JPopupMenu menu = uif.createPopupMenu("strip.menu");
 195         for (int i = 0; i < monitors.length; i++) {
 196             JMenuItem mi = uif.createLiteralMenuItem(
 197                 monitors[i].getSmallMonitorName(), actionListener);
 198             mi.setActionCommand(Integer.toString(i));
 199             menu.add(mi);
 200         }   // for
 201 
 202 
 203         return menu;
 204     }
 205 
 206     private JComponent createRightPanel() {
 207         JPanel right = uif.createPanel("strip.right", new GridBagLayout(), false);
 208 
 209         selector = uif.createLiteralChoice("strip.sel", monitors);
 210         uif.setAccessibleName(selector, "strip.sel");
 211         selector.addActionListener(actionListener);
 212         selector.setRenderer(new BasicComboBoxRenderer() {
 213                 public Component getListCellRendererComponent(JList list, Object value,
 214                             int index, boolean isSelected, boolean cellHasFocus) {
 215                     Component c = super.getListCellRendererComponent(list, value,
 216                                                 index, isSelected, cellHasFocus);
 217                     try {
 218                         JLabel lab = (JLabel)c;
 219                         if (value instanceof Monitor)
 220                             lab.setText(((Monitor)value).getSmallMonitorName());
 221                     }
 222                     catch (ClassCastException e) {
 223                     }
 224 
 225                     return c;
 226                 }
 227             });
 228         ContextHelpManager.setHelpIDString(selector, "run.testProgress");
 229 
 230         GridBagConstraints gbc = new GridBagConstraints();
 231         gbc.weightx = 2.0d;
 232         gbc.gridx = 0;
 233         gbc.gridy = 0;
 234         gbc.fill = GridBagConstraints.HORIZONTAL;
 235         gbc.anchor = GridBagConstraints.WEST;
 236 
 237         monitorCards = new CardLayout();
 238         rightPanel = uif.createPanel("strip.", monitorCards, false);
 239         for (int i = 0; i < monitors.length; i++)
 240             rightPanel.add(monitors[i].getSmallMonitorName(), monitors[i].getSmallMonitor());
 241         currMonitor = getDefaultSmallMonitor();
 242         monitorCards.show(rightPanel, monitors[currMonitor].getSmallMonitorName());
 243 
 244         JPanel tmpPanel = uif.createPanel("monitor container", new BorderLayout(), false);
 245         tmpPanel.add(selector, BorderLayout.WEST);
 246         tmpPanel.add(rightPanel, BorderLayout.CENTER);
 247 
 248         right.add(tmpPanel, gbc);
 249 
 250         gbc.gridx = 1;
 251         gbc.weightx = 0.0d;
 252         /*
 253         gbc.anchor = GridBagConstraints.EAST;
 254         selectButt = uif.createIconButton("strip.drop");
 255         selectButt.addMouseListener(popupListener);
 256         selectButt.addActionListener(popupListener);
 257         uif.setAccessibleName(selectButt, "strip.drop");
 258 
 259         gbc.gridx = 2;
 260         */
 261         magButt = uif.createIconButton("strip.magnify");
 262         magButt.addActionListener(actionListener);
 263         uif.setAccessibleName(magButt, "strip.magnify");
 264 
 265         JToolBar tb = uif.createToolBar("strip.tb",
 266                             new JButton[] {magButt});
 267         tb.setFloatable(false);
 268         tb.setBorderPainted(true);
 269 
 270         right.add(tb, gbc);
 271 
 272         right.setEnabled(true);
 273         right.setVisible(true);
 274         rightPanel.setEnabled(true);
 275         rightPanel.setVisible(true);
 276 
 277         return right;
 278     }
 279 
 280     // --------------- private --------------------
 281 
 282     /**
 283      * Determine by whatever means, which monitor should be shown.
 284      */
 285     private int getDefaultSmallMonitor() {
 286         if (idleMonitor != -1)
 287             return idleMonitor;
 288         else {
 289             Preferences p = Preferences.access();
 290             String prefSetting = p.getPreference(MINI_PREF, null);
 291 
 292             int index = 0;
 293 
 294             // don't do anything if there's no monitors or no pref.
 295             if (prefSetting != null && monitors != null) {
 296                 try {
 297                     for (int i = 0; i < monitors.length; i++) {
 298                         if (monitors[i].getClass().getName().equals(prefSetting)) {
 299                             index = i;
 300                             break;
 301                         }
 302                     }   // for
 303                 }   // try
 304                 catch (NumberFormatException excep) {
 305                     // ok, whatever...
 306                     index = 0;
 307                 }
 308             }   // outer if
 309             // whatever happens, zero is the default
 310 
 311             return index;
 312         }
 313     }
 314 
 315     private int getMonitorIndex(Monitor m) {
 316         if (monitors == null || monitors.length == 0)
 317             return -1;
 318 
 319         for (int i = 0; i < monitors.length; i++)
 320             if (monitors[i] == m)
 321                 return i;
 322 
 323         return -1;
 324     }
 325 
 326     // ---------- ComponentListener ----------
 327     public void componentHidden(ComponentEvent e) { }
 328     public void componentMoved(ComponentEvent e) { }
 329     public void componentResized(ComponentEvent e) {
 330         setDividerLocation(0.70d);
 331     }
 332     public void componentShown(ComponentEvent e) { }
 333 
 334     private JTextField leftField;
 335     private JPanel rightPanel;
 336     private JButton selectButt;
 337     private JButton magButt;
 338 
 339     private JComboBox<Monitor> selector;
 340     private JPopupMenu popMenu;
 341     private ActionListener actionListener = new SelectionListener();
 342     private ActionListener zoomListener;
 343     private Monitor[] monitors;
 344     private MonitorState state;
 345     private int currMonitor;
 346     private CardLayout monitorCards;
 347     private int runningMonitor = -1;
 348     private int idleMonitor = -1;
 349     private Timer clearTimer;
 350     private static final int CLEAR_TIMEOUT = 5000;  // time before msg is cleared
 351 
 352     private UIFactory uif;
 353 
 354     private static final String MINI_PREF = "exec.monitorstrip.mini";
 355 
 356     class SelectionListener implements ActionListener {
 357         public void actionPerformed(ActionEvent e) {
 358             Object source = e.getSource();
 359 
 360             if (source == magButt) {
 361                 zoomListener.actionPerformed(e);
 362             }
 363             else if (source == selector) {
 364                 Object item = selector.getSelectedItem();
 365                 setMonitor(getMonitorIndex((Monitor)item));
 366             }
 367             else if (source instanceof JMenuItem) {
 368                 try {
 369                     int index = Integer.parseInt(e.getActionCommand());
 370 
 371                     // no change, or index is out of valid range for some reason
 372                     if (currMonitor == index || index >= monitors.length)
 373                         return;
 374 
 375                     setMonitor(index);
 376                 }   // try
 377                 catch (NumberFormatException excep) {
 378                     // ignore event
 379                 }       // catch
 380             }
 381         }   // actionPerformed()
 382     }
 383 
 384 }
 385