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 }