1 /*
   2  * $Id$
   3  *
   4  * Copyright (c) 2001, 2013, 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.Dimension;
  33 import java.awt.EventQueue;
  34 import java.io.IOException;
  35 import java.io.StringWriter;
  36 import javax.swing.BorderFactory;
  37 import javax.swing.DefaultListCellRenderer;
  38 import javax.swing.DefaultListModel;
  39 import javax.swing.Icon;
  40 import javax.swing.ListSelectionModel;
  41 import javax.swing.JEditorPane;
  42 import javax.swing.JLabel;
  43 import javax.swing.JList;
  44 import javax.swing.JPanel;
  45 import javax.swing.JScrollPane;
  46 import javax.swing.JSplitPane;
  47 import javax.swing.JTextArea;
  48 import javax.swing.JTextField;
  49 import javax.swing.event.HyperlinkEvent;
  50 import javax.swing.event.HyperlinkListener;
  51 import javax.swing.event.ListSelectionEvent;
  52 import javax.swing.event.ListSelectionListener;
  53 import javax.swing.text.html.HTMLDocument;
  54 import javax.swing.text.html.HTMLEditorKit;
  55 import javax.swing.text.html.StyleSheet;
  56 
  57 import com.sun.javatest.JavaTestError;
  58 import com.sun.javatest.Status;
  59 import com.sun.javatest.TestResult;
  60 import com.sun.javatest.tool.IconFactory;
  61 import com.sun.javatest.tool.Preferences;
  62 import com.sun.javatest.tool.UIFactory;
  63 import com.sun.javatest.report.HTMLWriterEx;
  64 import com.sun.javatest.util.StringArray;
  65 import com.sun.javatest.tool.jthelp.ContextHelpManager;
  66 
  67 /**
  68  * Show the output sections for a particular test result.
  69  * This panel will dynamically update data if the test is running.
  70  */
  71 
  72 class TP_OutputSubpanel extends TP_Subpanel {
  73 
  74     String currentTOCEntry = null;
  75 
  76     TP_OutputSubpanel(UIFactory uif) {
  77         super(uif, "out");
  78         initGUI();
  79     }
  80 
  81     protected synchronized void updateSubpanel(TestResult newTest) {
  82         if (subpanelTest != null)
  83             subpanelTest.removeObserver(observer);
  84 
  85         super.updateSubpanel(newTest);
  86         updateTOC();
  87 
  88         // if it is mutable, track updates
  89         if (subpanelTest.isMutable())  {
  90             subpanelTest.addObserver(observer);
  91         }
  92     }
  93 
  94     private void initGUI() {
  95         setLayout(new BorderLayout());
  96 
  97         tocEntries = new DefaultListModel<>();
  98         toc = uif.createList("test.out.toc", tocEntries);
  99         toc.setCellRenderer(new TOCRenderer());
 100         toc.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
 101         toc.setPrototypeCellValue("12345678901234567890");
 102         toc.setVisibleRowCount(10);
 103         toc.addListSelectionListener(listener);
 104 
 105         JScrollPane scrollableTOC =
 106             uif.createScrollPane(toc,
 107                             JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
 108                             JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);
 109 
 110         main = new JPanel(new BorderLayout());
 111         titleField = uif.createOutputField("test.out.title");
 112         titleField.setBackground(UIFactory.Colors.PRIMARY_CONTROL_DARK_SHADOW.getValue());
 113         titleField.setForeground(UIFactory.Colors.WINDOW_BACKGROUND.getValue());
 114         main.add(titleField, BorderLayout.NORTH);
 115 
 116         body = new JPanel(new CardLayout()) {
 117             public Dimension getPreferredSize() {
 118                 int dpi = uif.getDotsPerInch();
 119                 return new Dimension(3 * dpi, 3 * dpi);
 120             }
 121         };
 122 
 123 
 124         textArea = uif.createTextArea("test.out.textbody");
 125         textArea.setEditable(false);
 126         textArea.setLineWrap(wrap);
 127         textArea.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 128         body.add(uif.createScrollPane(textArea,
 129                                  JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
 130                                  JScrollPane.HORIZONTAL_SCROLLBAR_AS_NEEDED),
 131                  "text");
 132 
 133         htmlArea = new JEditorPane();
 134         htmlArea.setName("out_summ");
 135         htmlArea.getAccessibleContext().setAccessibleName(uif.getI18NString("test.out.summ.name"));
 136         htmlArea.getAccessibleContext().setAccessibleDescription(uif.getI18NString("test.out.summ.name"));
 137         //htmlArea.setContentType("text/html");
 138 
 139         // create and set a vacuous subtype of HTMLDocument, simply in order
 140         // to have the right classloader associated with it, that can load
 141         // any related OBJECT tags
 142         htmlArea.setDocument(new HTMLDocument(getStyleSheet()) { });
 143         htmlArea.setEditable(false);
 144         htmlArea.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
 145         htmlArea.addHyperlinkListener(listener);
 146         body.add(uif.createScrollPane(htmlArea,
 147                                  JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
 148                                  JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
 149                  "html");
 150 
 151         main.add(body, BorderLayout.CENTER);
 152 
 153         JSplitPane sp =
 154             new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, scrollableTOC, main);
 155         sp.setBorder(BorderFactory.createLoweredBevelBorder());
 156         sp.setResizeWeight(0); // all excess space to right hand side
 157         add(sp);
 158 
 159         ContextHelpManager.setHelpIDString(this, "browse.outputTab.csh");
 160         initIcons();
 161     }
 162 
 163     private void initIcons() {
 164         streamIcon = uif.createIcon("test.out.sect.stream");
 165     }
 166 
 167     private String getStatusKey(int i) {
 168         String s;
 169         switch (i) {
 170         case Status.PASSED:  return "passed";
 171         case Status.FAILED:  return "failed";
 172         case Status.ERROR:   return "error";
 173         case Status.NOT_RUN: return "notRun";
 174         default:             return "unknown";
 175         }
 176     }
 177 
 178     private String createNotRunSummary() {
 179         StringWriter sw = new StringWriter();
 180         try {
 181             HTMLWriterEx out = new HTMLWriterEx(sw, uif.getI18NResourceBundle());
 182             out.startTag(HTMLWriterEx.HTML);
 183             out.startTag(HTMLWriterEx.HEAD);
 184             out.writeContentMeta();
 185             out.endTag(HTMLWriterEx.HEAD);
 186             out.startTag(HTMLWriterEx.BODY);
 187             //out.writeStyleAttr(bodyStyle);
 188             out.writeI18N("test.out.smry.testNotRun");
 189             out.endTag(HTMLWriterEx.BODY);
 190             out.endTag(HTMLWriterEx.HTML);
 191             out.close();
 192         }
 193         catch (IOException e) {
 194             // should not happen, with StringWriter
 195         }
 196         return sw.toString();
 197     }
 198 
 199     private String createSummary() {
 200         StringWriter sw = new StringWriter();
 201         try {
 202             HTMLWriterEx out = new HTMLWriterEx(sw, uif.getI18NResourceBundle());
 203             out.startTag(HTMLWriterEx.HTML);
 204             out.startTag(HTMLWriterEx.HEAD);
 205             out.writeContentMeta();
 206             out.endTag(HTMLWriterEx.HEAD);
 207             out.startTag(HTMLWriterEx.BODY);
 208             //out.writeStyleAttr(bodyStyle);
 209 
 210             String[] scriptAndArgs;
 211             try {
 212                 scriptAndArgs = StringArray.split(subpanelTest.getProperty(TestResult.SCRIPT));
 213             }
 214             catch (TestResult.Fault e) {
 215                 scriptAndArgs = null;
 216             }
 217 
 218             String script = (scriptAndArgs == null || scriptAndArgs.length == 0
 219                              ? uif.getI18NString("test.out.smry.unknownScript")
 220                              : scriptAndArgs[0]);
 221             out.writeI18N("test.out.script");
 222             out.startTag(HTMLWriterEx.TABLE);
 223             out.writeAttr(HTMLWriterEx.BORDER, "0");
 224             //out.writeStyleAttr(tableStyle);
 225             out.startTag(HTMLWriterEx.TR);
 226             out.startTag(HTMLWriterEx.TD);
 227             out.startTag(HTMLWriterEx.CODE);
 228             out.write(script);
 229             out.endTag(HTMLWriterEx.CODE);
 230             out.endTag(HTMLWriterEx.TD);
 231             out.endTag(HTMLWriterEx.TR);
 232             out.endTag(HTMLWriterEx.TABLE);
 233             if (scriptAndArgs != null && scriptAndArgs.length > 1) {
 234                 out.writeI18N("test.out.scriptArgs");
 235                 out.startTag(HTMLWriterEx.TABLE);
 236                 out.writeAttr(HTMLWriterEx.BORDER, "0");
 237                 //out.writeStyleAttr(tableStyle);
 238                 for (int i = 1; i < scriptAndArgs.length; i++) {
 239                     out.startTag(HTMLWriterEx.TR);
 240                     out.startTag(HTMLWriterEx.TD);
 241                     out.startTag(HTMLWriterEx.CODE);
 242                     out.write(scriptAndArgs[i]);
 243                     out.endTag(HTMLWriterEx.CODE);
 244                     out.endTag(HTMLWriterEx.TD);
 245                     out.endTag(HTMLWriterEx.TR);
 246                 }
 247                 out.endTag(HTMLWriterEx.TABLE);
 248             }
 249 
 250             if (subpanelTest.getSectionCount() > 0) {
 251                 TestResult.Section s = subpanelTest.getSection(0);
 252                 if (s.getTitle().equals(TestResult.MSG_SECTION_NAME)) {
 253                     out.writeI18N("test.out.smry.scriptLog.txt");
 254                     out.startTag(HTMLWriterEx.TABLE);
 255                     out.writeAttr(HTMLWriterEx.BORDER, "0");
 256                     //out.writeStyleAttr(tableStyle);
 257                     String[] names = s.getOutputNames();
 258                     for (int i = 0; i < names.length; i++) {
 259                         String name = names[i];
 260                         String text = s.getOutput(name);
 261                         out.startTag(HTMLWriterEx.TR);
 262                         out.startTag(HTMLWriterEx.TD);
 263                         out.writeLink("#" + name, name/*, linkStyle*/);
 264                         out.endTag(HTMLWriterEx.TD);
 265                         out.endTag(HTMLWriterEx.TR);
 266                     }
 267                     out.endTag(HTMLWriterEx.TABLE);
 268                 }
 269             }
 270 
 271             // generate a table showing the various sections
 272             if (subpanelTest.getSectionCount() > 0) {
 273                 out.startTag(HTMLWriterEx.H3);
 274                 //out.writeStyleAttr(h3Style);
 275                 out.writeI18N("test.out.smry.sections.head");
 276                 out.endTag(HTMLWriterEx.H3);
 277                 out.writeI18N("test.out.smry.sections.txt");
 278                 out.startTag(HTMLWriterEx.TABLE);
 279                 out.writeAttr(HTMLWriterEx.BORDER, "0");
 280                 //out.writeStyleAttr(tableStyle);
 281                 for (int i = 0; i < subpanelTest.getSectionCount(); i++) {
 282                     TestResult.Section s = subpanelTest.getSection(i);
 283                     if (s.getTitle().equals(TestResult.MSG_SECTION_NAME))
 284                         continue; // already done, above
 285                     out.startTag(HTMLWriterEx.TR);
 286                     out.startTag(HTMLWriterEx.TD);
 287                     out.startTag(HTMLWriterEx.OBJECT);
 288                     out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel");
 289                     out.writeParam("type", "testSection");
 290                     out.writeParam("state", getStatusKey(s.getStatus().getType()));
 291                     out.endTag(HTMLWriterEx.OBJECT);
 292                     out.writeLink(String.valueOf(i), s.getTitle()/*, linkStyle*/);
 293                     out.endTag(HTMLWriterEx.TD);
 294                     out.endTag(HTMLWriterEx.TR);
 295                 }
 296                 out.endTag(HTMLWriterEx.TABLE);
 297 
 298                 out.startTag(HTMLWriterEx.H3);
 299                 //out.writeStyleAttr(h3Style);
 300                 out.writeI18N("test.out.outcome.head");
 301                 out.endTag(HTMLWriterEx.H3);
 302                 out.writeI18N("test.out.testResultForOutput.txt");
 303             }
 304             else {
 305                 out.startTag(HTMLWriterEx.H3);
 306                 //out.writeStyleAttr(h3Style);
 307                 out.writeI18N("test.out.outcome.head");
 308                 out.endTag(HTMLWriterEx.H3);
 309                 out.writeI18N("test.out.testResultNoOutput.txt");
 310             }
 311 
 312             Status s = subpanelTest.getStatus();
 313             out.startTag(HTMLWriterEx.TABLE);
 314             out.writeAttr(HTMLWriterEx.BORDER, "0");
 315             //out.writeStyleAttr(tableStyle);
 316             out.startTag(HTMLWriterEx.TR);
 317             out.startTag(HTMLWriterEx.TD);
 318             out.startTag(HTMLWriterEx.OBJECT);
 319             out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel");
 320             out.writeParam("type", "test");
 321             out.writeParam("state", getStatusKey(s.getType()));
 322             out.endTag(HTMLWriterEx.OBJECT);
 323             out.endTag(HTMLWriterEx.TD);
 324             out.startTag(HTMLWriterEx.TD);
 325             out.write(s.toString());
 326             out.endTag(HTMLWriterEx.TD);
 327             out.endTag(HTMLWriterEx.TR);
 328             out.endTag(HTMLWriterEx.TABLE);
 329 
 330             out.endTag(HTMLWriterEx.BODY);
 331             out.endTag(HTMLWriterEx.HTML);
 332             out.close();
 333         }
 334         catch (IOException e) {
 335             // should not happen, writing to StringWriter
 336         }
 337         catch (TestResult.ReloadFault e) {
 338             throw new JavaTestError("Error loading result file for " +
 339                                     subpanelTest.getTestName());
 340         }
 341 
 342         return sw.toString();
 343     }
 344 
 345     private String createSectionSummary(TestResult.Section section) {
 346         StringWriter sw = new StringWriter();
 347         try {
 348             HTMLWriterEx out = new HTMLWriterEx(sw, uif.getI18NResourceBundle());
 349             out.startTag(HTMLWriterEx.HTML);
 350             out.startTag(HTMLWriterEx.HEAD);
 351             out.writeContentMeta();
 352             out.endTag(HTMLWriterEx.HEAD);
 353             out.startTag(HTMLWriterEx.BODY);
 354             //out.writeStyleAttr(bodyStyle);
 355 
 356             // generate a table showing the size of the various output streams
 357             out.startTag(HTMLWriterEx.H3);
 358             out.writeStyleAttr("margin-top: 0");
 359             out.writeI18N("test.out.outputSummary.head");
 360             out.endTag(HTMLWriterEx.H3);
 361             out.writeI18N("test.out.outputSummary.txt");
 362             out.startTag(HTMLWriterEx.TABLE);
 363             out.writeAttr(HTMLWriterEx.BORDER, "0");
 364             //out.writeStyleAttr(tableStyle);
 365             out.startTag(HTMLWriterEx.TR);
 366             out.startTag(HTMLWriterEx.TH);
 367             out.writeAttr(HTMLWriterEx.STYLE, HTMLWriterEx.TEXT_LEFT);
 368             out.writeI18N("test.out.outputName.txt");
 369             out.endTag(HTMLWriterEx.TH);
 370             out.startTag(HTMLWriterEx.TH);
 371             out.writeAttr(HTMLWriterEx.STYLE, HTMLWriterEx.TEXT_LEFT);
 372             out.writeStyleAttr("margin-left:10");
 373             out.writeI18N("test.out.outputSize.txt");
 374             out.endTag(HTMLWriterEx.TH);
 375             out.endTag(HTMLWriterEx.TR);
 376             String[] names = section.getOutputNames();
 377             for (int i = 0; i < names.length; i++) {
 378                 String name = names[i];
 379                 String text = section.getOutput(name);
 380                 out.startTag(HTMLWriterEx.TR);
 381                 out.startTag(HTMLWriterEx.TD);
 382                 if (text.length() == 0)
 383                     out.write(name);
 384                 else
 385                     out.writeLink("#" + name, name/*, linkStyle*/);
 386                 out.endTag(HTMLWriterEx.TD);
 387                 out.startTag(HTMLWriterEx.TD);
 388                 out.writeStyleAttr("margin-left:10");
 389                 if (text.length() == 0)
 390                     out.writeI18N("test.out.empty.txt");
 391                 else
 392                     out.write(String.valueOf(text.length()));
 393                 out.endTag(HTMLWriterEx.TD);
 394                 out.endTag(HTMLWriterEx.TR);
 395             }
 396             out.endTag(HTMLWriterEx.TABLE);
 397 
 398             // if there is a status, show it
 399             Status s = section.getStatus();
 400             if (s != null) {
 401                 out.startTag(HTMLWriterEx.H3);
 402                 //out.writeStyleAttr(h3Style);
 403                 out.writeI18N("test.out.outcome.head");
 404                 out.endTag(HTMLWriterEx.H3);
 405                 out.writeI18N("test.out.sectionResult.txt");
 406                 out.startTag(HTMLWriterEx.P);
 407                 out.writeStyleAttr("margin-left:30; margin-top:0; font-size: 12pt");
 408                 out.startTag(HTMLWriterEx.OBJECT);
 409                 out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel");
 410                 out.writeParam("type", "testSection");
 411                 out.writeParam("state", getStatusKey(s.getType()));
 412                 out.endTag(HTMLWriterEx.OBJECT);
 413                 out.write(s.toString());
 414                 out.endTag(HTMLWriterEx.P);
 415             }
 416 
 417             out.endTag(HTMLWriterEx.BODY);
 418             out.endTag(HTMLWriterEx.HTML);
 419             out.close();
 420         }
 421         catch (IOException e) {
 422             // should not happen with StringWriter
 423         }
 424         return sw.toString();
 425     }
 426 
 427     private String createStatusSummary() {
 428         StringWriter sw = new StringWriter();
 429         try {
 430             HTMLWriterEx out = new HTMLWriterEx(sw, uif.getI18NResourceBundle());
 431             out.startTag(HTMLWriterEx.HTML);
 432             out.startTag(HTMLWriterEx.HEAD);
 433             out.writeContentMeta();
 434             out.endTag(HTMLWriterEx.HEAD);
 435             out.startTag(HTMLWriterEx.BODY);
 436             //out.writeStyleAttr(bodyStyle);
 437 
 438             if (subpanelTest.getSectionCount() > 0)
 439                 out.writeI18N("test.out.testResultForOutput.txt");
 440             else
 441                 out.writeI18N("test.out.testResultNoOutput.txt");
 442 
 443             Status s = subpanelTest.getStatus();
 444             out.startTag(HTMLWriterEx.TABLE);
 445             out.writeAttr(HTMLWriterEx.BORDER, "0");
 446             //out.writeStyleAttr(tableStyle);
 447             out.startTag(HTMLWriterEx.TR);
 448             out.startTag(HTMLWriterEx.TD);
 449             out.startTag(HTMLWriterEx.OBJECT);
 450             out.writeAttr(HTMLWriterEx.CLASSID, "com.sun.javatest.tool.IconLabel");
 451             out.writeParam("type", "test");
 452             out.writeParam("state", getStatusKey(s.getType()));
 453             out.endTag(HTMLWriterEx.OBJECT);
 454             out.endTag(HTMLWriterEx.TD);
 455             out.startTag(HTMLWriterEx.TD);
 456             out.write(s.toString());
 457             out.endTag(HTMLWriterEx.TD);
 458             out.endTag(HTMLWriterEx.TR);
 459             out.endTag(HTMLWriterEx.TABLE);
 460             out.endTag(HTMLWriterEx.BODY);
 461             out.endTag(HTMLWriterEx.HTML);
 462             out.close();
 463         }
 464         catch (IOException e) {
 465             // should not happen, for StringWriter
 466         }
 467         return sw.toString();
 468     }
 469 
 470     void updateTOC() {
 471         try {
 472             TOCEntry newSelectedEntry = null;
 473             tocEntries.setSize(0);
 474             for (int i = 0; i < subpanelTest.getSectionCount(); i++) {
 475                 TestResult.Section s = subpanelTest.getSection(i);
 476                 TOCEntry e = new TOCEntry(s);
 477                 if (e.isScriptMessagesSection() && (currentTOCEntry == null) ||
 478                     (e.getID().equals(currentTOCEntry)))
 479                     newSelectedEntry = e;
 480                 tocEntries.addElement(e);
 481                 String[] names = s.getOutputNames();
 482                 for (int j = 0; j < names.length; j++) {
 483                     e = new TOCEntry(s, names[j]);
 484                     if (e.getID().equals(currentTOCEntry)) {
 485                         newSelectedEntry = e;
 486                     }
 487                     tocEntries.addElement(e);
 488                 }
 489             }
 490 
 491             TOCEntry e = new TOCEntry(); // for final status
 492             if (newSelectedEntry == null)
 493                 newSelectedEntry = e;
 494             tocEntries.addElement(e);
 495 
 496             currentTOCEntry = newSelectedEntry.getID();
 497             toc.setSelectedValue(newSelectedEntry, true);
 498         }
 499         catch (TestResult.ReloadFault e) {
 500             throw new JavaTestError("Error loading result file for " +
 501                                     subpanelTest.getTestName());
 502         }
 503     }
 504 
 505     private void updateTOCLater() {
 506         if (EventQueue.isDispatchThread())
 507             updateTOC();
 508         else {
 509             EventQueue.invokeLater(new Runnable() {
 510                     public void run() {
 511                         updateTOC(); // will also update current entry
 512                     }
 513                 });
 514         }
 515     }
 516 
 517     /**
 518      * @param tr Result being updated.
 519      * @param section Section being updated.
 520      * @param outputName Output in section being updated, may be null.
 521      * @param start Start index from TestResult API
 522      * @param end End index from TestResult API
 523      * @param text New text.
 524      * @see com.sun.javatest.TestResult
 525      */
 526     private void updateOutput(final TestResult tr, final TestResult.Section section,
 527                               final String outputName,
 528                               final int start, final int end, final String text) {
 529         //System.err.println("TPOS_TRO: written output[" + section.getTitle() + "/" + outputName + "]: " + tr.getWorkRelativePath());
 530         TOCEntry entry = findTOCEntry(section);
 531         // should happen zero or one times per section
 532         // primarily to catch observer messages that were missed before this
 533         // panel attached to the TR.
 534         if (entry == null) {
 535             updateTOC();
 536             return;  // return because it can't possibly be selected by user yet
 537         }
 538 
 539         // are we actually looking at the section being updated?
 540         entry = (TOCEntry) (toc.getSelectedValue());
 541         if (entry.getSection() == section && outputName == entry.getOutputName()) {
 542             addText(section, outputName, text);
 543         }
 544     }
 545 
 546 
 547     private TOCEntry findTOCEntry(TestResult.Section section) {
 548         if (tocEntries == null)
 549             return null;
 550 
 551         for (int i = 0; i < tocEntries.size(); i++) {
 552             TOCEntry entry = tocEntries.get(i);
 553             if (entry.getSection() == section) {
 554                 // found match, select this entry
 555                 return entry;
 556             }
 557         }
 558         return null;
 559     }
 560 
 561     private void showHTML(String s) {
 562         // high cost method call
 563         htmlArea.setContentType("text/html");
 564 
 565         // try resetting doc to an empty doc before setting new text
 566 
 567         // create and set a vacuous subtype of HTMLDocument, simply in order
 568         // to have the right classloader associated with it, that can load
 569         // any related OBJECT tags
 570         HTMLDocument doc = new HTMLDocument(getStyleSheet()) { };
 571         htmlArea.setDocument(doc);
 572         htmlArea.setText(s);
 573 
 574         /*
 575         StyleSheet styles = doc.getStyleSheet();
 576         Enumeration rules = styles.getStyleNames();
 577         while (rules.hasMoreElements()) {
 578             String name = (String) rules.nextElement();
 579             System.out.println(styles.getStyle(name));
 580         }
 581         */
 582 
 583         ((CardLayout)(body.getLayout())).show(body, "html");
 584     }
 585 
 586     private void showText(String s) {
 587         if (s.length() == 0) {
 588             textArea.setText(uif.getI18NString("test.out.empty.txt"));
 589             textArea.setEnabled(false);
 590         }
 591         else {
 592             wrap = Boolean.parseBoolean(prefs.getPreference(LINE_WRAP_PREF, Boolean.toString(true)));
 593             if (wrap) {
 594                 textArea.setLineWrap(true);
 595             } else {
 596                 textArea.setLineWrap(false);
 597             }
 598             textArea.setText(s);
 599             textArea.setCaretPosition(0);
 600             textArea.setEnabled(true);
 601         }
 602 
 603         ((CardLayout)(body.getLayout())).show(body, "text");
 604     }
 605 
 606     private void addText(TestResult.Section section,
 607             String outputName, String s) {
 608         if (s == null || s.length() == 0)
 609             return;
 610 
 611         if (!textArea.isEnabled()) {
 612             textArea.setText("");
 613             textArea.append(s);
 614             textArea.setEnabled(true);
 615         }
 616         else if (outputName != null) {
 617             textArea.append(s);
 618         }
 619     }
 620 
 621     private StyleSheet getStyleSheet() {
 622         if (htmlEditorKit == null)
 623             htmlEditorKit = new HTMLEditorKit();
 624 
 625         if (styleSheet == null) {
 626             styleSheet = new StyleSheet();
 627             styleSheet.addStyleSheet(htmlEditorKit.getStyleSheet());
 628             styleSheet.addRule("body  { font-family: SansSerif; font-size: 12pt }");
 629             styleSheet.addRule("h3    { margin-top:15 }");
 630             styleSheet.addRule("table { margin-left:30; margin-top:0 }");
 631         }
 632         return styleSheet;
 633     }
 634 
 635     private boolean wrap = true;
 636     private Preferences prefs = Preferences.access();
 637     public static final String LINE_WRAP_PREF = "testOutput.lineWrap";
 638     private Icon streamIcon;
 639     private JList toc;
 640     private JTextField titleField;
 641     private JPanel body;
 642     private JPanel main;
 643     private JTextArea textArea;
 644 
 645     private JEditorPane htmlArea;
 646 
 647     private DefaultListModel<TOCEntry> tocEntries;
 648     private Listener listener = new Listener();
 649     private TRObserver observer = new TRObserver();
 650 
 651     private StyleSheet styleSheet;
 652     private HTMLEditorKit htmlEditorKit;
 653 
 654     //------------------------------------------------------------------------------------
 655 
 656     private class Listener implements HyperlinkListener, ListSelectionListener
 657     {
 658         public void hyperlinkUpdate(HyperlinkEvent e) {
 659             if (e.getEventType().equals(HyperlinkEvent.EventType.ACTIVATED)) {
 660                 String desc = e.getDescription();
 661                 if (desc.startsWith("#")) {
 662                     String outputName = desc.substring(1);
 663                     // search for the output entry for the currently selected section
 664                     int index = toc.getSelectedIndex();
 665                     if (index != -1) {
 666                         for (int i = index + 1; i < tocEntries.size(); i++) {
 667                             TOCEntry entry = tocEntries.get(i);
 668                             String entryOutputName = entry.getOutputName();
 669                             if (entryOutputName == null)
 670                                 // name not found, reached next section entry
 671                                 break;
 672                             else if (entryOutputName.equals(outputName)) {
 673                                 // found match, select this entry
 674                                 toc.setSelectedIndex(i);
 675                                 return;
 676                             }
 677                         }
 678                     }
 679                 }
 680                 else {
 681                     try {
 682                         int sectIndex = Integer.parseInt(desc);
 683                         TestResult.Section s = subpanelTest.getSection(sectIndex);
 684                         for (int i = 0; i < tocEntries.size(); i++) {
 685                             TOCEntry entry = tocEntries.get(i);
 686                             if (entry.getSection() == s) {
 687                                 // found match, select this entry
 688                                 toc.setSelectedIndex(i);
 689                                 return;
 690                             }
 691                         }
 692 
 693                     }
 694                     catch (TestResult.ReloadFault f) {
 695                         throw new JavaTestError("Error loading result file for " +
 696                                                 subpanelTest.getTestName());
 697                     }
 698                 }
 699             }
 700         }
 701 
 702         public void valueChanged(ListSelectionEvent e) {
 703             JList l = (JList) (e.getSource());
 704             TOCEntry entry = (TOCEntry) (l.getSelectedValue());
 705             if (entry == null)
 706                 return;
 707             titleField.setText(entry.getTitle());
 708             currentTOCEntry = entry.getID();
 709             String outputName = entry.getOutputName();
 710 
 711             if (entry.section == null) {
 712                 if (subpanelTest.getStatus().getType() == Status.NOT_RUN)
 713                     showHTML(createNotRunSummary());
 714                 else
 715                     showHTML(createStatusSummary());
 716             }
 717             else if (outputName != null)
 718                 showText(entry.getSection().getOutput(outputName));
 719             else if (entry.isScriptMessagesSection())
 720                 showHTML(createSummary());
 721             else
 722                 showHTML(createSectionSummary(entry.getSection()));
 723         }
 724     }
 725 
 726     //------------------------------------------------------------------------------------
 727 
 728     private class TRObserver
 729         implements TestResult.Observer
 730     {
 731         public void completed(TestResult tr) {
 732             //System.err.println("TPOS_TRO: completed: " + tr.getWorkRelativePath());
 733             updateTOCLater();
 734             tr.removeObserver(this);
 735         }
 736 
 737         public void createdSection(TestResult tr, TestResult.Section section) {
 738             //System.err.println("TPOS_TRO: created section[" + section.getTitle() + "]: " + tr.getWorkRelativePath());
 739             updateTOCLater();
 740         }
 741 
 742         public void completedSection(TestResult tr, TestResult.Section section) {
 743             //System.err.println("TPOS_TRO: completed section[" + section.getTitle() + "]: " + tr.getWorkRelativePath());
 744             updateTOCLater();
 745         }
 746 
 747         public void createdOutput(TestResult tr, TestResult.Section section,
 748                                   String outputName) {
 749             //System.err.println("TPOS_TRO: created output[" + section.getTitle() + "/" + outputName + "]: " + tr.getWorkRelativePath());
 750             updateTOCLater();
 751         }
 752 
 753         public void completedOutput(TestResult tr, TestResult.Section section,
 754                                     String outputName) {
 755             //System.err.println("TPOS_TRO: completed output[" + section.getTitle() + "/" + outputName + "]: " + tr.getWorkRelativePath());
 756         }
 757 
 758         public void updatedOutput(final TestResult tr, final TestResult.Section section,
 759                                   final String outputName,
 760                                   final int start, final int end, final String text) {
 761             //System.err.println("TPOS_TRO: written output[" + section.getTitle() + "/" + outputName + "]: " + tr.getWorkRelativePath());
 762             // this msg almost always on different thread - send it to the
 763             // event thread
 764             Runnable t = new Runnable() {
 765                 public void run() {
 766                     updateOutput(tr, section, outputName, start, end, text);
 767                 }
 768             };  // Runnable
 769 
 770             EventQueue.invokeLater(t);
 771         }
 772 
 773         public void updatedProperty(TestResult tr, String name, String value) {
 774             // ignore
 775         }
 776     }
 777 
 778     //------------------------------------------------------------------------------------
 779 
 780     private class TOCEntry {
 781         // create an entry that will show the test result status
 782         TOCEntry() {
 783             section = null;
 784             outputName = null;
 785         }
 786 
 787         // create an entry for a section summary
 788         TOCEntry(TestResult.Section s) {
 789             section = s;
 790             outputName = null;
 791         }
 792 
 793         // create an entry for a block of section output
 794         TOCEntry(TestResult.Section s, String n) {
 795             section = s;
 796             outputName = n;
 797         }
 798 
 799         boolean isScriptMessagesSection() {
 800             return (section != null && section.getTitle().equals(TestResult.MSG_SECTION_NAME));
 801         }
 802 
 803         TestResult.Section getSection() {
 804             return section;
 805         }
 806 
 807         String getOutputName() {
 808             return outputName;
 809         }
 810 
 811         String getTitle() {
 812             if (section == null) {
 813                 if (subpanelTest.getStatus().getType() == Status.NOT_RUN)
 814                     return uif.getI18NString("test.out.notRunTitle");
 815                 else
 816                     return uif.getI18NString("test.out.statusTitle");
 817             }
 818             else if (isScriptMessagesSection()) {
 819                 if (outputName == null)
 820                     return uif.getI18NString("test.out.summary");
 821                 else
 822                     return uif.getI18NString("test.out.scriptMessages");
 823             }
 824             else {
 825                 if (outputName == null)
 826                     return uif.getI18NString("test.out.sectionTitle", section.getTitle());
 827                 else
 828                     return uif.getI18NString("test.out.streamTitle",
 829                                              new Object[] { section.getTitle(), outputName });
 830             }
 831         }
 832 
 833         String getText() {
 834             if (section == null){
 835                 if (subpanelTest.getStatus().getType() == Status.NOT_RUN)
 836                     return uif.getI18NString("test.out.notRunTitle");
 837                 else
 838                     return uif.getI18NString("test.out.statusTitle");
 839             }
 840             else if (isScriptMessagesSection()) {
 841                 if (outputName == null)
 842                     return uif.getI18NString("test.out.summary");
 843                 else
 844                     return uif.getI18NString("test.out.scriptMessages");
 845             }
 846             else {
 847                 if (outputName == null)
 848                     return section.getTitle();
 849                 else
 850                     return outputName;
 851             }
 852         }
 853 
 854         Icon getIcon() {
 855             if (section == null)
 856                 return IconFactory.getTestIcon(subpanelTest.getStatus().getType(), false, true);
 857             else if (outputName != null)
 858                 return streamIcon;
 859             else {
 860                 Status s = section.getStatus();
 861                 //return (s == null ? null : sectIcons[s.getType()]);
 862                 return (s == null ? null : IconFactory.getTestSectionIcon(s.getType()));
 863             }
 864         }
 865 
 866         String getID() {
 867             String s = "";
 868             if (section != null ) {
 869                 s = section.getTitle() + ":" +
 870                         (outputName == null ? "" : outputName);
 871             }
 872             return s;
 873         }
 874 
 875         private TestResult.Section section;
 876         private String outputName;  // null for section entry
 877     }
 878 
 879     private class TOCRenderer extends DefaultListCellRenderer {
 880         public Component getListCellRendererComponent(JList list,
 881                                                       Object value,
 882                                                       int index,
 883                                                       boolean isSelected,
 884                                                       boolean cellHasFocus) {
 885             JLabel l = (JLabel) super.getListCellRendererComponent(list, null, index,
 886                                                                    isSelected, cellHasFocus);
 887             if (value instanceof TOCEntry) {
 888                 TOCEntry e = (TOCEntry) value;
 889                 l.setText(e.getText());
 890                 l.setIcon(e.getIcon());
 891             }
 892             else
 893                 l.setText(value.toString());
 894             return l;
 895         }
 896     }
 897 
 898 
 899 }