KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > vladium > emma > report > html > ReportGenerator


1 /* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2  *
3  * This program and the accompanying materials are made available under
4  * the terms of the Common Public License v1.0 which accompanies this distribution,
5  * and is available at http://www.eclipse.org/legal/cpl-v10.html
6  *
7  * $Id: ReportGenerator.java,v 1.2.2.1 2004/07/16 23:32:04 vlad_r Exp $
8  */

9 package com.vladium.emma.report.html;
10
11 import java.io.BufferedReader JavaDoc;
12 import java.io.BufferedWriter JavaDoc;
13 import java.io.File JavaDoc;
14 import java.io.FileOutputStream JavaDoc;
15 import java.io.FileReader JavaDoc;
16 import java.io.IOException JavaDoc;
17 import java.io.OutputStreamWriter JavaDoc;
18 import java.io.UnsupportedEncodingException JavaDoc;
19 import java.text.DecimalFormat JavaDoc;
20 import java.text.FieldPosition JavaDoc;
21 import java.text.NumberFormat JavaDoc;
22 import java.util.Date JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.LinkedList JavaDoc;
25
26 import com.vladium.util.Descriptors;
27 import com.vladium.util.Files;
28 import com.vladium.util.IProperties;
29 import com.vladium.util.IntObjectMap;
30 import com.vladium.util.IntVector;
31 import com.vladium.util.ObjectIntMap;
32 import com.vladium.util.Property;
33 import com.vladium.util.asserts.$assert;
34 import com.vladium.emma.IAppConstants;
35 import com.vladium.emma.IAppErrorCodes;
36 import com.vladium.emma.EMMAProperties;
37 import com.vladium.emma.EMMARuntimeException;
38 import com.vladium.emma.data.ICoverageData;
39 import com.vladium.emma.data.IMetaData;
40 import com.vladium.emma.report.AbstractReportGenerator;
41 import com.vladium.emma.report.AllItem;
42 import com.vladium.emma.report.ClassItem;
43 import com.vladium.emma.report.IItem;
44 import com.vladium.emma.report.IItemAttribute;
45 import com.vladium.emma.report.IItemMetadata;
46 import com.vladium.emma.report.ItemComparator;
47 import com.vladium.emma.report.MethodItem;
48 import com.vladium.emma.report.PackageItem;
49 import com.vladium.emma.report.SourcePathCache;
50 import com.vladium.emma.report.SrcFileItem;
51 import com.vladium.emma.report.html.doc.*;
52
53 // ----------------------------------------------------------------------------
54
/**
55  * @author Vlad Roubtsov, (C) 2003
56  */

