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.javatest.exec;
  28 
  29 import java.awt.BorderLayout;
  30 import java.awt.Color;
  31 import java.awt.Component;
  32 import java.awt.Dimension;
  33 import java.awt.EventQueue;
  34 import java.awt.event.ComponentEvent;
  35 import java.awt.event.ComponentListener;
  36 import java.beans.PropertyChangeEvent;
  37 import java.beans.PropertyChangeListener;
  38 import java.util.Map;
  39 import com.sun.javatest.tool.jthelp.ContextHelpManager;
  40 import javax.swing.JPanel;
  41 import javax.swing.JTabbedPane;
  42 import javax.swing.JTextField;
  43 import javax.swing.SwingConstants;
  44 import javax.swing.event.ChangeEvent;
  45 import javax.swing.event.ChangeListener;
  46 
  47 import com.sun.javatest.Harness;
  48 import com.sun.javatest.JavaTestError;
  49 import com.sun.javatest.Parameters;
  50 import com.sun.javatest.Status;
  51 import com.sun.javatest.TestDescription;
  52 import com.sun.javatest.TestResult;
  53 import com.sun.javatest.TestSuite;
  54 import com.sun.javatest.tool.I18NUtils;
  55 import com.sun.javatest.tool.UIFactory;
  56 import java.util.HashMap;
  57 import java.util.Vector;
  58 
  59 /**
  60  * Browser for details of a specific test. The browser provides a variety
  61  * of displays. controlled by its own toolbar (button-bar.)
  62  */
  63 
  64 class TestPanel extends JPanel
  65 {
  66     TestPanel(UIFactory uif, Harness harness, ContextManager contextManager) {
  67         this.uif = uif;
  68         this.harness = harness;
  69         this.contextManager = contextManager;
  70         initGUI();
  71 
  72     }
  73 
  74     // most of the tabs have arbitrary, accommodating sizes,
  75     // so set a default preferred size here for the panel
  76     public Dimension getPreferredSize() {
  77         int dpi = uif.getDotsPerInch();
  78         return new Dimension(5 * dpi, 4 * dpi);
  79     }
  80 
  81     void setTestSuite(TestSuite ts) {
  82         for (int i = 0; i < panels.length; i++)
  83             panels[i].setTestSuite(ts);
  84     }
  85 
  86     TestResult getTest() {
  87         return currTest;
  88     }
  89 
  90     void setTest(TestResult tr) {
  91         for (int i=stdPanels.length ; i < panels.length; i++) {
  92               TP_CustomSubpanel sp = (TP_CustomSubpanel) panels[i];
  93               sp.onCangedTestResult(tr, (sp == currPanel));
  94         }
  95         updatePanel(tr, currPanel);
  96     }
  97 
  98     //------private methods----------------------------------------------
  99 
 100     private synchronized void updatePanel(TestResult newTest, TP_Subpanel newPanel) {
 101         // this method is specifically designed to be fast to execute when
 102         // the panel is hidden; it also tries to avoid unnecessarily getting
 103         // rid of useful information which is still valid
 104 
 105         if (newTest != currTest) {
 106             currTest = newTest;
 107             currDesc = null;  // don't evaluate till later
 108         }
 109 
 110         if (newPanel != currPanel) {
 111             // update help for tabbed pane to reflect help for selected panel
 112             ContextHelpManager.setHelpIDString(tabs, ContextHelpManager.getHelpIDString(newPanel));
 113             currPanel = newPanel;
 114         }
 115 
 116         if (EventQueue.isDispatchThread())
 117             updateGUIWhenVisible();
 118         else {
 119             if (!updatePending && !needToUpdateGUIWhenShown) {
 120                 EventQueue.invokeLater(new Runnable() {
 121                         public void run() {
 122                             synchronized (TestPanel.this) {
 123                                 updateGUIWhenVisible();
 124                                 updatePending = false;
 125                             }
 126                         }
 127                     });
 128                 updatePending = true;
 129             }
 130         }
 131     }
 132 
 133 
 134     // must be called on the AWT event thread
 135     private void updateGUIWhenVisible() {
 136         if (isVisible())
 137             updateGUI();
 138         else
 139             needToUpdateGUIWhenShown = true;
 140     }
 141 
 142     // updateGUI is the second half of updatePanel(...)
 143     // It is called directly from updatePanel via updateGUIWhenVisible,
 144     // if the update is made when the panel is visible; otherwise the
 145     // call is delayed until the panel gets ComponentEvent.shown.
 146     private synchronized void updateGUI() {
 147         //System.err.println("TP.updateGUI");
 148         if (currTest == null) {
 149             for (int i = 0; i < tabs.getComponentCount(); i++)
 150                 tabs.setEnabledAt(i, false);
 151 
 152             statusField.setEnabled(false);
 153         }
 154         else {
 155             try {
 156                 if (currDesc == null)
 157                     currDesc = currTest.getDescription();
 158             }
 159             catch (TestResult.Fault e) {
 160                 JavaTestError.unexpectedException(e);
 161                 // ignore exception if can't find description ??
 162             }
 163 
 164             // always got a test description
 165             tabs.setEnabledAt(tabs.indexOfComponent(descPanel), true);
 166 
 167             // always got source files
 168             tabs.setEnabledAt(tabs.indexOfComponent(filesPanel), true);
 169 
 170             // check if there are any environment entries recorded
 171             boolean hasEnv;
 172             try {
 173                 Map map = currTest.getEnvironment();
 174                 hasEnv = (map != null && map.size() > 0);
 175             }
 176             catch (TestResult.Fault f) {
 177                 hasEnv = false;
 178             }
 179             tabs.setEnabledAt(tabs.indexOfComponent(envPanel), hasEnv);
 180 
 181             // check if there are any result properties recorded
 182             boolean hasResults = currTest.getPropertyNames().hasMoreElements();
 183             tabs.setEnabledAt(tabs.indexOfComponent(resultPanel), hasResults);
 184 
 185             // check if there is any output recorded
 186             boolean hasOutput = (currTest.getSectionCount() > 0);
 187             tabs.setEnabledAt(tabs.indexOfComponent(outputPanel), hasOutput);
 188 
 189             for (int i = stdPanels.length; i < tabs.getTabCount(); i++) {
 190                 tabs.setEnabledAt(i, true);
 191             }
 192 
 193             updateStatus();
 194 
 195             // should consider tracking test, if test is mutable
 196             // and enable tabs/status as required
 197             if (currPanel.isUpdateRequired(currTest)) {
 198                 currPanel.updateSubpanel(currTest);
 199             }
 200 
 201             FeatureManager fm = contextManager.getFeatureManager();
 202             if (fm.isEnabled(fm.SHOW_DOCS_FOR_TEST)) {
 203                 if (docPanel.isUpdateRequired(currTest)) {
 204                     docPanel.updateSubpanel(currTest);
 205                 }
 206                 tabs.setEnabledAt(tabs.indexOfComponent(docPanel),
 207                     docPanel.getDocuments() != null);
 208 
 209             }
 210 
 211         }
 212     }
 213 
 214     private void updateStatus() {
 215         if (isShowing()) {
 216             Status s = currTest.getStatus();
 217             statusField.setText(I18NUtils.getStatusMessage(s));
 218             Color c = I18NUtils.getStatusBarColor(s.getType());
 219             statusField.setBackground(c);
 220             statusField.setEnabled(true);
 221         }
 222     }
 223 
 224     /**
 225      * Updates custom panels except currPanel. Invoked when invoked when the
 226      * status of the current test result has changed.
 227      * @param tr  - test result
 228      * @param currPanel - the panel to not update
 229      */
 230     private void updateCustomPanels(TestResult tr, TP_Subpanel currPanel) {
 231         for (int i = stdPanels.length ; i < panels.length; i++) {
 232               TP_CustomSubpanel sp = (TP_CustomSubpanel) panels[i];
 233               if (sp != currPanel) {
 234                   sp.updateSubpanel(tr);
 235               }
 236         }
 237     }
 238 
 239     private void initGUI() {
 240         setName("test");
 241         descPanel = new TP_DescSubpanel(uif);
 242         filesPanel = new TP_FilesSubpanel(uif);
 243         resultPanel = new TP_ResultsSubpanel(uif);
 244         envPanel = new TP_EnvSubpanel(uif);
 245         outputPanel = new TP_OutputSubpanel(uif);
 246 
 247         Vector<TP_Subpanel> vpanels = new Vector<>();
 248         vpanels.add(descPanel);
 249 
 250         FeatureManager fm = contextManager.getFeatureManager();
 251         if (fm.isEnabled(fm.SHOW_DOCS_FOR_TEST)) {
 252             docPanel = new TP_DocumentationSubpanel(uif);
 253             vpanels.add(docPanel);
 254         }
 255 
 256         vpanels.add(filesPanel);
 257         vpanels.add(resultPanel);
 258         vpanels.add(envPanel);
 259         vpanels.add(outputPanel);
 260 
 261         stdPanels = new TP_Subpanel[vpanels.size()];
 262         stdPanels = vpanels.toArray(stdPanels);
 263 
 264         tabs = uif.createTabbedPane("test", stdPanels);
 265 
 266         panels = stdPanels;
 267         if (contextManager != null ) {
 268             CustomTestResultViewer[] cv = contextManager.getCustomResultViewers();
 269             if (cv != null) {
 270                 customViewTable = new HashMap<>();
 271                 panels = new TP_Subpanel[stdPanels.length + cv.length];
 272                 System.arraycopy(stdPanels, 0, panels, 0, stdPanels.length);
 273                 for (int i=0; i < cv.length; i++) {
 274                     panels[stdPanels.length + i] = new TP_CustomSubpanel(uif, cv[i]);
 275                     customViewTable.put(cv[i], panels[stdPanels.length + i]);
 276                     if (cv[i].isViewerVisible()) {
 277                         tabs.addTab(cv[i].getDescription(), null, cv[i], cv[i].getDescription());
 278                     }
 279                 }
 280                 for (int i=0; i < cv.length; i++) {
 281                     cv[i].addPropertyChangeListener(CustomTestResultViewer.visibleProperetyName,
 282                             new ViewerStateListener(cv, i, stdPanels.length));
 283                 }
 284             }
 285         }
 286 
 287         tabs.setTabPlacement(SwingConstants.TOP);
 288         tabs.setName("testTabs");
 289         tabs.setSelectedComponent(outputPanel);
 290         tabs.addChangeListener(new ChangeListener() {
 291             public void stateChanged(ChangeEvent e) {
 292                 Component c = tabs.getSelectedComponent();
 293                 if (c instanceof TP_Subpanel) {
 294                     updatePanel(currTest, (TP_Subpanel) c);
 295                 }  if (c instanceof CustomTestResultViewer) {
 296                     updatePanel(currTest, (TP_CustomSubpanel) customViewTable.get(c));
 297                 }
 298             }
 299         });
 300 
 301         currPanel = outputPanel;
 302         ContextHelpManager.setHelpIDString(tabs, ContextHelpManager.getHelpIDString(currPanel));
 303 
 304         statusField = uif.createOutputField("test.status");
 305         statusField.setEnabled(false);
 306 
 307         setLayout(new BorderLayout());
 308         add(tabs, BorderLayout.CENTER);
 309         add(statusField, BorderLayout.SOUTH);
 310 
 311         // --- anonymous class ---
 312         ComponentListener cl = new ComponentListener() {
 313             public void componentResized(ComponentEvent e) {
 314             }
 315 
 316             public void componentMoved(ComponentEvent e) {
 317             }
 318             public void componentShown(ComponentEvent e) {
 319                 if (needToUpdateGUIWhenShown) {
 320                     updateGUI();
 321                     needToUpdateGUIWhenShown = false;
 322                 }
 323                 //System.err.println("TP: showing");
 324                 harness.addObserver(observer);
 325             }
 326             public void componentHidden(ComponentEvent e) {
 327                 //System.err.println("TP: hidden");
 328                 harness.removeObserver(observer);
 329             }
 330         };
 331         addComponentListener(cl);
 332     }
 333 
 334     class ViewerStateListener implements  PropertyChangeListener{
 335         ViewerStateListener(CustomTestResultViewer[] cv, int pos, int offset) {
 336             this.cv = cv;
 337             this.pos = pos;
 338             this.offset = offset;
 339         }
 340         private CustomTestResultViewer[] cv;
 341         private int pos, offset;
 342 
 343         public void propertyChange(PropertyChangeEvent evt) {
 344             Boolean state = (Boolean) evt.getNewValue();
 345             if (state.booleanValue()) {
 346                 int j = offset;
 347                 for (int i = 0; i < pos; i++) {
 348                     if (tabs.indexOfComponent(cv[i]) >=0){
 349                         j++;
 350                     }
 351                 }
 352                 tabs.insertTab(cv[pos].getDescription(), null, cv[pos], cv[pos].getDescription(), j);
 353             } else {
 354                 tabs.remove(cv[pos]);
 355             }
 356         }
 357     }
 358 
 359     static final String lineSeparator = System.getProperty("line.separator");
 360 
 361     // basic GUI objects
 362     private UIFactory uif;
 363     private TP_Subpanel[] panels;
 364     private TP_Subpanel[] stdPanels;
 365     private JTabbedPane tabs;
 366     private TP_DescSubpanel descPanel;
 367     private TP_DocumentationSubpanel docPanel;
 368     private TP_FilesSubpanel filesPanel;
 369     private TP_ResultsSubpanel resultPanel;
 370     private TP_EnvSubpanel envPanel;
 371     private TP_OutputSubpanel outputPanel;
 372     private JTextField statusField;
 373     private HashMap<CustomTestResultViewer, TP_Subpanel> customViewTable;
 374 
 375     //
 376     private Harness harness;
 377 
 378     //
 379     private ContextManager contextManager;
 380 
 381     // set these values via update
 382     private TestResult currTest;
 383     private TP_Subpanel currPanel;
 384 
 385     // these values are derived from values given to update
 386     private TestDescription currDesc;
 387 
 388     // used to minimize update load
 389     private boolean needToUpdateGUIWhenShown = true;
 390     private boolean updatePending = false;
 391 
 392     // will be needed for dynamic update
 393     private final Observer observer = new Observer();
 394 
 395     private class Observer implements Harness.Observer, TestResult.Observer {
 396             // ---------- Harness.Observer ----------
 397         public void startingTestRun(Parameters params) {
 398         }
 399 
 400         public void startingTest(TestResult tr) {
 401         //System.err.println("TP$Observer.starting: " + tr);
 402             try {
 403                 if (tr.getDescription() == currDesc) {
 404                     //System.out.println("RunnerObserver.UPDATING CURRENT TEST");
 405                     // this will update currTest to tr if needed
 406                     updatePanel(tr, currPanel);
 407                     updateCustomPanels(tr, currPanel);
 408                 }
 409             }
 410                 catch (TestResult.Fault e) {
 411             }
 412         }
 413 
 414         public void finishedTest(TestResult tr) {
 415             //System.err.println("TP$Observer.finished: " + tr);
 416             if (tr == currTest) {
 417                 updatePanel(tr, currPanel);
 418                 updateCustomPanels(tr, currPanel);
 419             }
 420         }
 421 
 422         public void stoppingTestRun() {
 423         }
 424 
 425         public void finishedTesting() {
 426         }
 427 
 428         public void finishedTestRun(boolean allOK) {
 429         }
 430 
 431         public void error(String msg) {
 432         }
 433 
 434         // ----- TestResult.Observer interface -----
 435         public void completed(TestResult tr) {
 436             tr.removeObserver(this);
 437             updateStatus();
 438         }
 439 
 440         public void createdSection(TestResult tr, TestResult.Section section) { }
 441 
 442         public void completedSection(TestResult tr, TestResult.Section section) { }
 443 
 444         public void createdOutput(TestResult tr, TestResult.Section section,
 445                       String outputName) { }
 446 
 447         public void completedOutput(TestResult tr, TestResult.Section section,
 448                         String outputName) { }
 449 
 450         public void updatedOutput(TestResult tr, TestResult.Section section,
 451                       String outputName,
 452                       int start, int end, String text) { }
 453 
 454         public void updatedProperty(TestResult tr, String name, String value) { }
 455     }
 456 
 457 }