1 /* 2 * $Id$ 3 * 4 * Copyright (c) 2001, 2011, 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.Component; 30 import java.awt.CardLayout; 31 import java.awt.Color; 32 import java.awt.EventQueue; 33 import java.awt.GridBagConstraints; 34 import java.awt.GridBagLayout; 35 import java.awt.event.ActionEvent; 36 import java.awt.event.ActionListener; 37 import java.awt.event.MouseAdapter; 38 import java.awt.event.MouseEvent; 39 import java.lang.reflect.InvocationTargetException; 40 41 import javax.swing.BorderFactory; 42 import javax.swing.Box; 43 import javax.swing.DefaultListModel; 44 import javax.swing.JButton; 45 import javax.swing.JComponent; 46 import javax.swing.JLabel; 47 import javax.swing.JList; 48 import javax.swing.JPanel; 49 import javax.swing.JScrollPane; 50 import javax.swing.JTextField; 51 import javax.swing.Timer; 52 import javax.swing.border.Border; 53 54 import com.sun.javatest.Status; 55 import com.sun.javatest.TestResult; 56 import com.sun.javatest.tool.I18NUtils; 57 import com.sun.javatest.tool.ToolDialog; 58 import com.sun.javatest.tool.UIFactory; 59 60 class ProgressMonitor extends ToolDialog { 61 62 ProgressMonitor(Component parent, UIFactory uif, MonitorState state) { 63 super(parent, uif, "pm", FRAME); 64 65 /*ToolDialog 66 super(parent, uif.getI18NString("pm.title"), false); 67 */ 68 69 // ToolDialog this.uif = uif; 70 this.state = state; 71 } 72 73 protected void initGUI() { 74 setI18NTitle("pm.title"); 75 setHelp("browse.testMonitor.csh"); 76 77 subpanels = new StatusSubpanel[4]; 78 79 /*ToolDialog 80 Container content = getContentPane(); 81 content.setName("progressD"); 82 content.setLayout(new BorderLayout()); 83 */ 84 85 JPanel body = new JPanel(new GridBagLayout()); 86 GridBagConstraints c = new GridBagConstraints(); 87 c.fill = GridBagConstraints.BOTH; 88 89 // TOP 90 c.gridwidth = 2; 91 c.gridx = 0; 92 c.gridy = 0; 93 c.insets.left = 8; 94 c.insets.right = 8; 95 c.insets.top = 5; 96 c.weightx = 1; 97 c.weighty = 0; 98 progressSubpanel = new ProgressSubpanel(); 99 subpanels[0] = progressSubpanel; 100 body.add(progressSubpanel, c); 101 102 // LEFT SIDE 103 c.gridheight = 1; 104 c.gridwidth = 1; 105 c.gridx = 0; 106 c.gridy = 1; 107 c.insets.right = 0; 108 c.weightx = 1; 109 c.weighty = 2; 110 111 timeSubpanel = new TimeSubpanel(); 112 subpanels[1] = timeSubpanel; 113 body.add(timeSubpanel, c); 114 115 c.gridy = 2; 116 memorySubpanel = new MemorySubpanel(); 117 subpanels[2] = memorySubpanel; 118 body.add(memorySubpanel, c); 119 120 // RIGHT SIDE 121 // list of tests running 122 c.fill = GridBagConstraints.BOTH; 123 c.gridheight = 2; 124 c.gridwidth = 1; 125 c.gridx = 1; 126 c.gridy = 1; 127 c.insets.right = 8; 128 c.weightx = 3; 129 c.weighty = 1; 130 activitySubpanel = new ActivitySubpanel(); 131 subpanels[3] = activitySubpanel; 132 body.add(activitySubpanel, c); 133 134 setBody(body); 135 /*ToolDialog 136 content.add(body, BorderLayout.CENTER); 137 */ 138 139 /*ToolDialog 140 JPanel btnPanel = new JPanel(new GridBagLayout()); 141 GridBagConstraints bc = new GridBagConstraints(); 142 bc.anchor = GridBagConstraints.EAST; 143 bc.insets.top = 5; 144 bc.insets.bottom = 11; // value from JL&F Guidelines 145 bc.insets.right = 5; // value from JL&F Guidelines 146 bc.weightx = 1; 147 148 JButton helpBtn = uif.createHelpButton("pm.help", "browse.testMonitor.csh"); 149 btnPanel.add(helpBtn, bc); 150 151 JButton closeBtn = uif.createCloseButton("pm.close"); 152 bc.insets.right = 11; // value from JL&F Guidelines 153 bc.weightx = 0; 154 btnPanel.add(closeBtn, bc); 155 156 content.add(btnPanel, BorderLayout.SOUTH); 157 */ 158 JButton helpBtn = uif.createHelpButton("pm.help", "browse.testMonitor.csh"); 159 JButton closeBtn = uif.createCloseButton("pm.close"); 160 setButtons(new JButton[] { helpBtn, closeBtn }, closeBtn); 161 162 // other stuff 163 state.addObserver(listener); 164 165 if (state.isRunning()) 166 listener.starting(); 167 168 /*ToolDialog 169 HelpBroker b = uif.getHelpBroker(); 170 //Desktop.addHelpDebugListener(progDialog); 171 b.enableHelpKey(getRootPane(), "browse.testMonitor.csh", null); 172 */ 173 174 //ToolDialog pack(); 175 176 for (int i = 0; i < subpanels.length; i++) { 177 // make sure the panels are in any initial state 178 // important for getting the "last" run info, less important if 179 // there's a run in progress or a future runs 180 subpanels[i].update(); 181 } 182 183 /*ToolDialog 184 getAccessibleContext().setAccessibleDescription( 185 uif.getI18NString("pm.desc")); 186 */ 187 } 188 189 void setTreePanelModel(TreePanelModel tpm) { 190 this.tpm = tpm; 191 } 192 193 //----------member variables----------------------------------------------------- 194 195 private MonitorState state; 196 private TreePanelModel tpm; 197 198 private ProgressSubpanel progressSubpanel; 199 private ActivitySubpanel activitySubpanel; 200 private TimeSubpanel timeSubpanel; 201 private MemorySubpanel memorySubpanel; 202 203 private StatusSubpanel[] subpanels; 204 205 private volatile boolean running; 206 private Listener listener = new Listener(); 207 208 private static final int UPDATE_FREQUENCY = 1000; 209 private static int componentCount; // for generating names 210 211 212 //----------nested classes------------------------------------------------------- 213 214 class Listener implements MonitorState.Observer, ActionListener { 215 Listener() { 216 timer = new Timer(UPDATE_FREQUENCY, this); 217 } 218 219 public void actionPerformed(ActionEvent e) { 220 if (e.getSource() == timer) { 221 for (int i = 0; i < subpanels.length; i++) 222 subpanels[i].update(); 223 } 224 } 225 226 // these are probably on whichever thread the harness is running on 227 // be sure to switch them onto the event thread 228 public void starting() { 229 running = true; 230 231 for (int i = 0; i < subpanels.length; i++) 232 subpanels[i].starting(); 233 234 timer.start(); 235 } 236 237 public void postProcessing() { 238 for (int i = 0; i < subpanels.length; i++) { 239 // make sure the panels update one last time 240 subpanels[i].update(); 241 subpanels[i].postProcessing(); 242 } // for 243 } 244 245 public void stopping() { 246 // it is assumed that finished() will be called right away 247 } 248 249 public void finished(final boolean allOk) { 250 running = false; 251 for (int i = 0; i < subpanels.length; i++) { 252 // make sure the panels update one last time 253 subpanels[i].update(); 254 subpanels[i].stopping(); 255 } // for 256 257 timer.stop(); 258 } 259 260 private Timer timer; 261 } 262 263 private abstract class StatusSubpanel extends JPanel { 264 /** 265 * Refresh any data in this subpanel. 266 * This method is always called on the event dispatch thread. 267 */ 268 abstract void update(); 269 270 /** 271 * Test run is starting. This method can be ignored if it does not apply. 272 */ 273 void starting() { 274 } 275 276 void postProcessing() { 277 } 278 279 /** 280 * Test run is finishing. This method can be ignored if it does not apply. 281 */ 282 void stopping() { 283 } 284 } 285 286 private class ProgressSubpanel extends StatusSubpanel 287 { 288 ProgressSubpanel() { 289 setBorder(uif.createTitledBorder("pm.prog")); 290 setLayout(new GridBagLayout()); 291 292 // Line label 293 GridBagConstraints lnc = new GridBagConstraints(); 294 lnc.gridx = 0; 295 lnc.anchor = GridBagConstraints.EAST; 296 lnc.insets.right = 10; 297 298 // Field label 299 GridBagConstraints lc = new GridBagConstraints(); 300 lc.insets.right = 5; 301 302 // Field 303 GridBagConstraints fc = new GridBagConstraints(); 304 fc.weightx = 1; 305 fc.fill = GridBagConstraints.HORIZONTAL; 306 fc.insets.right = 15; 307 308 // Remaining field 309 GridBagConstraints rc = new GridBagConstraints(); 310 rc.weightx = 1; 311 rc.fill = GridBagConstraints.BOTH; 312 rc.gridwidth = GridBagConstraints.REMAINDER; 313 314 JTextField tf = uif.createHeading("pm.tests"); 315 tf.setBackground(UIFactory.Colors.TRANSPARENT.getValue()); 316 uif.setAccessibleInfo(tf, "pm.tests"); 317 add(tf, lnc); 318 JLabel lab = uif.createLabel("pm.tests.pass"); 319 add(lab, lc); 320 passTf = uif.createOutputField("pm.tests.pass", 6); 321 passTf.setHorizontalAlignment(JTextField.RIGHT); 322 lab.setLabelFor(passTf); 323 lab.setDisplayedMnemonic(uif.getI18NString("pm.tests.pass.mne").charAt(0)); 324 add(passTf, fc); 325 326 lab = uif.createLabel("pm.tests.fail"); 327 lab.setDisplayedMnemonic(uif.getI18NString("pm.tests.fail.mne").charAt(0)); 328 add(lab, lc); 329 failTf = uif.createOutputField("pm.tests.fail", 6); 330 failTf.setHorizontalAlignment(JTextField.RIGHT); 331 lab.setLabelFor(failTf); 332 add(failTf, fc); 333 334 lab = uif.createLabel("pm.tests.err"); 335 add(lab, lc); 336 errorTf = uif.createOutputField("pm.tests.err", 6); 337 lab.setDisplayedMnemonic(uif.getI18NString("pm.tests.err.mne").charAt(0)); 338 errorTf.setHorizontalAlignment(JTextField.RIGHT); 339 lab.setLabelFor(errorTf); 340 add(errorTf, fc); 341 342 lab = uif.createLabel("pm.tests.nr"); 343 lab.setDisplayedMnemonic(uif.getI18NString("pm.tests.nr.mne").charAt(0)); 344 add(lab, lc); 345 notRunTf = uif.createOutputField("pm.tests.nr", 6); 346 notRunTf.setHorizontalAlignment(JTextField.RIGHT); 347 lab.setLabelFor(notRunTf); 348 add(notRunTf, rc); 349 add(Box.createVerticalStrut(10), rc); 350 351 Color[] colors = new Color[Status.NUM_STATES]; 352 colors[Status.PASSED] = I18NUtils.getStatusBarColor(Status.PASSED); 353 colors[Status.FAILED] = I18NUtils.getStatusBarColor(Status.FAILED); 354 colors[Status.ERROR] = I18NUtils.getStatusBarColor(Status.ERROR); 355 colors[Status.NOT_RUN] = I18NUtils.getStatusBarColor(Status.NOT_RUN); 356 357 /* 358 String[] actions = new String[5 + 1]; 359 actions[Status.PASSED] = Integer.toString(Status.PASSED); 360 actions[Status.FAILED] = Integer.toString(Status.FAILED); 361 actions[Status.ERROR] = Integer.toString(Status.ERROR); 362 actions[Status.NOT_RUN] = Integer.toString(Status.NOT_RUN); 363 actions[actions.length - 1] = "-1"; 364 */ 365 366 tf = uif.createHeading("pm.tests.mtr"); 367 uif.setAccessibleInfo(tf, "pm.tests.mtr"); 368 add(tf, lnc); 369 add(meter = new ProgressMeter(colors, state), rc); 370 uif.setAccessibleInfo(meter, "pm.tests.bar"); 371 /* 372 meter.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 373 374 ActionListener al = new ActionListener() { 375 public void actionPerformed(ActionEvent e) { 376 model.showSummary(Integer.parseInt(e.getActionCommand())); 377 } 378 }; 379 380 meter.addActionListener(al); 381 */ 382 uif.setToolTip(this, "pm.tests"); 383 } 384 385 public void update() { 386 updateAll(); 387 } 388 389 //-------------------------------------------------------------------------------- 390 391 private void updateAll() { 392 meter.update(); 393 394 int[] stats = state.getStats(); 395 396 setCount(passTf, stats[Status.PASSED]); 397 setCount(failTf, stats[Status.FAILED]); 398 setCount(errorTf, stats[Status.ERROR]); 399 setCount(notRunTf,state.getTestsRemainingCount()); 400 } 401 402 private final void setCount(JTextField tf, int value) { 403 if (EventQueue.isDispatchThread()) 404 tf.setText(Integer.toString(value)); 405 else 406 try { 407 EventQueue.invokeAndWait(new BranchPanel.TextUpdater(tf, 408 Integer.toString(value), uif)); 409 } 410 catch (InterruptedException e) { 411 } 412 catch (InvocationTargetException e) { 413 } 414 } 415 416 private JTextField passTf; 417 private JTextField failTf; 418 private JTextField errorTf; 419 private JTextField notRunTf; 420 421 private ProgressMeter meter; 422 private int[] meterStats; 423 } 424 425 private class ActivitySubpanel extends StatusSubpanel { 426 ActivitySubpanel() { 427 setBorder(uif.createTitledBorder("pm.activity")); 428 setLayout(new CardLayout()); 429 430 idleCard = createSimpleCard("pm.idle"); 431 addCard(idleCard); 432 initRunningCard(); 433 showCard(idleCard); 434 } 435 436 void starting() { 437 showCard(runningCard); 438 //StatusDialog.this.validate(); 439 } 440 441 void postProcessing() { 442 showCard(idleCard); 443 } 444 445 void stopping() { 446 } 447 448 void update() { 449 testListData.removeAllElements(); 450 TestResult[] rt = state.getRunningTests(); 451 for (int i = 0; i < rt.length; i++) 452 testListData.addElement(rt[i]); 453 } 454 455 //------------------------------------------------------------------ 456 457 private JComponent createSimpleCard(String uiKey) { 458 JPanel card = new JPanel(); 459 card.setLayout(new GridBagLayout()); 460 GridBagConstraints c = new GridBagConstraints(); 461 c.anchor = GridBagConstraints.CENTER; 462 c.gridwidth = GridBagConstraints.REMAINDER; 463 c.weightx = 1; 464 c.weighty = 1; 465 JTextField tf = uif.createHeading(uiKey); 466 uif.setAccessibleInfo(tf, uiKey); 467 card.add(tf, c); 468 469 JLabel icon = uif.createIconLabel(uiKey); 470 c.anchor = GridBagConstraints.WEST; 471 c.weighty = 0; 472 card.add(icon, c); 473 474 return card; 475 } 476 477 private void initRunningCard() { 478 testListData = new DefaultListModel<>(); 479 final JList list = uif.createList("pm.runlist", testListData); 480 list.setBorder(BorderFactory.createEtchedBorder()); 481 list.setCellRenderer(RenderingUtilities.createTestListRenderer()); 482 list.addMouseListener(new MouseAdapter() { 483 public void mouseClicked(MouseEvent e) { 484 int index = list.locationToIndex(e.getPoint()); 485 if (index < 0) 486 return; 487 Object target = list.getModel().getElementAt(index); 488 if (target instanceof TestResult && tpm != null) { 489 tpm.showTest(((TestResult)target).getTestName()); 490 } 491 } 492 } 493 ); 494 runningCard = 495 uif.createScrollPane(list, JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, 496 JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED); 497 addCard(runningCard); 498 } 499 500 private void addCard(JComponent comp) { 501 String s = comp.getName(); 502 if (s == null) 503 comp.setName("StatusDialog.component" + componentCount++); 504 add(comp, comp.getName()); 505 } 506 507 private void showCard(JComponent comp) { 508 //setVisible(false); 509 ((CardLayout)(getLayout())).show(this, comp.getName()); 510 //setVisible(true); 511 } 512 513 private JComponent idleCard; 514 private JComponent runningCard; 515 516 private JTextField fileField; 517 private DefaultListModel<TestResult> testListData; 518 private JList testList; 519 private String rootDir; 520 } 521 522 private class TimeSubpanel extends StatusSubpanel { 523 TimeSubpanel() { 524 setLayout(new GridBagLayout()); 525 Border b1 = uif.createTitledBorder("pm.time"); 526 Border b2 = BorderFactory.createEmptyBorder(10, 5, 10, 5); 527 setBorder(BorderFactory.createCompoundBorder(b1, b2)); 528 529 // Line label 530 GridBagConstraints lnc = new GridBagConstraints(); 531 lnc.gridx = 0; 532 lnc.anchor = GridBagConstraints.EAST; 533 lnc.insets.right = 10; 534 535 // Remaining field 536 GridBagConstraints rc = new GridBagConstraints(); 537 rc.fill = GridBagConstraints.BOTH; 538 rc.gridwidth = GridBagConstraints.REMAINDER; 539 rc.weightx = 1; 540 541 JLabel lab = uif.createLabel("pm.time.sofar"); 542 lab.setDisplayedMnemonic(uif.getI18NString("pm.time.sofar.mne").charAt(0)); 543 add(lab, lnc); 544 add(elapsedField = uif.createOutputField("pm.time.sofar", 8), rc); 545 elapsedField.setText("00:00:00"); 546 lab.setLabelFor(elapsedField); 547 548 lab = uif.createLabel("pm.time.remain"); 549 lab.setDisplayedMnemonic(uif.getI18NString("pm.time.remain.mne").charAt(0)); 550 add(lab, lnc); 551 add(estimatedRemainingField = uif.createOutputField("pm.time.remain", 8), rc); 552 estimatedRemainingField.setText("00:00:00"); 553 lab.setLabelFor(estimatedRemainingField); 554 555 // workaround unknown GridBagLayout problem 556 add(Box.createVerticalStrut(10), rc); 557 558 uif.setToolTip(this, "pm.time"); 559 } 560 561 void update() { 562 long elapsed = state.getElapsedTime(); 563 elapsedField.setText(ElapsedTimeMonitor.millisToString(elapsed)); 564 565 long remain = state.getEstimatedTime(); 566 estimatedRemainingField.setText(ElapsedTimeMonitor.millisToString(remain)); 567 } 568 569 private JTextField elapsedField; 570 private JTextField estimatedRemainingField; 571 //private ProgressMeter meter; 572 private int[] meterStats = new int[2]; 573 } 574 575 private class MemorySubpanel extends StatusSubpanel { 576 MemorySubpanel() { 577 setLayout(new GridBagLayout()); 578 Border b1 = uif.createTitledBorder("pm.memory"); 579 Border b2 = BorderFactory.createEmptyBorder(10, 5, 10, 5); 580 setBorder(BorderFactory.createCompoundBorder(b1, b2)); 581 582 // Line label 583 GridBagConstraints lnc = new GridBagConstraints(); 584 lnc.gridx = 0; 585 lnc.anchor = GridBagConstraints.EAST; 586 lnc.insets.right = 10; 587 lnc.weightx = 0; 588 lnc.fill = GridBagConstraints.NONE; 589 590 // Remaining field 591 GridBagConstraints rc = new GridBagConstraints(); 592 rc.fill = GridBagConstraints.BOTH; 593 rc.gridwidth = GridBagConstraints.REMAINDER; 594 rc.weightx = 1; 595 596 JLabel lab = uif.createLabel("pm.memory.used"); 597 lab.setDisplayedMnemonic(uif.getI18NString("pm.memory.used.mne").charAt(0)); 598 add(lab, lnc); 599 add(usedField = uif.createOutputField("pm.memory.used", 10), rc); 600 lab.setLabelFor(usedField); 601 602 lab = uif.createLabel("pm.memory.ttl"); 603 lab.setDisplayedMnemonic(uif.getI18NString("pm.memory.ttl.mne").charAt(0)); 604 add(lab, lnc); 605 add(totalField = uif.createOutputField("pm.memory.ttl", 10), rc); 606 lab.setLabelFor(totalField); 607 608 // workaround unknown GridBagLayout problem 609 add(Box.createVerticalStrut(10), rc); 610 611 /* 612 rc.fill = GridBagConstraints.VERTICAL; 613 Color[] mc = { 614 new Color(128, 0, 0), 615 new Color(0, 128, 0) 616 }; 617 add(meter = new ProgressMeter(mc, state), rc); 618 */ 619 uif.setToolTip(this, "pm.memory"); 620 } 621 622 void update() { 623 int freeMem = (int)(runtime.freeMemory() / 1024); 624 int totalMem = (int)(runtime.totalMemory() / 1024); 625 int usedMem = totalMem - freeMem; 626 usedField.setText(usedMem + "K"); 627 totalField.setText(totalMem + "K"); 628 629 } 630 631 private JTextField usedField; 632 private JTextField totalField; 633 private ProgressMeter meter; 634 private int[] meterStats = new int[2]; 635 private Runtime runtime = Runtime.getRuntime(); 636 } 637 }