57 public
58 final class ReportGenerator extends AbstractReportGenerator
59                             implements IAppErrorCodes
60 {
61     // public: ................................................................
62

63     // TODO: make sure relative file names are converted to relative URLs in all anchors/hrefs
64

65     public ReportGenerator ()
66     {
67         m_format = (DecimalFormat JavaDoc) NumberFormat.getPercentInstance (); // TODO: locale
68
m_fieldPosition = new FieldPosition JavaDoc (DecimalFormat.INTEGER_FIELD);
69         
70         m_format.setMaximumFractionDigits (0);
71     }
72
73         
74     // IReportGenerator:
75

76     public final String JavaDoc getType ()
77     {
78         return TYPE;
79     }
80     
81     public void process (final IMetaData mdata, final ICoverageData cdata,
82                          final SourcePathCache cache, final IProperties properties)
83         throws EMMARuntimeException
84     {
85         initialize (mdata, cdata, cache, properties);
86         
87         m_pageTitle = null;
88         m_footerBottom = null;
89         
90         File JavaDoc outDir = m_settings.getOutDir ();
91         if ((outDir == null) /* this should never happen */ || (outDir.equals (new File JavaDoc (Property.getSystemProperty ("user.dir", "")))))
92         {
93             outDir = new File JavaDoc ("coverage");
94             m_settings.setOutDir (outDir);
95         }
96         
97         long start = 0, end;
98         final boolean trace1 = m_log.atTRACE1 ();
99         
100         if (trace1) start = System.currentTimeMillis ();
101         
102         {
103             m_queue = new LinkedList JavaDoc ();
104             m_reportIDNamespace = new IDGenerator (mdata.size ());
105             
106             for (m_queue.add (m_view.getRoot ()); ! m_queue.isEmpty (); )
107             {
108                 final IItem head = (IItem) m_queue.removeFirst ();
109                 
110                 head.accept (this, null);
111             }
112             
113             m_reportIDNamespace = null;
114         }
115         
116         if (trace1)
117         {
118             end = System.currentTimeMillis ();
119             
120             m_log.trace1 ("process", "[" + getType () + "] report generated in " + (end - start) + " ms");
121         }
122     }
123     
124     public void cleanup ()
125     {
126         m_queue = null;
127         m_reportIDNamespace = null;
128         
129         super.cleanup ();
130     }
131
132         
133     // IItemVisitor:
134

135     public Object JavaDoc visit (final AllItem item, final Object JavaDoc ctx)
136     {
137         HTMLWriter out = null;
138         try
139         {
140             File JavaDoc outFile = m_settings.getOutFile ();
141             if (outFile == null)
142             {
143                 outFile = new File JavaDoc ("index".concat (FILE_EXTENSION));
144                 m_settings.setOutFile (outFile);
145             }
146             
147             final File JavaDoc fullOutFile = Files.newFile (m_settings.getOutDir (), outFile);
148             
149             m_log.info ("writing [" + getType () + "] report to [" + fullOutFile.getAbsolutePath () + "] ...");
150             
151             out = openOutFile (fullOutFile, m_settings.getOutEncoding (), true);
152             
153             final int [] columns = m_settings.getColumnOrder ();
154             final StringBuffer JavaDoc buf = new StringBuffer JavaDoc ();
155             
156             final String JavaDoc title;
157             {
158                 final StringBuffer JavaDoc _title = new StringBuffer JavaDoc (REPORT_HEADER_TITLE);
159                 
160                 _title.append (" (generated ");
161                 _title.append (new Date JavaDoc (EMMAProperties.getTimeStamp ()));
162                 _title.append (')');
163                 
164                 title = _title.toString ();
165             }
166             
167             final HTMLDocument page = createPage (title);
168             {
169                 final IItem [] path = getParentPath (item);
170                 
171                 addPageHeader (page, item, path);
172                 addPageFooter (page, item, path);
173             }
174                         
175             // [all] coverage summary table:
176

177             page.addH (1, "OVERALL COVERAGE SUMMARY", null);
178             
179             final HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0");
180             {
181                 // header row:
182
final HTMLTable.IRow header = summaryTable.newTitleRow ();
183                 // coverage row:
184
final HTMLTable.IRow coverage = summaryTable.newRow ();
185                 
186                 for (int c = 0; c < columns.length; ++ c)
187                 {
188                     final int attrID = columns [c];
189                     final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
190                     
191                     final HTMLTable.ICell headercell = header.newCell ();
192                     headercell.setText (attr.getName (), true);
193                     
194                     if (attr != null)
195                     {
196                         boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
197                         
198                         buf.setLength (0);
199                         attr.format (item, buf);
200                         
201                         final HTMLTable.ICell cell = coverage.newCell ();
202                         cell.setText (buf.toString (), true);
203                         if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
204                     }
205                 }
206             }
207             page.add (summaryTable);
208             
209             // [all] stats summary table ([all] only):
210

211             page.addH (2, "OVERALL STATS SUMMARY", null);
212             
213             final HTMLTable statsTable = new HTMLTable (null, null, null, "0");
214             statsTable.setClass (CSS_INVISIBLE_TABLE);
215             {
216                 HTMLTable.IRow row = statsTable.newRow ();
217                 row.newCell ().setText ("total packages:", true);
218                 row.newCell ().setText ("" + item.getChildCount (), false);
219                 
220                 if (m_srcView && m_hasSrcFileInfo)
221                 {
222                     row = statsTable.newRow ();
223                     row.newCell ().setText ("total executable files:", true);
224                     row.newCell ().setText ("" + item.getAggregate (IItem.TOTAL_SRCFILE_COUNT), false);
225                 }
226                 
227                 row = statsTable.newRow ();
228                 row.newCell ().setText ("total classes:", true);
229                 row.newCell ().setText ("" + item.getAggregate (IItem.TOTAL_CLASS_COUNT), true);
230                 row = statsTable.newRow ();
231                 row.newCell ().setText ("total methods:", true);
232                 row.newCell ().setText ("" + item.getAggregate (IItem.TOTAL_METHOD_COUNT), true);
233                 
234                 if (m_srcView && m_hasSrcFileInfo && m_hasLineNumberInfo)
235                 {
236                     row = statsTable.newRow ();
237                     row.newCell ().setText ("total executable lines:", true);
238                     row.newCell ().setText ("" + item.getAggregate (IItem.TOTAL_LINE_COUNT), true);
239                 }
240             }
241             /*
242             {
243                 final HTMLTable.IRow first = statsTable.newRow (); // stats always available
244                 
245                 first.newCell ().setText ("total packages: " + item.getChildCount (), true);
246                 first.newCell ().setText ("total classes: " + item.getAggregate (IItem.TOTAL_CLASS_COUNT), true);
247                 first.newCell ().setText ("total methods: " + item.getAggregate (IItem.TOTAL_METHOD_COUNT), true);
248                 
249                 if (m_srcView && m_hasSrcFileInfo)
250                 {
251                     final HTMLTable.IRow second = statsTable.newRow ();
252                     
253                     final HTMLTable.ICell cell1 = second.newCell ();
254                     cell1.setText ("total source files: " + item.getAggregate (IItem.TOTAL_SRCFILE_COUNT), true);
255                 
256                     if (m_hasLineNumberInfo)
257                     {
258                         final HTMLTable.ICell cell2 = second.newCell ();
259                         
260                         cell2.setText ("total executable source lines: " + item.getAggregate (IItem.TOTAL_LINE_COUNT), true);
261                         cell2.getAttributes ().set (Attribute.COLSPAN, "2");
262                     }
263                     else
264                     {
265                         cell1.getAttributes ().set (Attribute.COLSPAN, "3");
266                     }
267                 }
268             }
269             */

270             page.add (statsTable);
271             
272             final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
273             
274             // render package summary tables on the same page:
275

276             page.addH (2, "COVERAGE BREAKDOWN BY PACKAGE", null);
277             
278             final HTMLTable childSummaryTable = new HTMLTable ("100%", null, null, "0");
279             {
280                 int [] headerColumns = null;
281                 
282                 boolean odd = true;
283                 final ItemComparator order = m_typeSortComparators [PackageItem.getTypeMetadata ().getTypeID ()];
284                 for (Iterator JavaDoc packages = item.getChildren (order); packages.hasNext (); odd = ! odd)
285                 {
286                     final IItem pkg = (IItem) packages.next ();
287                     
288                     if (headerColumns == null)
289                     {
290                         // header row:
291
headerColumns = addHeaderRow (pkg, childSummaryTable, columns);
292                     }
293                     
294                     // coverage row:
295
String JavaDoc childHREF = null;
296                     if (deeper)
297                     {
298                         childHREF = getItemHREF (item, pkg);
299                     }
300                     addItemRow (pkg, odd, childSummaryTable, headerColumns, childHREF, false);
301                     
302                     if (deeper) m_queue.addLast (pkg);
303                 }
304             }
305             page.add (childSummaryTable);
306             
307             
308             page.emit (out);
309             out.flush ();
310         }
311         finally
312         {
313             if (out != null) out.close ();
314             out = null;
315         }
316         
317         return ctx;
318     }
319     
320     public Object JavaDoc visit (final PackageItem item, final Object JavaDoc ctx)
321     {
322         HTMLWriter out = null;
323         try
324         {
325             if (m_verbose) m_log.verbose (" report: processing package [" + item.getName () + "] ...");
326             
327             final File JavaDoc outFile = getItemFile (NESTED_ITEMS_PARENT_DIR, m_reportIDNamespace.getID (getItemKey (item)));
328             
329             out = openOutFile (Files.newFile (m_settings.getOutDir (), outFile), m_settings.getOutEncoding (), true);
330             
331             final int [] columns = m_settings.getColumnOrder ();
332             final StringBuffer JavaDoc buf = new StringBuffer JavaDoc ();
333             
334             // TODO: set title [from a prop?]
335
final HTMLDocument page = createPage (REPORT_HEADER_TITLE);
336             {
337                 final IItem [] path = getParentPath (item);
338                 
339                 addPageHeader (page, item, path);
340                 addPageFooter (page, item, path);
341             }
342                         
343             // summary table:
344

345             {
346                 final IElement itemname = IElement.Factory.create (Tag.SPAN);
347                 itemname.setText (item.getName (), true);
348                 itemname.setClass (CSS_ITEM_NAME);
349                 
350                 final IElementList title = new ElementList ();
351                 title.add (new Text ("COVERAGE SUMMARY FOR PACKAGE [", true));
352                 title.add (itemname);
353                 title.add (new Text ("]", true));
354                 
355                 page.addH (1, title, null);
356             }
357             
358             final HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0");
359             {
360                 // header row:
361
final HTMLTable.IRow header = summaryTable.newTitleRow ();
362                 // coverage row:
363
final HTMLTable.IRow coverage = summaryTable.newRow ();
364                 
365                 for (int c = 0; c < columns.length; ++ c)
366                 {
367                     final int attrID = columns [c];
368                     final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
369                     
370                     final HTMLTable.ICell headercell = header.newCell ();
371                     headercell.setText (attr.getName (), true);
372                     
373                     if (attr != null)
374                     {
375                         boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
376                         
377                         buf.setLength (0);
378                         attr.format (item, buf);
379                         
380                         final HTMLTable.ICell cell = coverage.newCell ();
381                         cell.setText (buf.toString (), true);
382                         if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
383                     }
384                 }
385             }
386             page.add (summaryTable);
387             
388             final boolean deeper = (m_settings.getDepth () > item.getMetadata ().getTypeID ());
389             
390             // render child summary tables on the same page:
391

392             final String JavaDoc summaryTitle = m_srcView ? "COVERAGE BREAKDOWN BY SOURCE FILE" : "COVERAGE BREAKDOWN BY CLASS";
393             page.addH (2, summaryTitle, null);
394             
395             final HTMLTable childSummaryTable = new HTMLTable ("100%", null, null, "0");
396             {
397                 int [] headerColumns = null;
398                 
399                 boolean odd = true;
400                 final ItemComparator order = m_typeSortComparators [m_srcView ? SrcFileItem.getTypeMetadata ().getTypeID () : ClassItem.getTypeMetadata ().getTypeID ()];
401                 for (Iterator JavaDoc srcORclsFiles = item.getChildren (order); srcORclsFiles.hasNext (); odd = ! odd)
402                 {
403                     final IItem srcORcls = (IItem) srcORclsFiles.next ();
404                     
405                     if (headerColumns == null)
406                     {
407                         // header row:
408
headerColumns = addHeaderRow (srcORcls, childSummaryTable, columns);
409                     }
410                     
411                     // coverage row:
412
String JavaDoc childHREF = null;
413                     if (deeper)
414                     {
415                         childHREF = getItemHREF (item, srcORcls);
416                     }
417                     addItemRow (srcORcls, odd, childSummaryTable, headerColumns, childHREF, false);
418                                         
419                     if (deeper) m_queue.addLast (srcORcls);
420                 }
421             }
422             page.add (childSummaryTable);
423             
424             
425             page.emit (out);
426             out.flush ();
427         }
428         finally
429         {
430             if (out != null) out.close ();
431             out = null;
432         }
433         
434         return ctx;
435     }
436
437     public Object JavaDoc visit (final SrcFileItem item, final Object JavaDoc ctx)
438     {
439         // this visit only takes place in src views
440

441         HTMLWriter out = null;
442         try
443         {
444             final File JavaDoc outFile = getItemFile (NESTED_ITEMS_PARENT_DIR, m_reportIDNamespace.getID (getItemKey (item)));
445             
446             out = openOutFile (Files.newFile (m_settings.getOutDir (), outFile), m_settings.getOutEncoding (), true);
447             
448             final int [] columns = m_settings.getColumnOrder ();
449             final StringBuffer JavaDoc buf = new StringBuffer JavaDoc ();
450             
451             // TODO: set title [from a prop?]
452
final HTMLDocument page = createPage (REPORT_HEADER_TITLE);
453             {
454                 final IItem [] path = getParentPath (item);
455                 
456                 addPageHeader (page, item, path);
457                 addPageFooter (page, item, path);
458             }
459             
460             // summary table:
461

462             {
463                 final IElement itemname = IElement.Factory.create (Tag.SPAN);
464                 itemname.setText (item.getName (), true);
465                 itemname.setClass (CSS_ITEM_NAME);
466                 
467                 final IElementList title = new ElementList ();
468                 title.add (new Text ("COVERAGE SUMMARY FOR SOURCE FILE [", true));
469                 title.add (itemname);
470                 title.add (new Text ("]", true));
471                 
472                 page.addH (1, title, null);
473             }
474             
475             final HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0");
476             {
477                 // header row:
478
final HTMLTable.IRow header = summaryTable.newTitleRow ();
479                 // coverage row:
480
final HTMLTable.IRow coverage = summaryTable.newRow ();
481                 
482                 for (int c = 0; c < columns.length; ++ c)
483                 {
484                     final int attrID = columns [c];
485                     final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
486                     
487                     final HTMLTable.ICell headercell = header.newCell ();
488                     headercell.setText (attr.getName (), true);
489                     
490                     if (attr != null)
491                     {
492                         boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
493                         
494                         buf.setLength (0);
495                         attr.format (item, buf);
496                         
497                         final HTMLTable.ICell cell = coverage.newCell ();
498                         cell.setText (buf.toString (), true);
499                         if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
500                     }
501                 }
502             }
503             page.add (summaryTable);
504             
505             final boolean deeper = (m_settings.getDepth () > ClassItem.getTypeMetadata ().getTypeID ());
506             final boolean embedSrcFile = deeper && srcFileAvailable (item, m_cache);
507             final boolean createAnchors = embedSrcFile && m_hasLineNumberInfo;
508             
509             final IDGenerator pageIDNamespace = createAnchors ? new IDGenerator () : null;
510             
511             // child summary table is special for srcfile items:
512

513             page.addH (2, "COVERAGE BREAKDOWN BY CLASS AND METHOD", null);
514
515             final IntObjectMap lineAnchorIDMap = embedSrcFile ? new IntObjectMap () : null;
516             final HTMLTable childSummaryTable = new HTMLTable ("100%", null, null, "0");
517             
518             childSummaryTable.setClass (CSS_CLS_NOLEFT);
519             
520             {
521                 int [] headerColumns = null;
522
523                 final ItemComparator order = m_typeSortComparators [ClassItem.getTypeMetadata ().getTypeID ()];
524                 int clsIndex = 0;
525                 for (Iterator JavaDoc classes = item.getChildren (order); classes.hasNext (); ++ clsIndex)
526                 {
527                     final ClassItem cls = (ClassItem) classes.next ();
528
529                     if (headerColumns == null)
530                     {
531                         // header row:
532
headerColumns = addHeaderRow (cls, childSummaryTable, columns);
533                     }
534                     
535                     String JavaDoc HREFname = null;
536                     
537                     // special class subheader:
538
if (createAnchors)
539                     {
540                         if ($assert.ENABLED)
541                         {
542                             $assert.ASSERT (lineAnchorIDMap != null);
543                             $assert.ASSERT (pageIDNamespace != null);
544                         }
545                         
546                         final String JavaDoc childKey = getItemKey (cls);
547                         
548                         HREFname = addLineAnchorID (cls.getFirstLine (), pageIDNamespace.getID (childKey), lineAnchorIDMap);
549                     }
550
551                     addClassRow (cls, clsIndex, childSummaryTable, headerColumns, HREFname, createAnchors);
552                     
553 // // row to separate this class's methods:
554
// final HTMLTable.IRow subheader = childSummaryTable.newTitleRow ();
555
// final HTMLTable.ICell cell = subheader.newCell ();
556
// // TODO: cell.setColspan (???)
557
// cell.setText ("class " + child.getName () + " methods:", true);
558

559                     boolean odd = false;
560                     final ItemComparator order2 = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
561                     for (Iterator JavaDoc methods = cls.getChildren (order2); methods.hasNext (); odd = ! odd)
562                     {
563                         final MethodItem method = (MethodItem) methods.next ();
564                         
565                         HREFname = null;
566                         
567                         if (createAnchors)
568                         {
569                             if ($assert.ENABLED)
570                             {
571                                 $assert.ASSERT (lineAnchorIDMap != null);
572                                 $assert.ASSERT (pageIDNamespace != null);
573                             }
574                             
575                             final String JavaDoc child2Key = getItemKey (method);
576                             
577                             HREFname = addLineAnchorID (method.getFirstLine (), pageIDNamespace.getID (child2Key), lineAnchorIDMap);
578                         }
579
580                         addClassItemRow (method, odd, childSummaryTable, headerColumns, HREFname, createAnchors);
581                     }
582                 }
583             }
584             page.add (childSummaryTable);
585             
586             
587             // embed source file:
588

589             if (deeper)
590             {
591                 //page.addHR (1);
592
page.addEmptyP ();
593                 {
594                     embedSrcFile (item, page, lineAnchorIDMap, m_cache);
595                 }
596                 //page.addHR (1);
597
}
598                 
599             
600             page.emit (out);
601             out.flush ();
602         }
603         finally
604         {
605             if (out != null) out.close ();
606             out = null;
607         }
608
609         return ctx;
610     }
611
612     public Object JavaDoc visit (final ClassItem item, final Object JavaDoc ctx)
613     {
614         // this visit only takes place in class views
615

616         HTMLWriter out = null;
617         try
618         {
619             final File JavaDoc outFile = getItemFile (NESTED_ITEMS_PARENT_DIR, m_reportIDNamespace.getID (getItemKey (item)));
620             
621             // TODO: deal with overwrites
622
out = openOutFile (Files.newFile (m_settings.getOutDir (), outFile), m_settings.getOutEncoding (), true);
623             
624             final int [] columns = m_settings.getColumnOrder ();
625             final StringBuffer JavaDoc buf = new StringBuffer JavaDoc ();
626             
627             // TODO: set title [from a prop?]
628
final HTMLDocument page = createPage (REPORT_HEADER_TITLE);
629             {
630                 final IItem [] path = getParentPath (item);
631                 
632                 addPageHeader (page, item, path);
633                 addPageFooter (page, item, path);
634             }
635             
636             
637             // summary table:
638

639             {
640                 final IElement itemname = IElement.Factory.create (Tag.SPAN);
641                 itemname.setText (item.getName (), true);
642                 itemname.setClass (CSS_ITEM_NAME);
643                 
644                 final IElementList title = new ElementList ();
645                 title.add (new Text ("COVERAGE SUMMARY FOR CLASS [", true));
646                 title.add (itemname);
647                 title.add (new Text ("]", true));
648                 
649                 page.addH (1, title, null);
650             }
651             
652             final HTMLTable summaryTable = new HTMLTable ("100%", null, null, "0");
653             {
654                 // header row:
655
final HTMLTable.IRow header = summaryTable.newTitleRow ();
656                 // coverage row:
657
final HTMLTable.IRow coverage = summaryTable.newRow ();
658                 
659                 for (int c = 0; c < columns.length; ++ c)
660                 {
661                     final int attrID = columns [c];
662                     final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
663                     
664                     final HTMLTable.ICell headercell = header.newCell ();
665                     headercell.setText (attr.getName (), true);
666                     
667                     if (attr != null)
668                     {
669                         boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
670                         
671                         buf.setLength (0);
672                         attr.format (item, buf);
673                         
674                         final HTMLTable.ICell cell = coverage.newCell ();
675                         cell.setText (buf.toString (), true);
676                         if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
677                     }
678                 }
679             }
680             page.add (summaryTable);
681             
682             
683             // child summary table:
684

685             page.addH (2, "COVERAGE BREAKDOWN BY METHOD", null);
686
687             final HTMLTable childSummaryTable = new HTMLTable ("100%", null, null, "0");
688             {
689                 int [] headerColumns = null;
690                 
691                 boolean odd = true;
692                 final ItemComparator order = m_typeSortComparators [MethodItem.getTypeMetadata ().getTypeID ()];
693                 for (Iterator JavaDoc methods = item.getChildren (order); methods.hasNext (); odd = ! odd)
694                 {
695                     final MethodItem method = (MethodItem) methods.next ();
696
697                     if (headerColumns == null)
698                     {
699                         // header row:
700
headerColumns = addHeaderRow (method, childSummaryTable, columns);
701                     }
702                     
703                     addItemRow (method, odd, childSummaryTable, headerColumns, null, false);
704                 }
705             }
706             page.add (childSummaryTable);
707             
708             
709             page.emit (out);
710             out.flush ();
711         }
712         finally
713         {
714             if (out != null) out.close ();
715             out = null;
716         }
717
718         return ctx;
719     }
720     
721     // protected: .............................................................
722

723     // package: ...............................................................
724

725     // private: ...............................................................
726

727     
728     private static final class IDGenerator
729     {
730         IDGenerator ()
731         {
732             m_namespace = new ObjectIntMap (101);
733             m_out = new int [1];
734         }
735         
736         IDGenerator (final int initialCapacity)
737         {
738             m_namespace = new ObjectIntMap (initialCapacity);
739             m_out = new int [1];
740         }
741         
742         String JavaDoc getID (final String JavaDoc key)
743         {
744             final int [] out = m_out;
745             final int ID;
746             
747             if (m_namespace.get (key, out))
748                 ID = out [0];
749             else
750             {
751                 ID = m_namespace.size ();
752                 m_namespace.put (key, ID);
753             }
754             
755             return Integer.toHexString (ID);
756         }
757         
758         private final ObjectIntMap /* key:String->ID */ m_namespace;
759         private final int [] m_out;
760         
761     } // end of nested class
762

763     
764     private HTMLDocument createPage (final String JavaDoc title)
765     {
766         final HTMLDocument page = new HTMLDocument (title, m_settings.getOutEncoding ());
767         page.addStyle (CSS); // TODO: split by visit type
768

769         return page;
770     }
771     
772     private IElement addPageHeader (final HTMLDocument page, final IItem item, final IItem [] path)
773     {
774         // TODO: merge header and footer in the same method
775

776         if ($assert.ENABLED)
777         {
778             $assert.ASSERT (page != null);
779         }
780         
781         final HTMLTable header = new HTMLTable ("100%", null, null, "0");
782         header.setClass (CSS_HEADER_FOOTER);
783
784         // header row:
785
addPageHeaderTitleRow (header);
786         
787         // nav row:
788
{
789             final HTMLTable.IRow navRow = header.newRow ();
790             
791             final HTMLTable.ICell cell = navRow.newCell ();
792             cell.setClass (CSS_NAV);
793             
794             final int lLimit = path.length > 1 ? path.length - 1 : path.length;
795             for (int l = 0; l < lLimit; ++ l)
796             {
797                 cell.add (LEFT_BRACKET);
798                 
799                 final String JavaDoc name = path [l].getName ();
800                 final String JavaDoc HREF = getItemHREF (item, path [l]);
801                 cell.add (new HyperRef (HREF, name, true));
802                 
803                 cell.add (RIGHT_BRACKET);
804             }
805         }
806         
807         page.setHeader (header);
808         
809         return header;
810     }
811     
812     private IElement addPageFooter (final HTMLDocument page, final IItem item, final IItem [] path)
813     {
814         if ($assert.ENABLED)
815         {
816             $assert.ASSERT (page != null);
817         }
818
819         final HTMLTable footerTable = new HTMLTable ("100%", null, null, "0");
820         footerTable.setClass (CSS_HEADER_FOOTER);
821
822         // nav row:
823
{
824             final HTMLTable.IRow navRow = footerTable.newRow ();
825             
826             final HTMLTable.ICell cell = navRow.newCell ();
827             cell.setClass (CSS_NAV);
828             
829             final int lLimit = path.length > 1 ? path.length - 1 : path.length;
830             for (int l = 0; l < lLimit; ++ l)
831             {
832                 cell.add (LEFT_BRACKET);
833                 
834                 final String JavaDoc name = path [l].getName ();
835                 final String JavaDoc HREF = getItemHREF (item, path [l]);
836                 cell.add (new HyperRef (HREF, name, true));
837                 
838                 cell.add (RIGHT_BRACKET);
839             }
840         }
841         
842         // title row:
843
{
844             final HTMLTable.IRow titleRow = footerTable.newRow ();
845             
846             final HTMLTable.ICell cell = titleRow.newCell ();
847             cell.setClass (CSS_TITLE);
848             
849             cell.add (getFooterBottom ());
850         }
851         
852         final ElementList footer = new ElementList ();
853         
854         footer.add (IElement.Factory.create (Tag.P)); // spacer
855
footer.add (footerTable);
856         
857         page.setFooter (footer);
858         
859         return footerTable;
860     }
861     
862     private int [] addHeaderRow (final IItem item, final HTMLTable table, final int [] columns)
863     {
864         if ($assert.ENABLED)
865         {
866             $assert.ASSERT (item != null, "null input: item");
867             $assert.ASSERT (table != null, "null input: table");
868             $assert.ASSERT (columns != null, "null input: columns");
869         }
870         
871         // header row:
872
final HTMLTable.IRow header = table.newTitleRow ();
873         
874         // determine the set of columns actually present in the header [may be narrower than 'columns']:
875
final IntVector headerColumns = new IntVector (columns.length);
876         
877         for (int c = 0; c < columns.length; ++ c)
878         {
879             final int attrID = columns [c];
880             final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
881             
882             if (attr != null)
883             {
884                 final HTMLTable.ICell cell = header.newCell ();
885             
886                 cell.setText (attr.getName (), true);//.getAttributes ().set (Attribute.WIDTH, "20%");
887
cell.setClass (headerCellStyle (c));
888                 headerColumns.add (attrID);
889             }
890             
891             // note: by design this does not create columns for nonexistent attribute types
892
}
893         
894         return headerColumns.values ();
895     }
896     
897     /*
898      * No header row, just data rows.
899      */

900     private void addItemRow (final IItem item, final boolean odd, final HTMLTable table, final int [] columns, final String JavaDoc nameHREF, final boolean anchor)
901     {
902         if ($assert.ENABLED)
903         {
904             $assert.ASSERT (item != null, "null input: item");
905             $assert.ASSERT (table != null, "null input: table");
906             $assert.ASSERT (columns != null, "null input: columns");
907         }
908         
909         final HTMLTable.IRow row = table.newRow ();
910         if (odd) row.setClass (CSS_ODDROW);
911         
912         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc (11); // TODO: reuse a buffer
913

914         for (int c = 0; c < columns.length; ++ c)
915         {
916             final int attrID = columns [c];
917             final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
918             
919             if (attr != null)
920             {
921                 final HTMLTable.ICell cell = row.newCell ();
922                 
923                 if ((nameHREF != null) && (attrID == IItemAttribute.ATTRIBUTE_NAME_ID))
924                 {
925                     buf.setLength (0);
926                     attr.format (item, buf);
927                     
928                     trimForDisplay (buf);
929                     
930                     final String JavaDoc fullHREFName = anchor ? "#".concat (nameHREF) : nameHREF;
931                     
932                     cell.add (new HyperRef (fullHREFName, buf.toString (), true));
933                 }
934                 else
935                 {
936                     final boolean fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
937                     
938                     buf.setLength (0);
939                     attr.format (item, buf);
940                     
941                     trimForDisplay (buf);
942                      
943                     cell.setText (buf.toString (), true);
944                     if (fail) cell.setClass (CSS_DATA_HIGHLIGHT);
945                 }
946             }
947             else
948             {
949                 // note: by design this puts empty cells for nonexistent attribute types
950

951                 final HTMLTable.ICell cell = row.newCell ();
952                 cell.setText (" ", true);
953             }
954         }
955     }
956     
957     private void addClassRow (final ClassItem item, final int clsIndex, final HTMLTable table, final int [] columns,
958                               final String JavaDoc itemHREF, final boolean isAnchor)
959     {
960         if ($assert.ENABLED)
961         {
962             $assert.ASSERT (item != null, "null input: item");
963             $assert.ASSERT (table != null, "null input: table");
964             $assert.ASSERT (columns != null, "null input: columns");
965         }
966         
967         final HTMLTable.IRow blank = table.newRow ();
968         
969         final HTMLTable.IRow row = table.newRow ();
970         row.setClass (CSS_CLASS_ITEM_SPECIAL);
971         
972         final StringBuffer JavaDoc buf = new StringBuffer JavaDoc (11);
973         
974         for (int c = 0; c < columns.length; ++ c)
975         {
976             final int attrID = columns [c];
977             final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
978             
979             if (attr != null)
980             {
981                 buf.setLength (0);
982                 attr.format (item, buf);
983                 
984                 final HTMLTable.ICell blankcell = blank.newCell ();
985                 blankcell.setClass (clsIndex == 0 ? CSS_BLANK : CSS_BOTTOM);
986                 blankcell.setText (" ", true);
987                 
988                 final HTMLTable.ICell cell = row.newCell ();
989                 
990                 boolean fail = false;
991                 if (attrID == IItemAttribute.ATTRIBUTE_NAME_ID)
992                 {
993                     if (itemHREF != null)
994                     {
995                         final String JavaDoc fullItemHREF = isAnchor ? "#".concat (itemHREF) : itemHREF;
996                         
997                         cell.add (new Text ("class ", true));
998                         cell.add (new HyperRef (fullItemHREF, buf.toString (), true));
999                     }
1000                    else
1001                    {
1002                        cell.setText ("class " + buf.toString (), true);
1003                    }
1004                }
1005                else
1006                {
1007                    fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
1008                    
1009                    cell.setText (buf.toString (), true);
1010                }
1011                
1012                cell.setClass (dataCellStyle (c, fail));
1013            }
1014            else
1015            {
1016                final HTMLTable.ICell cell = row.newCell ();
1017                cell.setText (" ", true);
1018                cell.setClass (dataCellStyle (c, false));
1019            }
1020        }
1021    }
1022    
1023    
1024    private void addClassItemRow (final IItem item, final boolean odd, final HTMLTable table, final int [] columns, final String JavaDoc nameHREF, final boolean anchor)
1025    {
1026        if ($assert.ENABLED)
1027        {
1028            $assert.ASSERT (item != null, "null input: item");
1029            $assert.ASSERT (table != null, "null input: table");
1030            $assert.ASSERT (columns != null, "null input: columns");
1031        }
1032        
1033        final HTMLTable.IRow row = table.newRow ();
1034        if (odd) row.setClass (CSS_ODDROW);
1035        
1036        final StringBuffer JavaDoc buf = new StringBuffer JavaDoc (11); // TODO: reuse a buffer
1037

1038        for (int c = 0; c < columns.length; ++ c)
1039        {
1040            final int attrID = columns [c];
1041            final IItemAttribute attr = item.getAttribute (attrID, m_settings.getUnitsType ());
1042            
1043            if (attr != null)
1044            {
1045                final HTMLTable.ICell cell = row.newCell ();
1046                
1047                boolean fail = false;
1048                if ((nameHREF != null) && (attrID == IItemAttribute.ATTRIBUTE_NAME_ID))
1049                {
1050                    buf.setLength (0);
1051                    attr.format (item, buf);
1052                    
1053                    trimForDisplay (buf);
1054                    
1055                    final String JavaDoc fullHREFName = anchor ? "#".concat (nameHREF) : nameHREF;
1056                    
1057                    cell.add (new HyperRef (fullHREFName, buf.toString (), true));
1058                }
1059                else
1060                {
1061                    fail = (m_metrics [attrID] > 0) && ! attr.passes (item, m_metrics [attrID]);
1062                    
1063                    buf.setLength (0);
1064                    attr.format (item, buf);
1065                    
1066                    trimForDisplay (buf);
1067                     
1068                    cell.setText (buf.toString (), true);
1069                }
1070                
1071                cell.setClass (dataCellStyle (c, fail));
1072            }
1073            else
1074            {
1075                // note: by design this puts empty cells for nonexistent attribute types
1076

1077                final HTMLTable.ICell cell = row.newCell ();
1078                cell.setText (" ", true);
1079                cell.setClass (dataCellStyle (c, false));
1080            }
1081        }
1082    }
1083    
1084    
1085    private boolean srcFileAvailable (final SrcFileItem item, final SourcePathCache cache)
1086    {
1087        if (cache == null) return false;
1088        
1089        if ($assert.ENABLED) $assert.ASSERT (item != null, "null input: item");
1090        
1091        final String JavaDoc fileName = item.getName ();
1092        if ($assert.ENABLED) $assert.ASSERT (fileName.endsWith (".java"), "cache only handles .java extensions");
1093        
1094        // TODO: should I keep VM names in package items?
1095
final String JavaDoc packageVMName = ((PackageItem) item.getParent ()).getVMName ();
1096        
1097        return (cache.find (packageVMName, fileName) != null);
1098    }
1099    
1100// private boolean srcFileAvailable (final ClassItem item, final SourcePathCache cache)
1101
// {
1102
// if (cache == null) return false;
1103
//
1104
// if ($assert.ENABLED) $assert.ASSERT (item != null, "null input: item");
1105
//
1106
// final String fileName = item.getSrcFileName ();
1107
// if ($assert.ENABLED) $assert.ASSERT (fileName.endsWith (".java"), "cache only handles .java extensions");
1108
//
1109
// // TODO: should I keep VM names in package items?
1110
// final String packageVMName = ((PackageItem) item.getParent ()).getVMName ();
1111
//
1112
// return (cache.find (packageVMName, fileName) != null);
1113
// }
1114

1115    private void embedSrcFile (final SrcFileItem item, final HTMLDocument page,
1116                               final IntObjectMap /* line num:int->anchor name:String */anchorMap,
1117                               final SourcePathCache cache)
1118    {
1119        if ($assert.ENABLED)
1120        {
1121            $assert.ASSERT (item != null, "null input: item");
1122            $assert.ASSERT (page != null, "null input: page");
1123        }
1124        
1125        final String JavaDoc fileName = item.getName ();
1126        if ($assert.ENABLED) $assert.ASSERT (fileName.endsWith (".java"), "cache only handles .java extensions");
1127        
1128        // TODO: should I keep VM names in package items?
1129
final String JavaDoc packageVMName = ((PackageItem) item.getParent ()).getVMName ();
1130        
1131        boolean success = false;
1132
1133        final HTMLTable srcTable = new HTMLTable ("100%", null, null, "0");
1134        
1135        if (cache != null) // TODO: do this check earlier, in outer scope
1136
{
1137            srcTable.setClass (CSS_SOURCE);
1138            final File JavaDoc srcFile = cache.find (packageVMName, fileName);
1139            
1140            if (srcFile != null)
1141            {
1142                BufferedReader JavaDoc in = null;
1143                try
1144                {
1145                    in = new BufferedReader JavaDoc (new FileReader JavaDoc (srcFile), IO_BUF_SIZE);
1146                    
1147                    final boolean markupCoverage = m_hasLineNumberInfo;
1148                    
1149                    final int unitsType = m_settings.getUnitsType ();
1150                    IntObjectMap /* line num:int -> SrcFileItem.LineCoverageData */ lineCoverageMap = null;
1151                    StringBuffer JavaDoc tooltipBuffer = null;
1152                    
1153                    
1154                    if (markupCoverage)
1155                    {
1156                        lineCoverageMap = item.getLineCoverage ();
1157                        $assert.ASSERT (lineCoverageMap != null, "null: lineCoverageMap");
1158                        
1159                        tooltipBuffer = new StringBuffer JavaDoc (64);
1160                    }
1161                    
1162                    int l = 1;
1163                    for (String JavaDoc line; (line = in.readLine ()) != null; ++ l)
1164                    {
1165                        final HTMLTable.IRow srcline = srcTable.newRow ();
1166                        final HTMLTable.ICell lineNumCell = srcline.newCell ();
1167                        lineNumCell.setClass (CSS_LINENUM);
1168                        
1169                        if (anchorMap != null)
1170                        {
1171                            final int adjustedl = l < SRC_LINE_OFFSET ? l : l + SRC_LINE_OFFSET;
1172                            
1173                            final String JavaDoc anchor = (String JavaDoc) anchorMap.get (adjustedl);
1174                            if (anchor != null)
1175                            {
1176                                final IElement a = IElement.Factory.create (Tag.A);
1177                                //a.getAttributes ().set (Attribute.ID, anchor); ID anchoring does not work in NS 4.0
1178
a.getAttributes ().set (Attribute.NAME, anchor);
1179                                
1180                                a.setText (Integer.toString (l), true);
1181                                
1182                                lineNumCell.add (a);
1183                            }
1184                            else
1185                            {
1186                                lineNumCell.setText (Integer.toString (l), true);
1187                            }
1188                        }
1189                        else
1190                        {
1191                            lineNumCell.setText (Integer.toString (l), true);
1192                        }
1193                        
1194                        final HTMLTable.ICell lineTxtCell = srcline.newCell ();
1195                        lineTxtCell.setText (line.length () > 0 ? line : " ", true);
1196                        
1197                        if (markupCoverage)
1198                        {
1199                            final SrcFileItem.LineCoverageData lCoverageData = (SrcFileItem.LineCoverageData) lineCoverageMap.get (l);
1200                            
1201                            if (lCoverageData != null)
1202                            {
1203                                switch (lCoverageData.m_coverageStatus)
1204                                {
1205                                    case SrcFileItem.LineCoverageData.LINE_COVERAGE_ZERO:
1206                                        srcline.setClass (CSS_COVERAGE_ZERO);
1207                                    break;
1208                                    
1209                                    case SrcFileItem.LineCoverageData.LINE_COVERAGE_PARTIAL:
1210                                    {
1211                                        srcline.setClass (CSS_COVERAGE_PARTIAL);
1212                                        
1213                                        if (USE_LINE_COVERAGE_TOOLTIPS)
1214                                        {
1215                                            tooltipBuffer.setLength (0);
1216                                            
1217                                            final int [] coverageRatio = lCoverageData.m_coverageRatio [unitsType];
1218                                            
1219                                            final int d = coverageRatio [0];
1220                                            final int n = coverageRatio [1];
1221
1222                                            m_format.format ((double) n / d, tooltipBuffer, m_fieldPosition);
1223                                            
1224                                            tooltipBuffer.append (" line coverage (");
1225                                            tooltipBuffer.append (n);
1226                                            tooltipBuffer.append (" out of ");
1227                                            tooltipBuffer.append (d);
1228
1229                                            switch (unitsType)
1230                                            {
1231                                                case IItemAttribute.UNITS_COUNT:
1232                                                    tooltipBuffer.append (" basic blocks)");
1233                                                break;
1234                                                
1235                                                case IItemAttribute.UNITS_INSTR:
1236                                                    tooltipBuffer.append (" instructions)");
1237                                                break;
1238                                            }
1239                                            
1240                                            // [Opera does not display TITLE tooltios on <TR> elements]
1241

1242                                            lineNumCell.getAttributes ().set (Attribute.TITLE, tooltipBuffer.toString ());
1243                                            lineTxtCell.getAttributes ().set (Attribute.TITLE, tooltipBuffer.toString ());
1244                                        }
1245                                    }
1246                                    break;
1247                                        
1248                                    case SrcFileItem.LineCoverageData.LINE_COVERAGE_COMPLETE:
1249                                        srcline.setClass (CSS_COVERAGE_COMPLETE);
1250                                    break;
1251                                    
1252                                    default: $assert.ASSERT (false, "invalid line coverage status: " + lCoverageData.m_coverageStatus);
1253                                    
1254                                } // end of switch
1255
}
1256                        }
1257                    }
1258                    
1259                    success = true;
1260                }
1261                catch (Throwable JavaDoc t)
1262                {
1263                    t.printStackTrace (System.out); // TODO: logging
1264
success = false;
1265                }
1266                finally
1267                {
1268                    if (in != null) try { in.close (); } catch (Throwable JavaDoc ignore) {}
1269                    in = null;
1270                }
1271            }
1272        }
1273        
1274        if (! success)
1275        {
1276            srcTable.setClass (CSS_INVISIBLE_TABLE);
1277            
1278            final HTMLTable.IRow row = srcTable.newTitleRow ();
1279            row.newCell ().setText ("[source file '" + Descriptors.combineVMName (packageVMName, fileName) + "' not found in sourcepath]", false);
1280        }
1281        
1282        page.add (srcTable);
1283    }
1284    
1285    
1286    private static String JavaDoc addLineAnchorID (final int line, final String JavaDoc anchorID,
1287                                           final IntObjectMap /* line num:int->anchorID:String */lineAnchorIDMap)
1288    {
1289        if (line > 0)
1290        {
1291            final String JavaDoc _anchorID = (String JavaDoc) lineAnchorIDMap.get (line);
1292            if (_anchorID != null)
1293                return _anchorID;
1294            else
1295            {
1296                lineAnchorIDMap.put (line, anchorID);
1297
1298                return anchorID;
1299            }
1300        }
1301        
1302        return null;
1303    }
1304    
1305    /*
1306     * Always includes AllItem
1307     */

1308    private IItem [] getParentPath (IItem item)
1309    {
1310        final LinkedList JavaDoc /* IItem */ _result = new LinkedList JavaDoc ();
1311        
1312        for ( ; item != null; item = item.getParent ())
1313        {
1314            _result.add (item);
1315        }
1316        
1317        final IItem [] result = new IItem [_result.size ()];
1318        int j = result.length - 1;
1319        for (Iterator JavaDoc i = _result.iterator (); i.hasNext (); -- j)
1320        {
1321            result [j] = (IItem) i.next ();
1322        }
1323        
1324        return result;
1325    }
1326
1327    /*
1328     *
1329     */

1330    private String JavaDoc getItemHREF (final IItem base, final IItem item)
1331    {
1332        final String JavaDoc itemHREF;
1333        if (item instanceof AllItem)
1334            itemHREF = m_settings.getOutFile ().getName (); // note that this is always a simple filename [no parent path]
1335
else
1336            itemHREF = m_reportIDNamespace.getID (getItemKey (item)).concat (FILE_EXTENSION);
1337             
1338        final String JavaDoc fullHREF;
1339        
1340        if (base == null)
1341            fullHREF = itemHREF;
1342        else
1343        {
1344            final int nesting = NESTING [base.getMetadata ().getTypeID ()] [item.getMetadata ().getTypeID ()];
1345            if (nesting == 1)
1346                fullHREF = NESTED_ITEMS_PARENT_DIRNAME.concat ("/").concat (itemHREF);
1347            else if (nesting == -1)
1348                fullHREF = "../".concat (itemHREF);
1349            else
1350                fullHREF = itemHREF;
1351        }
1352        
1353        return fullHREF;
1354    }
1355    
1356    
1357    private IContent getPageTitle ()
1358    {
1359        IContent title = m_pageTitle;
1360        if (title == null)
1361        {
1362            final IElementList _title = new ElementList ();
1363            
1364            _title.add (new HyperRef (IAppConstants.APP_HOME_SITE_LINK, IAppConstants.APP_NAME, true));
1365            
1366            final StringBuffer JavaDoc s = new StringBuffer JavaDoc (" Coverage Report (generated ");
1367            s.append (new Date JavaDoc (EMMAProperties.getTimeStamp ()));
1368            s.append (')');
1369            
1370            _title.add (new Text (s.toString (), true));
1371            
1372            m_pageTitle = title = _title;
1373        }
1374        
1375        return title;
1376    }
1377    
1378    private IContent getFooterBottom ()
1379    {
1380        IContent bottom = m_footerBottom;
1381        if (bottom == null)
1382        {
1383            final IElementList _bottom = new ElementList ();
1384            
1385            _bottom.add (new HyperRef (IAppConstants.APP_BUG_REPORT_LINK, IAppConstants.APP_NAME + " " + IAppConstants.APP_VERSION_WITH_BUILD_ID_AND_TAG, true));
1386            _bottom.add (new Text (" " + IAppConstants.APP_COPYRIGHT, true));
1387            
1388            m_footerBottom = bottom = _bottom;
1389        }
1390        
1391        return bottom;
1392    }
1393    
1394    private void addPageHeaderTitleRow (final HTMLTable header)
1395    {
1396        final HTMLTable.IRow titleRow = header.newTitleRow ();
1397        
1398        final HTMLTable.ICell cell = titleRow.newCell ();
1399        cell.setClass (CSS_TITLE);
1400        cell.add (getPageTitle ());
1401    }
1402    
1403    private static void trimForDisplay (final StringBuffer JavaDoc buf)
1404    {
1405        if (buf.length () > MAX_DISPLAY_NAME_LENGTH)
1406        {
1407            buf.setLength (MAX_DISPLAY_NAME_LENGTH - 3);
1408            buf.append ("...");
1409        }
1410    }
1411    
1412    /*
1413     * Assumes relative pathnames.
1414     */

1415    private static File JavaDoc getItemFile (final File JavaDoc parentDir, final String JavaDoc itemKey)
1416    {
1417        if (parentDir == null)
1418            return new File JavaDoc (itemKey.concat (FILE_EXTENSION));
1419        else
1420            return new File JavaDoc (parentDir, itemKey.concat (FILE_EXTENSION));
1421    }
1422
1423    private static String JavaDoc getItemKey (IItem item)
1424    {
1425        final StringBuffer JavaDoc result = new StringBuffer JavaDoc ();
1426        
1427        for ( ; item != null; item = item.getParent ())
1428        {
1429            result.append (item.getName ());
1430            result.append (':');
1431        }
1432        
1433        return result.toString ();
1434    }
1435
1436    private static HTMLWriter openOutFile (final File JavaDoc file, final String JavaDoc encoding, final boolean mkdirs)
1437    {
1438        BufferedWriter JavaDoc out = null;
1439        try
1440        {
1441            if (mkdirs)
1442            {
1443                final File JavaDoc parent = file.getParentFile ();
1444                if (parent != null) parent.mkdirs ();
1445            }
1446            
1447            out = new BufferedWriter JavaDoc (new OutputStreamWriter JavaDoc (new FileOutputStream JavaDoc (file), encoding), IO_BUF_SIZE);
1448        }
1449        catch (UnsupportedEncodingException JavaDoc uee)
1450        {
1451            // TODO: error code
1452
throw new EMMARuntimeException (uee);
1453        }
1454        // note: in J2SDK 1.3 FileOutputStream constructor's throws clause
1455
// was narrowed to FileNotFoundException:
1456
catch (IOException JavaDoc fnfe) // FileNotFoundException
1457
{
1458            // TODO: error code
1459
throw new EMMARuntimeException (fnfe);
1460        }
1461        
1462        return new HTMLWriter (out);
1463    }
1464    
1465    private static String JavaDoc dataCellStyle (final int column, final boolean highlight)
1466    {
1467        if (column == 0)
1468            return highlight ? CSS_DATA_HIGHLIGHT_FIRST : CSS_DATA_FIRST;
1469        else
1470            return highlight ? CSS_DATA_HIGHLIGHT : CSS_DATA;
1471    }
1472    
1473    private static String JavaDoc headerCellStyle (final int column)
1474    {
1475        return (column == 0) ? CSS_HEADER_FIRST : CSS_HEADER;
1476    }
1477
1478    
1479    private final DecimalFormat JavaDoc m_format;
1480    private final FieldPosition JavaDoc m_fieldPosition;
1481        
1482    private LinkedList JavaDoc /* IITem */ m_queue;
1483    private IDGenerator m_reportIDNamespace;
1484    
1485    private IContent m_pageTitle, m_footerBottom;
1486    
1487    private static final boolean USE_LINE_COVERAGE_TOOLTIPS = true;
1488    
1489    private static final String JavaDoc TYPE = "html";
1490    private static final String JavaDoc REPORT_HEADER_TITLE = IAppConstants.APP_NAME + " Coverage Report";
1491    private static final IContent LEFT_BRACKET = new Text ("[", false);
1492    private static final IContent RIGHT_BRACKET = new Text ("]", false);
1493
1494    private static final int MAX_DISPLAY_NAME_LENGTH = 80;
1495    private static final int SRC_LINE_OFFSET = 4;
1496    
1497    
1498    private static final String JavaDoc CSS_HEADER_FOOTER = "hdft";
1499    private static final String JavaDoc CSS_TITLE = "tl";
1500    private static final String JavaDoc CSS_NAV = "nv";
1501    
1502    private static final String JavaDoc CSS_COVERAGE_ZERO = "z";
1503    private static final String JavaDoc CSS_COVERAGE_PARTIAL = "p";
1504    private static final String JavaDoc CSS_COVERAGE_COMPLETE = "c";
1505    
1506    private static final String JavaDoc DARKER_BACKGROUND = "#F0F0F0";
1507    private static final String JavaDoc TITLE_BACKGROUND = "#6699CC";
1508    private static final String JavaDoc NAV_BACKGROUND = "#6633DD";
1509    
1510    private static final String JavaDoc CSS_INVISIBLE_TABLE = "it";
1511    
1512    private static final String JavaDoc CSS_ITEM_NAME = "in";
1513    
1514    private static final String JavaDoc CSS_CLASS_ITEM_SPECIAL = "cis";
1515    
1516    private static final String JavaDoc CSS_SOURCE = "s";
1517    private static final String JavaDoc CSS_LINENUM = "l";
1518    
1519    private static final String JavaDoc CSS_BOTTOM = "bt";
1520    private static final String JavaDoc CSS_ODDROW = "o";
1521    private static final String JavaDoc CSS_BLANK = "b";
1522    
1523    private static final String JavaDoc CSS_DATA = "";
1524    private static final String JavaDoc CSS_DATA_HIGHLIGHT = CSS_DATA + "h";
1525    private static final String JavaDoc CSS_DATA_FIRST = CSS_DATA + "f";
1526    private static final String JavaDoc CSS_DATA_HIGHLIGHT_FIRST = CSS_DATA + "hf";
1527    private static final String JavaDoc CSS_HEADER = "";
1528    private static final String JavaDoc CSS_HEADER_FIRST = CSS_HEADER + "f";
1529    
1530    private static final String JavaDoc CSS_CLS_NOLEFT = "cn";
1531    
1532    // TODO: optimize this
1533

1534    private static final String JavaDoc CSS =
1535        " TABLE,TD,TH {border-style:solid; border-color:black;}" +
1536        " TD,TH {background:white;margin:0;line-height:100%;padding-left:0.5em;padding-right:0.5em;}" +
1537        
1538        " TD {border-width:0 1px 0 0;}" +
1539        " TH {border-width:1px 1px 1px 0;}" +
1540        " TR TD." + CSS_DATA_HIGHLIGHT + " {color:red;}" +
1541
1542        " TABLE {border-spacing:0; border-collapse:collapse;border-width:0 0 1px 1px;}" +
1543            
1544        " P,H1,H2,H3,TH {font-family:verdana,arial,sans-serif;font-size:10pt;}" +
1545        " TD {font-family:courier,monospace;font-size:10pt;}" +
1546         
1547        " TABLE." + CSS_HEADER_FOOTER + " {border-spacing:0;border-collapse:collapse;border-style:none;}" +
1548        " TABLE." + CSS_HEADER_FOOTER + " TH,TABLE." + CSS_HEADER_FOOTER + " TD {border-style:none;line-height:normal;}" +
1549        
1550        " TABLE." + CSS_HEADER_FOOTER + " TH." + CSS_TITLE + ",TABLE." + CSS_HEADER_FOOTER + " TD." + CSS_TITLE + " {background:" + TITLE_BACKGROUND + ";color:white;}" +
1551        " TABLE." + CSS_HEADER_FOOTER + " TD." + CSS_NAV + " {background:" + NAV_BACKGROUND + ";color:white;}" +
1552                
1553        " ." + CSS_NAV + " A:link {color:white;}" +
1554        " ." + CSS_NAV + " A:visited {color:white;}" +
1555        " ." + CSS_NAV + " A:active {color:yellow;}" +
1556        
1557        " TABLE." + CSS_HEADER_FOOTER + " A:link {color:white;}" +
1558        " TABLE." + CSS_HEADER_FOOTER + " A:visited {color:white;}" +
1559        " TABLE." + CSS_HEADER_FOOTER + " A:active {color:yellow;}" +
1560        
1561        //" ." + CSS_ITEM_NAME + " {color:#6633FF;}" +
1562
//" ." + CSS_ITEM_NAME + " {color:#C000E0;}" +
1563
" ." + CSS_ITEM_NAME + " {color:#356085;}" +
1564        
1565        //" A:hover {color:#0066FF; text-decoration:underline; font-style:italic}" +
1566

1567        " TABLE." + CSS_SOURCE + " TD {padding-left:0.25em;padding-right:0.25em;}" +
1568        " TABLE." + CSS_SOURCE + " TD." + CSS_LINENUM + " {padding-left:0.25em;padding-right:0.25em;text-align:right;background:" + DARKER_BACKGROUND + ";}" +
1569        " TABLE." + CSS_SOURCE + " TR." + CSS_COVERAGE_ZERO + " TD {background:#FF9999;}" +
1570        " TABLE." + CSS_SOURCE + " TR." + CSS_COVERAGE_PARTIAL + " TD {background:#FFFF88;}" +
1571        " TABLE." + CSS_SOURCE + " TR." + CSS_COVERAGE_COMPLETE + " TD {background:#CCFFCC;}" +
1572        
1573        " A:link {color:#0000EE;text-decoration:none;}" +
1574        " A:visited {color:#0000EE;text-decoration:none;}" +
1575        " A:hover {color:#0000EE;text-decoration:underline;}" +
1576        
1577        " TABLE." + CSS_CLS_NOLEFT + " {border-width:0 0 1px 0;}" +
1578        " TABLE." + CSS_SOURCE + " {border-width:1px 0 1px 1px;}" +
1579        
1580// " TD {border-width: 0px 1px 0px 0px; }" +
1581
" TD." + CSS_DATA_HIGHLIGHT + " {color:red;border-width:0 1px 0 0;}" +
1582        " TD." + CSS_DATA_FIRST + " {border-width:0 1px 0 1px;}" +
1583        " TD." + CSS_DATA_HIGHLIGHT_FIRST + " {color:red;border-width:0 1px 0 1px;}" +
1584
1585// " TH {border-width: 1px 1px 1px 0px; }" +
1586
" TH." + CSS_HEADER_FIRST + " {border-width:1px 1px 1px 1px;}" +
1587
1588        " TR." + CSS_CLASS_ITEM_SPECIAL + " TD {background:" + DARKER_BACKGROUND + ";}" +
1589        " TR." + CSS_CLASS_ITEM_SPECIAL + " TD {border-width:1px 1px 1px 0;}" +
1590        " TR." + CSS_CLASS_ITEM_SPECIAL + " TD." + CSS_DATA_HIGHLIGHT + " {color:red;border-width:1px 1px 1px 0;}" +
1591        " TR." + CSS_CLASS_ITEM_SPECIAL + " TD." + CSS_DATA_FIRST + " {border-width:1px 1px 1px 1px;}" +
1592        " TR." + CSS_CLASS_ITEM_SPECIAL + " TD." + CSS_DATA_HIGHLIGHT_FIRST + " {color:red;border-width:1px 1px 1px 1px;}" +
1593        
1594        " TD." + CSS_BLANK + " {border-style:none;background:transparent;line-height:50%;} " +
1595        " TD." + CSS_BOTTOM + " {border-width:1px 0 0 0;background:transparent;line-height:50%;}" +
1596        " TR." + CSS_ODDROW + " TD {background:" + DARKER_BACKGROUND + ";}" +
1597        
1598        "TABLE." + CSS_INVISIBLE_TABLE + " {border-style:none;}" +
1599        "TABLE." + CSS_INVISIBLE_TABLE + " TD,TABLE." + CSS_INVISIBLE_TABLE + " TH {border-style:none;}" +
1600        
1601        "";
1602
1603    private static final String JavaDoc NESTED_ITEMS_PARENT_DIRNAME = "_files";
1604    private static final File JavaDoc NESTED_ITEMS_PARENT_DIR = new File JavaDoc (NESTED_ITEMS_PARENT_DIRNAME);
1605    private static final int [][] NESTING; // set in <clinit>; this reflects the dir structure for the report
1606

1607    private static final String JavaDoc FILE_EXTENSION = ".html";
1608    private static final int IO_BUF_SIZE = 32 * 1024;
1609    
1610    private static final long [] ATTRIBUTE_SETS; // set in <clinit>
1611

1612    static
1613    {
1614        final IItemMetadata [] allTypes = IItemMetadata.Factory.getAllTypes ();
1615        
1616        ATTRIBUTE_SETS = new long [allTypes.length];
1617        for (int t = 0; t < allTypes.length; ++ t)
1618        {
1619            ATTRIBUTE_SETS [allTypes [t].getTypeID ()] = allTypes [t].getAttributeIDs ();
1620        }
1621        
1622        NESTING = new int [4][4];
1623        
1624        int base = AllItem.getTypeMetadata().getTypeID ();
1625        NESTING [base][PackageItem.getTypeMetadata ().getTypeID ()] = 1;
1626        NESTING [base][SrcFileItem.getTypeMetadata ().getTypeID ()] = 1;
1627        NESTING [base][ClassItem.getTypeMetadata ().getTypeID ()] = 1;
1628        
1629        base = PackageItem.getTypeMetadata().getTypeID ();
1630        NESTING [base][AllItem.getTypeMetadata ().getTypeID ()] = -1;
1631        
1632        base = SrcFileItem.getTypeMetadata().getTypeID ();
1633        NESTING [base][AllItem.getTypeMetadata ().getTypeID ()] = -1;
1634        
1635        base = ClassItem.getTypeMetadata().getTypeID ();
1636        NESTING [base][AllItem.getTypeMetadata ().getTypeID ()] = -1;
1637    }
1638
1639} // end of class
1640
// ----------------------------------------------------------------------------
1641
Popular Tags