KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jdiff > HTMLReportGenerator


1 package jdiff;
2
3 import java.util.*;
4 import java.io.*;
5
6 /**
7  * Emit HTML based on the changes between two sets of APIs.
8  *
9  * See the file LICENSE.txt for copyright details.
10  * @author Matthew Doar, doar@pobox.com
11  */

12 public class HTMLReportGenerator {
13
14     /** Default constructor. */
15     public HTMLReportGenerator() {
16     }
17
18     /** The Comments object for existing comments. */
19     private Comments existingComments_ = null;
20
21     /**
22      * The Comments object for freshly regenerated comments.
23      * This is populated during the generation of the report,
24      * and should be like existingComments_ but with unused comments
25      * marked as such, so that they can be commented out in XML when
26      * the new comments are written out to the comments file.
27      */

28     private Comments newComments_ = null;
29
30     /**
31      * Accessor method for the freshly generated Comments object.
32      * The list of comments is sorted before the object is returned.
33      */

34     public Comments getNewComments() {
35         Collections.sort(newComments_.commentsList_);
36         return newComments_;
37     }
38
39     /** Generate the report. */
40     public void generate(APIComparator comp, Comments existingComments) {
41         String JavaDoc fullReportFileName = reportFileName;
42         if (outputDir != null)
43             fullReportFileName = outputDir + JDiff.DIR_SEP + reportFileName;
44         System.out.println("JDiff: generating HTML report into the file '" + fullReportFileName + reportFileExt + "' and the subdirectory '" + fullReportFileName + "'");
45         // May be null if no comments file exists yet
46
existingComments_ = existingComments;
47         // Where the new comments will be placed
48
newComments_ = new Comments();
49         // Writing to multiple files, so make sure the subdirectory exists
50
File opdir = new File(fullReportFileName);
51         if (!opdir.mkdir() && !opdir.exists()) {
52             System.out.println("Error: could not create the subdirectory '" + fullReportFileName + "'");
53             System.exit(3);
54         }
55
56         // Emit the documentation difference files
57
if (!Diff.noDocDiffs) {
58             // Documentation differences, one file per package
59
Diff.emitDocDiffs(fullReportFileName);
60         }
61
62         // This is the top-level summary file, first in the right hand frame
63
// or linked at the start to if no frames are used.
64
String JavaDoc changesSummaryName = fullReportFileName + JDiff.DIR_SEP +
65             reportFileName + "-summary" + reportFileExt;
66         apiDiff = comp.apiDiff;
67         try {
68             FileOutputStream fos = new FileOutputStream(changesSummaryName);
69             reportFile = new PrintWriter(fos);
70             writeStartHTMLHeader();
71             // Write out the title in he HTML header
72
String JavaDoc oldAPIName = "Old API";
73             if (apiDiff.oldAPIName_ != null)
74                 oldAPIName = apiDiff.oldAPIName_;
75             String JavaDoc newAPIName = "New API";
76             if (apiDiff.newAPIName_ != null)
77                 newAPIName = apiDiff.newAPIName_;
78             if (windowTitle == null)
79                 writeHTMLTitle("API Differences between " + oldAPIName + " and " + newAPIName);
80             else
81                 writeHTMLTitle(windowTitle);
82             writeStyleSheetRef();
83             writeText("</HEAD>");
84             writeText("<BODY>");
85
86             // Add the nav bar for the summary page
87
writeNavigationBar(reportFileName + "-summary", null, null,
88                                null, 0, true,
89                                apiDiff.packagesRemoved.size() != 0,
90                                apiDiff.packagesAdded.size() != 0,
91                                apiDiff.packagesChanged.size() != 0);
92             
93             // Write the title in the body with some formatting
94
if (docTitle == null) {
95                 writeText("<center>");
96                 writeText("<H1>API Differences</H1>");
97                 writeText("</center>");
98                 writeText("<center>");
99                 writeText("<H2>Between " + oldAPIName + " and " + newAPIName + "</H2>");
100                 writeText("</center>");
101             } else {
102                 writeText(docTitle);
103             }
104
105             // Write the contents and the other files as well
106
writeReport(apiDiff);
107             writeHTMLFooter();
108             reportFile.close();
109         } catch(IOException e) {
110             System.out.println("IO Error while attempting to create " + changesSummaryName);
111             System.out.println("Error: " + e.getMessage());
112             System.exit(1);
113         }
114
115         // Now generate all the other files for multiple frames.
116
//
117
// The top-level changes.html frames file where everything starts.
118
String JavaDoc tln = fullReportFileName + reportFileExt;
119         // The file for the top-left frame.
120
String JavaDoc tlf = fullReportFileName + JDiff.DIR_SEP +
121             "jdiff_topleftframe" + reportFileExt;
122         // The default file for the bottom-left frame is the one with the
123
// most information in it.
124
String JavaDoc allDiffsIndexName = fullReportFileName + JDiff.DIR_SEP +
125             "alldiffs_index";
126         // Other indexes for the bottom-left frame.
127
String JavaDoc packagesIndexName = fullReportFileName + JDiff.DIR_SEP +
128             "packages_index";
129         String JavaDoc classesIndexName = fullReportFileName + JDiff.DIR_SEP +
130             "classes_index";
131         String JavaDoc constructorsIndexName = fullReportFileName + JDiff.DIR_SEP +
132             "constructors_index";
133         String JavaDoc methodsIndexName = fullReportFileName + JDiff.DIR_SEP +
134             "methods_index";
135         String JavaDoc fieldsIndexName = fullReportFileName + JDiff.DIR_SEP +
136             "fields_index";
137
138         HTMLFiles hf = new HTMLFiles(this);
139         hf.emitTopLevelFile(tln, apiDiff);
140         hf.emitTopLeftFile(tlf);
141         hf.emitHelp(fullReportFileName, apiDiff);
142         hf.emitStylesheet();
143
144         HTMLIndexes h = new HTMLIndexes(this);
145         h.emitAllBottomLeftFiles(packagesIndexName, classesIndexName,
146                             constructorsIndexName, methodsIndexName,
147                             fieldsIndexName, allDiffsIndexName, apiDiff);
148
149         if (doStats) {
150             // The file for the statistical report.
151
String JavaDoc sf = fullReportFileName + JDiff.DIR_SEP +
152                 "jdiff_statistics" + reportFileExt;
153             HTMLStatistics stats = new HTMLStatistics(this);
154             stats.emitStatistics(sf, apiDiff);
155         }
156     }
157
158     /**
159      * Write the HTML report.
160      *
161      * The top section describes all the packages added (with links) and
162      * removed, and the changed packages section has links which takes you
163      * to a section for each package. This pattern continues for classes and
164      * constructors, methods and fields.
165      */

166     public void writeReport(APIDiff apiDiff) {
167
168         // Report packages which were removed in the new API
169
if (apiDiff.packagesRemoved.size() != 0) {
170             writeTableStart("Removed Packages", 2);
171             Iterator iter = apiDiff.packagesRemoved.iterator();
172             while (iter.hasNext()) {
173                 PackageAPI pkgAPI = (PackageAPI)(iter.next());
174                 String JavaDoc pkgName = pkgAPI.name_;
175                 if (trace) System.out.println("Package " + pkgName + " was removed.");
176                 writePackageTableEntry(pkgName, 0, pkgAPI.doc_, false);
177             }
178             writeTableEnd();
179         }
180         
181         // Report packages which were added in the new API
182
if (apiDiff.packagesAdded.size() != 0) {
183             writeTableStart("Added Packages", 2);
184             Iterator iter = apiDiff.packagesAdded.iterator();
185             while (iter.hasNext()) {
186                 PackageAPI pkgAPI = (PackageAPI)(iter.next());
187                 String JavaDoc pkgName = pkgAPI.name_;
188                 if (trace) System.out.println("Package " + pkgName + " was added.");
189                 writePackageTableEntry(pkgName, 1, pkgAPI.doc_, false);
190             }
191             writeTableEnd();
192         }
193
194         // Report packages which were changed in the new API
195
if (apiDiff.packagesChanged.size() != 0) {
196             // Emit a table of changed packages, with links to the file
197
// for each package.
198
writeTableStart("Changed Packages", 3);
199             Iterator iter = apiDiff.packagesChanged.iterator();
200             while (iter.hasNext()) {
201                 PackageDiff pkgDiff = (PackageDiff)(iter.next());
202                 String JavaDoc pkgName = pkgDiff.name_;
203                 if (trace) System.out.println("Package " + pkgName + " was changed.");
204                 writePackageTableEntry(pkgName, 2, null, false);
205             }
206             writeTableEnd();
207             writeText("<!-- End of API section -->");
208
209             // Now emit a separate file for each changed package.
210
writeText("<!-- Start of packages section -->");
211             PackageDiff[] pkgDiffs = new PackageDiff[apiDiff.packagesChanged.size()];
212             pkgDiffs = (PackageDiff[])apiDiff.packagesChanged.toArray(pkgDiffs);
213             for (int i = 0; i < pkgDiffs.length; i++) {
214                 reportChangedPackage(pkgDiffs, i);
215             }
216         }
217     }
218     
219     /**
220      * Write out the details of a changed package in a separate file.
221      */

222     public void reportChangedPackage(PackageDiff[] pkgDiffs, int pkgIndex) {
223         PackageDiff pkgDiff = pkgDiffs[pkgIndex];
224         String JavaDoc pkgName = pkgDiff.name_;
225
226         PrintWriter oldReportFile = null;
227         oldReportFile = reportFile;
228         String JavaDoc localReportFileName = null;
229         try {
230             // Prefix package files with pkg_ because there may be a class
231
// with the same name.
232
localReportFileName = reportFileName + JDiff.DIR_SEP + "pkg_" + pkgName + reportFileExt;
233             if (outputDir != null)
234                 localReportFileName = outputDir + JDiff.DIR_SEP + localReportFileName;
235             FileOutputStream fos = new FileOutputStream(localReportFileName);
236             reportFile = new PrintWriter(fos);
237             writeStartHTMLHeader();
238             writeHTMLTitle(pkgName);
239             writeStyleSheetRef();
240             writeText("</HEAD>");
241             writeText("<BODY>");
242         } catch(IOException e) {
243             System.out.println("IO Error while attempting to create " + localReportFileName);
244             System.out.println("Error: "+ e.getMessage());
245             System.exit(1);
246         }
247
248         String JavaDoc pkgRef = pkgName;
249         pkgRef = pkgRef.replace('.', '/');
250         pkgRef = newDocPrefix + pkgRef + "/package-summary";
251         // A link to the package in the new API
252
String JavaDoc linkedPkgName = "<A HREF=\"" + pkgRef + ".html\" target=\"_top\"><tt>" + pkgName + "</tt></A>";
253         String JavaDoc prevPkgRef = null;
254         if (pkgIndex != 0) {
255             prevPkgRef = "pkg_" + pkgDiffs[pkgIndex-1].name_ + reportFileExt;
256         }
257         // Create the HTML link to the next package
258
String JavaDoc nextPkgRef = null;
259         if (pkgIndex < pkgDiffs.length - 1) {
260             nextPkgRef = "pkg_" + pkgDiffs[pkgIndex+1].name_ + reportFileExt;
261         }
262         
263         writeSectionHeader("Package " + linkedPkgName, pkgName,
264                            prevPkgRef, nextPkgRef,
265                            null, 1,
266                            pkgDiff.classesRemoved.size() != 0,
267                            pkgDiff.classesAdded.size() != 0,
268                            pkgDiff.classesChanged.size() != 0);
269
270         // Report changes in documentation
271
if (reportDocChanges && pkgDiff.documentationChange_ != null) {
272             String JavaDoc pkgDocRef = pkgName + "/package-summary";
273             pkgDocRef = pkgDocRef.replace('.', '/');
274             String JavaDoc oldPkgRef = pkgDocRef;
275             String JavaDoc newPkgRef = pkgDocRef;
276             if (oldDocPrefix != null)
277                 oldPkgRef = oldDocPrefix + oldPkgRef;
278             else
279                 oldPkgRef = null;
280             newPkgRef = newDocPrefix + newPkgRef;
281             if (oldPkgRef != null)
282                 pkgDiff.documentationChange_ += "<A HREF=\"" + oldPkgRef +
283                     ".html#package_description\" target=\"_self\"><tt>old</tt></A> to ";
284             else
285                 pkgDiff.documentationChange_ += "<tt>old</tt> to ";
286             pkgDiff.documentationChange_ += "<A HREF=\"" + newPkgRef +
287                 ".html#package_description\" target=\"_self\"><tt>new</tt></A>. ";
288             writeText(pkgDiff.documentationChange_);
289         }
290
291         // Report classes which were removed in the new API
292
if (pkgDiff.classesRemoved.size() != 0) {
293             // Determine the title for this section
294
boolean hasClasses = false;
295             boolean hasInterfaces = false;
296             Iterator iter = pkgDiff.classesRemoved.iterator();
297             while (iter.hasNext()) {
298                 ClassAPI classAPI = (ClassAPI)(iter.next());
299                 if (classAPI.isInterface_)
300                     hasInterfaces = true;
301                 else
302                     hasClasses = true;
303             }
304             if (hasInterfaces && hasClasses)
305                 writeTableStart("Removed Classes and Interfaces", 2);
306             else if (!hasInterfaces && hasClasses)
307                      writeTableStart("Removed Classes", 2);
308             else if (hasInterfaces && !hasClasses)
309                      writeTableStart("Removed Interfaces", 2);
310             // Emit the table entries
311
iter = pkgDiff.classesRemoved.iterator();
312             while (iter.hasNext()) {
313                 ClassAPI classAPI = (ClassAPI)(iter.next());
314                 String JavaDoc className = classAPI.name_;
315                 if (trace) System.out.println("Class/Interface " + className + " was removed.");
316                 writeClassTableEntry(pkgName, className, 0, classAPI.isInterface_, classAPI.doc_, false);
317             }
318             writeTableEnd();
319         }
320         
321         // Report classes which were added in the new API
322
if (pkgDiff.classesAdded.size() != 0) {
323             // Determine the title for this section
324
boolean hasClasses = false;
325             boolean hasInterfaces = false;
326             Iterator iter = pkgDiff.classesAdded.iterator();
327             while (iter.hasNext()) {
328                 ClassAPI classAPI = (ClassAPI)(iter.next());
329                 if (classAPI.isInterface_)
330                     hasInterfaces = true;
331                 else
332                     hasClasses = true;
333             }
334             if (hasInterfaces && hasClasses)
335                 writeTableStart("Added Classes and Interfaces", 2);
336             else if (!hasInterfaces && hasClasses)
337                      writeTableStart("Added Classes", 2);
338             else if (hasInterfaces && !hasClasses)
339                      writeTableStart("Added Interfaces", 2);
340             // Emit the table entries
341
iter = pkgDiff.classesAdded.iterator();
342             while (iter.hasNext()) {
343                 ClassAPI classAPI = (ClassAPI)(iter.next());
344                 String JavaDoc className = classAPI.name_;
345                 if (trace) System.out.println("Class/Interface " + className + " was added.");
346                 writeClassTableEntry(pkgName, className, 1, classAPI.isInterface_, classAPI.doc_, false);
347             }
348             writeTableEnd();
349         }
350
351         // Report classes which were changed in the new API
352
if (pkgDiff.classesChanged.size() != 0) {
353             // Determine the title for this section
354
boolean hasClasses = false;
355             boolean hasInterfaces = false;
356             Iterator iter = pkgDiff.classesChanged.iterator();
357             while (iter.hasNext()) {
358                 ClassDiff classDiff = (ClassDiff)(iter.next());
359                 if (classDiff.isInterface_)
360                     hasInterfaces = true;
361                 else
362                     hasClasses = true;
363             }
364             if (hasInterfaces && hasClasses)
365                 writeTableStart("Changed Classes and Interfaces", 2);
366             else if (!hasInterfaces && hasClasses)
367                      writeTableStart("Changed Classes", 2);
368             else if (hasInterfaces && !hasClasses)
369                      writeTableStart("Changed Interfaces", 2);
370             // Emit a table of changed classes, with links to the file
371
// for each class.
372
iter = pkgDiff.classesChanged.iterator();
373             while (iter.hasNext()) {
374                 ClassDiff classDiff = (ClassDiff)(iter.next());
375                 String JavaDoc className = classDiff.name_;
376                 if (trace) System.out.println("Package " + pkgDiff.name_ + ", class/Interface " + className + " was changed.");
377                 writeClassTableEntry(pkgName, className, 2, classDiff.isInterface_, null, false);
378             }
379             writeTableEnd();
380             // Now emit a separate file for each changed class and interface.
381
ClassDiff[] classDiffs = new ClassDiff[pkgDiff.classesChanged.size()];
382             classDiffs = (ClassDiff[])pkgDiff.classesChanged.toArray(classDiffs);
383             for (int k = 0; k < classDiffs.length; k++) {
384                 reportChangedClass(pkgName, classDiffs, k);
385             }
386         }
387         
388         writeSectionFooter(pkgName, prevPkgRef, nextPkgRef, null, 1);
389         writeHTMLFooter();
390         reportFile.close();
391         reportFile = oldReportFile;
392     }
393
394     /**
395      * Write out the details of a changed class in a separate file.
396      */

397     public void reportChangedClass(String JavaDoc pkgName, ClassDiff[] classDiffs, int classIndex) {
398         ClassDiff classDiff = classDiffs[classIndex];
399         String JavaDoc className = classDiff.name_;
400
401         PrintWriter oldReportFile = null;
402         oldReportFile = reportFile;
403         String JavaDoc localReportFileName = null;
404         try {
405             localReportFileName = reportFileName + JDiff.DIR_SEP + pkgName + "." + className + reportFileExt;
406             if (outputDir != null)
407                 localReportFileName = outputDir + JDiff.DIR_SEP + localReportFileName;
408             FileOutputStream fos = new FileOutputStream(localReportFileName);
409             reportFile = new PrintWriter(fos);
410             writeStartHTMLHeader();
411             writeHTMLTitle(pkgName + "." + className);
412             writeStyleSheetRef();
413             writeText("</HEAD>");
414             writeText("<BODY>");
415         } catch(IOException e) {
416             System.out.println("IO Error while attempting to create " + localReportFileName);
417             System.out.println("Error: "+ e.getMessage());
418             System.exit(1);
419         }
420
421         String JavaDoc classRef = pkgName + "." + className;
422         classRef = classRef.replace('.', '/');
423         if (className.indexOf('.') != -1) {
424             classRef = pkgName + ".";
425             classRef = classRef.replace('.', '/');
426             classRef = newDocPrefix + classRef + className;
427         } else {
428             classRef = newDocPrefix + classRef;
429         }
430         // A link to the class in the new API
431
String JavaDoc linkedClassName = "<A HREF=\"" + classRef + ".html\" target=\"_top\"><tt>" + className + "</tt></A>";
432         String JavaDoc lcn = pkgName + "." + linkedClassName;
433         //Links to the previous and next classes
434
String JavaDoc prevClassRef = null;
435         if (classIndex != 0) {
436             prevClassRef = pkgName + "." + classDiffs[classIndex-1].name_ + reportFileExt;
437         }
438         // Create the HTML link to the next package
439
String JavaDoc nextClassRef = null;
440         if (classIndex < classDiffs.length - 1) {
441             nextClassRef = pkgName + "." + classDiffs[classIndex+1].name_ + reportFileExt;
442         }
443
444         if (classDiff.isInterface_)
445             lcn = "Interface " + lcn;
446         else
447             lcn = "Class " + lcn;
448         boolean hasCtors = classDiff.ctorsRemoved.size() != 0 ||
449             classDiff.ctorsAdded.size() != 0 ||
450             classDiff.ctorsChanged.size() != 0;
451         boolean hasMethods = classDiff.methodsRemoved.size() != 0 ||
452             classDiff.methodsAdded.size() != 0 ||
453             classDiff.methodsChanged.size() != 0;
454         boolean hasFields = classDiff.fieldsRemoved.size() != 0 ||
455             classDiff.fieldsAdded.size() != 0 ||
456             classDiff.fieldsChanged.size() != 0;
457         writeSectionHeader(lcn, pkgName, prevClassRef, nextClassRef,
458                            className, 2,
459                            hasCtors, hasMethods, hasFields);
460
461         if (classDiff.inheritanceChange_ != null)
462             writeText("<p><font size=\"+1\">" + classDiff.inheritanceChange_ + "</font>");
463
464         // Report changes in documentation
465
if (reportDocChanges && classDiff.documentationChange_ != null) {
466             String JavaDoc oldClassRef = null;
467             if (oldDocPrefix != null) {
468                 oldClassRef = pkgName + "." + className;
469                 oldClassRef = oldClassRef.replace('.', '/');
470                 if (className.indexOf('.') != -1) {
471                     oldClassRef = pkgName + ".";
472                     oldClassRef = oldClassRef.replace('.', '/');
473                     oldClassRef = oldDocPrefix + oldClassRef + className;
474                 } else {
475                     oldClassRef = oldDocPrefix + oldClassRef;
476                 }
477             }
478             if (oldDocPrefix != null)
479                 classDiff.documentationChange_ += "<A HREF=\"" + oldClassRef +
480                     ".html\" target=\"_self\"><tt>old</tt></A> to ";
481             else
482                 classDiff.documentationChange_ += "<tt>old</tt> to ";
483             classDiff.documentationChange_ += "<A HREF=\"" + classRef +
484                 ".html\" target=\"_self\"><tt>new</tt></A>. ";
485             writeText(classDiff.documentationChange_);
486         }
487
488         if (classDiff.modifiersChange_ != null)
489             writeText("<p><font size=\"+1\">" + classDiff.modifiersChange_ + "</font>");
490
491         reportAllCtors(pkgName, classDiff);
492         reportAllMethods(pkgName, classDiff);
493         reportAllFields(pkgName, classDiff);
494
495         writeSectionFooter(pkgName, prevClassRef, nextClassRef, className, 2);
496         writeHTMLFooter();
497         reportFile.close();
498         reportFile = oldReportFile;
499     }
500
501     /**
502      * Write out the details of constructors in a class.
503      */

504     public void reportAllCtors(String JavaDoc pkgName, ClassDiff classDiff) {
505         String JavaDoc className = classDiff.name_;
506         writeText("<a NAME=\"constructors\"></a>"); // Named anchor
507
// Report ctors which were removed in the new API
508
if (classDiff.ctorsRemoved.size() != 0) {
509             writeTableStart("Removed Constructors", 2);
510             Iterator iter = classDiff.ctorsRemoved.iterator();
511             while (iter.hasNext()) {
512                 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next());
513                 String JavaDoc ctorType = ctorAPI.type_;
514                 if (ctorType.compareTo("void") == 0)
515                     ctorType = "";
516                 String JavaDoc id = className + "(" + ctorType + ")";
517                 if (trace) System.out.println("Constructor " + id + " was removed.");
518                 writeCtorTableEntry(pkgName, className, ctorType, 0, ctorAPI.doc_, false);
519             }
520             writeTableEnd();
521         }
522
523         // Report ctors which were added in the new API
524
if (classDiff.ctorsAdded.size() != 0) {
525             writeTableStart("Added Constructors", 2);
526             Iterator iter = classDiff.ctorsAdded.iterator();
527             while (iter.hasNext()) {
528                 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next());
529                 String JavaDoc ctorType = ctorAPI.type_;
530                 if (ctorType.compareTo("void") == 0)
531                     ctorType = "";
532                 String JavaDoc id = className + "(" + ctorType + ")";
533                 if (trace) System.out.println("Constructor " + id + " was added.");
534                 writeCtorTableEntry(pkgName, className, ctorType, 1, ctorAPI.doc_, false);
535             }
536             writeTableEnd();
537         }
538         
539         // Report ctors which were changed in the new API
540
if (classDiff.ctorsChanged.size() != 0) {
541             // Emit a table of changed classes, with links to the section
542
// for each class.
543
writeTableStart("Changed Constructors", 3);
544             Iterator iter = classDiff.ctorsChanged.iterator();
545             while (iter.hasNext()) {
546                 MemberDiff memberDiff = (MemberDiff)(iter.next());
547                 if (trace) System.out.println("Constructor for " + className +
548                     " was changed from " + memberDiff.oldType_ + " to " +
549                     memberDiff.newType_);
550                 writeCtorChangedTableEntry(pkgName, className, memberDiff);
551             }
552             writeTableEnd();
553         }
554     }
555
556     /**
557      * Write out the details of methods in a class.
558      */

559     public void reportAllMethods(String JavaDoc pkgName, ClassDiff classDiff) {
560         writeText("<a NAME=\"methods\"></a>"); // Named anchor
561
String JavaDoc className = classDiff.name_;
562         // Report methods which were removed in the new API
563
if (classDiff.methodsRemoved.size() != 0) {
564             writeTableStart("Removed Methods", 2);
565             Iterator iter = classDiff.methodsRemoved.iterator();
566             while (iter.hasNext()) {
567                 MethodAPI methodAPI = (MethodAPI)(iter.next());
568                 String JavaDoc methodName = methodAPI.name_ + "(" + methodAPI.getSignature() + ")";
569                 if (trace) System.out.println("Method " + methodName + " was removed.");
570                 writeMethodTableEntry(pkgName, className, methodAPI, 0, methodAPI.doc_, false);
571             }
572             writeTableEnd();
573         }
574
575         // Report methods which were added in the new API
576
if (classDiff.methodsAdded.size() != 0) {
577             writeTableStart("Added Methods", 2);
578             Iterator iter = classDiff.methodsAdded.iterator();
579             while (iter.hasNext()) {
580                 MethodAPI methodAPI = (MethodAPI)(iter.next());
581                 String JavaDoc methodName = methodAPI.name_ + "(" + methodAPI.getSignature() + ")";
582                 if (trace) System.out.println("Method " + methodName + " was added.");
583                 writeMethodTableEntry(pkgName, className, methodAPI, 1, methodAPI.doc_, false);
584             }
585             writeTableEnd();
586         }
587         
588         // Report methods which were changed in the new API
589
if (classDiff.methodsChanged.size() != 0) {
590             // Emit a table of changed methods.
591
writeTableStart("Changed Methods", 3);
592             Iterator iter = classDiff.methodsChanged.iterator();
593             while (iter.hasNext()) {
594                 MemberDiff memberDiff = (MemberDiff)(iter.next());
595                 if (trace) System.out.println("Method " + memberDiff.name_ +
596                       " was changed.");
597                 writeMethodChangedTableEntry(pkgName, className, memberDiff);
598             }
599             writeTableEnd();
600         }
601     }
602
603     /**
604      * Write out the details of fields in a class.
605      */

606     public void reportAllFields(String JavaDoc pkgName, ClassDiff classDiff) {
607         writeText("<a NAME=\"fields\"></a>"); // Named anchor
608
String JavaDoc className = classDiff.name_;
609         // Report fields which were removed in the new API
610
if (classDiff.fieldsRemoved.size() != 0) {
611             writeTableStart("Removed Fields", 2);
612             Iterator iter = classDiff.fieldsRemoved.iterator();
613             while (iter.hasNext()) {
614                 FieldAPI fieldAPI = (FieldAPI)(iter.next());
615                 String JavaDoc fieldName = fieldAPI.name_;
616                 if (trace) System.out.println("Field " + fieldName + " was removed.");
617                 writeFieldTableEntry(pkgName, className, fieldAPI, 0, fieldAPI.doc_, false);
618             }
619             writeTableEnd();
620         }
621         
622         // Report fields which were added in the new API
623
if (classDiff.fieldsAdded.size() != 0) {
624             writeTableStart("Added Fields", 2);
625             Iterator iter = classDiff.fieldsAdded.iterator();
626             while (iter.hasNext()) {
627                 FieldAPI fieldAPI = (FieldAPI)(iter.next());
628                 String JavaDoc fieldName = fieldAPI.name_;
629                 if (trace) System.out.println("Field " + fieldName + " was added.");
630                 writeFieldTableEntry(pkgName, className, fieldAPI, 1, fieldAPI.doc_, false);
631             }
632             writeTableEnd();
633         }
634         
635         // Report fields which were changed in the new API
636
if (classDiff.fieldsChanged.size() != 0) {
637             // Emit a table of changed classes, with links to the section
638
// for each class.
639
writeTableStart("Changed Fields", 3);
640             Iterator iter = classDiff.fieldsChanged.iterator();
641             while (iter.hasNext()) {
642                 MemberDiff memberDiff = (MemberDiff)(iter.next());
643                 if (trace) System.out.println("Field " + pkgName + "." + className + "." + memberDiff.name_ + " was changed from " + memberDiff.oldType_ + " to " + memberDiff.newType_);
644                 writeFieldChangedTableEntry(pkgName, className, memberDiff);
645             }
646             writeTableEnd();
647         }
648         
649     }
650
651     /**
652      * Write the start of the HTML header, together with the current
653      * date and time in an HTML comment.
654      */

655     public void writeStartHTMLHeaderWithDate() {
656         writeStartHTMLHeader(true);
657     }
658
659     /** Write the start of the HTML header. */
660     public void writeStartHTMLHeader() {
661         writeStartHTMLHeader(false);
662     }
663
664     /** Write the start of the HTML header. */
665     public void writeStartHTMLHeader(boolean addDate) {
666         writeText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">");
667         writeText("<HTML>");
668         writeText("<HEAD>");
669         writeText("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">");
670         writeText("<!-- Generated by the JDiff Javadoc doclet -->");
671         writeText("<!-- (" + JDiff.jDiffLocation + ") -->");
672         if (addDate)
673             writeText("<!-- on " + new Date() + " -->");
674         writeText("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">");
675         writeText("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">");
676     }
677
678     /** Write the HTML title */
679     public void writeHTMLTitle(String JavaDoc title) {
680         writeText("<TITLE>");
681         writeText(title);
682         writeText("</TITLE>");
683     }
684
685     /**
686      * Write the HTML style sheet reference for files in the subdirectory.
687      */

688     public void writeStyleSheetRef() {
689         writeStyleSheetRef(false);
690     }
691
692     /**
693      * Write the HTML style sheet reference. If inSameDir is set, don't add
694      * "../" to the location.
695      */

696     public void writeStyleSheetRef(boolean inSameDir) {
697         if (inSameDir)
698             writeText("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"stylesheet-jdiff.css\" TITLE=\"Style\">");
699         else
700             writeText("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + "../" + "stylesheet-jdiff.css\" TITLE=\"Style\">");
701 // This doesn't work in non-windows browsers, so have to change the stylesheet
702
// writeText("<!-- Override the color choice for the navigation bar -->");
703
// writeText("<STYLE>");
704
// //writeText(".NavBarCell1 { background-color:#FFFF99;} /* palegoldenrod */");
705
// writeText(".NavBarCell1 { background-color:#FFFFCC;} /* */");
706
// writeText("</STYLE>");
707
}
708
709     /** Write the HTML footer. */
710     public void writeHTMLFooter() {
711         writeText("</BODY>");
712         writeText("</HTML>");
713     }
714
715     /**
716      * Write a section header, which includes a navigation bar.
717      *
718      * @param title Title of the header. Contains any links necessary.
719      * @param packageName The name of the current package, with no slashes or
720      * links in it. May be null
721      * @param prevElemLink An HTML link to the previous element (a package or
722      * class). May be null.
723      * @param nextElemLink An HTML link to the next element (a package or
724      * class). May be null.
725      * @param className The name of the current class, with no slashes or
726      * links in it. May be null.
727      * @param level 0 = overview, 1 = package, 2 = class/interface
728      */

729     public void writeSectionHeader(String JavaDoc title, String JavaDoc packageName,
730                                    String JavaDoc prevElemLink, String JavaDoc nextElemLink,
731                                    String JavaDoc className, int level,
732                                    boolean hasRemovals,
733                                    boolean hasAdditions,
734                                    boolean hasChanges) {
735         writeNavigationBar(packageName, prevElemLink, nextElemLink,
736                            className, level, true,
737                            hasRemovals, hasAdditions, hasChanges);
738         if (level != 0) {
739             reportFile.println("<H2>");
740             reportFile.println(title);
741             reportFile.println("</H2>");
742         }
743     }
744     
745     /**
746      * Write a section footer, which includes a navigation bar.
747      *
748      * @param packageName The name of the current package, with no slashes or
749      * links in it. may be null
750      * @param prevElemLink An HTML link to the previous element (a package or
751      * class). May be null.
752      * @param nextElemLink An HTML link to the next element (a package or
753      * class). May be null.
754      * @param className The name of the current class, with no slashes or
755      * links in it. May be null
756      * @param level 0 = overview, 1 = package, 2 = class/interface
757      */

758     public void writeSectionFooter(String JavaDoc packageName,
759                                    String JavaDoc prevElemLink, String JavaDoc nextElemLink,
760                                    String JavaDoc className, int level) {
761         reportFile.println("<HR>");
762         writeNavigationBar(packageName, prevElemLink, nextElemLink,
763                            className, level, false,
764                            false, false, false);
765     }
766     
767     /**
768      * Write a navigation bar section header.
769      *
770      * @param pkgName The name of the current package, with no slashes or
771      * links in it.
772      * @param prevElemLink An HTML link to the previous element (a package or
773      * class). May be null.
774      * @param nextElemLink An HTML link to the next element (a package or
775      * class). May be null.
776      * @param className The name of the current class, with no slashes or
777      * links in it. May be null.
778      * @param level 0 = overview, 1 = package, 2 = class/interface
779      */

780     public void writeNavigationBar(String JavaDoc pkgName,
781                                    String JavaDoc prevElemLink, String JavaDoc nextElemLink,
782                                    String JavaDoc className, int level,
783                                    boolean upperNavigationBar,
784                                    boolean hasRemovals, boolean hasAdditions,
785                                    boolean hasChanges) {
786         reportFile.println("<!-- Start of nav bar -->");
787         reportFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">");
788         reportFile.println(" <TR>");
789         reportFile.println(" <TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">");
790         reportFile.println(" <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">");
791         reportFile.println(" <TR ALIGN=\"center\" VALIGN=\"top\">");
792         boolean atOverview = (level == 0);
793         boolean atPackage = (level == 1);
794         boolean atClass = (level == 2);
795
796         // Always have a link to the Javadoc files
797
if (atOverview) {
798             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + newDocPrefix + "index.html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><tt>" + apiDiff.newAPIName_ + "</tt></B></FONT></A>&nbsp;</TD>");
799         } else if (atPackage) {
800             String JavaDoc pkgRef = pkgName;
801             pkgRef = pkgRef.replace('.', '/');
802             pkgRef = newDocPrefix + pkgRef + "/package-summary";
803             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + pkgRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><tt>" + apiDiff.newAPIName_ + "</tt></B></FONT></A>&nbsp;</TD>");
804         } else if (atClass) {
805             String JavaDoc classRef = pkgName + "." + className;
806             classRef = classRef.replace('.', '/');
807             if (className.indexOf('.') != -1) {
808                 classRef = pkgName + ".";
809                 classRef = classRef.replace('.', '/');
810                 classRef = newDocPrefix + classRef + className;
811             } else {
812                 classRef = newDocPrefix + classRef;
813             }
814             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + classRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><tt>" + apiDiff.newAPIName_ + "</tt></B></FONT></A>&nbsp;</TD>");
815         }
816
817         if (atOverview) {
818             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> &nbsp;<FONT CLASS=\"NavBarFont1Rev\"><B>Overview</B></FONT>&nbsp;</TD>");
819             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Package</FONT>&nbsp;</TD>");
820             reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Class</FONT>&nbsp;</TD>");
821         }
822
823         String JavaDoc changesSummaryName = reportFileName + "-summary" + reportFileExt;
824         if (atPackage) {
825             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + changesSummaryName + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A>&nbsp;</TD>");
826             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> &nbsp;<FONT CLASS=\"NavBarFont1Rev\"><B>Package</B></FONT>&nbsp;</TD>");
827             reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> &nbsp;<FONT CLASS=\"NavBarFont1\">Class</FONT>&nbsp;</TD>");
828         }
829         if (atClass) {
830             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + changesSummaryName + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A>&nbsp;</TD>");
831             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"pkg_" + pkgName + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Package</B></FONT></A>&nbsp;</TD>");
832             reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1Rev\"> &nbsp;<FONT CLASS=\"NavBarFont1Rev\"><B>Class</B></FONT>&nbsp;</TD>");
833         }
834
835         if (!Diff.noDocDiffs) {
836             if (atPackage) {
837                 String JavaDoc id = (String JavaDoc)Diff.firstDiffOutput.get(pkgName + "!package");
838                 if (id != null)
839                     reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "#" + id + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A>&nbsp;</TD>");
840                 else
841                     reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Text Changes</FONT>&nbsp;</TD>");
842             } else if (atClass) {
843                 String JavaDoc id = (String JavaDoc)Diff.firstDiffOutput.get(pkgName + "." + className + "!class");
844                 if (id != null)
845                     reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "#" + id + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A>&nbsp;</TD>");
846                 else
847                     reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Text Changes</FONT>&nbsp;</TD>");
848             } else {
849                 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A>&nbsp;</TD>");
850             }
851         }
852
853         if (doStats) {
854             reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A>&nbsp;</TD>");
855         }
856
857         // Always have a link to the JDiff help file
858
reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A>&nbsp;</TD>");
859         reportFile.println(" </TR>");
860         reportFile.println(" </TABLE>");
861         reportFile.println(" </TD>");
862
863         // The right hand side title, only added at the top
864
if (upperNavigationBar) {
865             reportFile.println(" <TD ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3><EM><b>Generated by<br><a HREF=\"" + JDiff.jDiffLocation + "\" class=\"staysblack\" target=\"_top\">JDiff</a></b></EM></TD>");
866         } else {
867             reportFile.println(" <TD ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3></TD>");
868         }
869         reportFile.println("</TR>");
870
871         // Links for frames and no frames
872
reportFile.println("<TR>");
873
874         // All of the previous and next links, and the frames and non-frames
875
// links are in one table cell
876
reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">");
877         // Display links to the previous and next packages or classes
878
if (atPackage || atClass) {
879             String JavaDoc elemName = "CLASS";
880             if (className == null) {
881                 elemName = "PACKAGE";
882             }
883             if (prevElemLink == null) {
884                 reportFile.println("&nbsp;<B>PREV " + elemName + "</B>&nbsp;");
885             } else {
886                 reportFile.println("&nbsp;<A HREF=\"" + prevElemLink + "\"><B>PREV " + elemName + "</B></A>");
887             }
888             if (nextElemLink == null) {
889                 reportFile.println("&nbsp;<B>NEXT " + elemName + "</B>&nbsp;");
890             } else {
891                 reportFile.println("&nbsp;<A HREF=\"" + nextElemLink + "\"><B>NEXT " + elemName + "</B></A>");
892             }
893             reportFile.println("&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;");
894         } else {
895             reportFile.println(" &nbsp;&nbsp;");
896         }
897         // Links for frames and non-frames.
898
reportFile.println(" <A HREF=\"" + "../" + reportFileName + reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A> &nbsp;");
899         if (className == null) {
900             if (level == 0) {
901                 reportFile.println(" &nbsp;<A HREF=\"" + pkgName + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>");
902             } else {
903                 reportFile.println(" &nbsp;<A HREF=\"pkg_" + pkgName + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>");
904             }
905         } else {
906             reportFile.println(" &nbsp;<A HREF=\"" + pkgName + "." + className + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>");
907         }
908
909         // All of the details links are in one table cell
910
if (atClass) {
911             // Links to a class page's sections
912
// The meaning of these three variable is overloaded
913
boolean hasCtors = hasRemovals;
914             boolean hasMethods = hasAdditions;
915             boolean hasFields = hasChanges;
916             if (hasCtors || hasMethods || hasFields) {
917                 reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell3\"><FONT SIZE=\"-2\"> DETAIL: &nbsp;");
918                 if (hasCtors) {
919                     reportFile.println("<a HREF=\"#constructors\">CONSTRUCTORS</a>&nbsp;|&nbsp;");
920                 } else {
921                     reportFile.println("CONSTRUCTORS&nbsp;|&nbsp;");
922                 }
923                 if (hasMethods) {
924                     reportFile.println("<a HREF=\"#methods\">METHODS</a>&nbsp;|&nbsp;");
925                 } else {
926                     reportFile.println("METHODS&nbsp;|&nbsp;");
927                 }
928                 if (hasFields) {
929                     reportFile.println("<a HREF=\"#fields\">FIELDS</a>");
930                 } else {
931                     reportFile.println("FIELDS");
932                 }
933                 reportFile.println(" </FONT></TD>");
934             } else {
935                 // Make the end of the table line match the length of the top
936
reportFile.println("<TD BGCOLOR=\"0xFFFFFF\" CLASS=\"NavBarCell3\"></TD>");
937             }
938         } else {
939             // Links to a package page's sections
940
if (hasRemovals || hasAdditions || hasChanges) {
941                 reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell3\"><FONT SIZE=\"-2\"> DETAIL: &nbsp;");
942                 if (hasRemovals) {
943                     reportFile.println("<a HREF=\"#Removed\">REMOVED</a>&nbsp;|&nbsp;");
944                 } else {
945                     reportFile.println("REMOVED&nbsp;|&nbsp;");
946                 }
947                 if (hasAdditions) {
948                     reportFile.println("<a HREF=\"#Added\">ADDED</a>&nbsp;|&nbsp;");
949                 } else {
950                     reportFile.println("ADDED&nbsp;|&nbsp;");
951                 }
952                 if (hasChanges) {
953                     reportFile.println("<a HREF=\"#Changed\">CHANGED</a>");
954                 } else {
955                     reportFile.println("CHANGED");
956                 }
957                 reportFile.println(" </FONT></TD>");
958             } else {
959                 // Make the end of the table line match the length of the top
960
reportFile.println("<TD BGCOLOR=\"0xFFFFFF\" CLASS=\"NavBarCell3\"></TD>");
961             }
962         }
963
964         reportFile.println("</TR>");
965         reportFile.println("</TABLE>");
966         reportFile.println("<HR>");
967         reportFile.println("<!-- End of nav bar -->");
968     }
969     
970     /** Write the start of a table. */
971     public void writeTableStart(String JavaDoc title, int colSpan) {
972         reportFile.println("<p>");
973         // Assumes that the first word of the title categorizes the table type
974
// and that there is a space after the first word in the title
975
int idx = title.indexOf(' ');
976         String JavaDoc namedAnchor = title.substring(0, idx);
977         reportFile.println("<a NAME=\"" + namedAnchor + "\"></a>"); // Named anchor
978
reportFile.println("<TABLE summary=\"" + title+ "\" BORDER=\"1\" CELLPADDING=\"3\" CELLSPACING=\"0\" WIDTH=\"100%\">");
979         reportFile.println("<TR BGCOLOR=\"#CCCCFF\" CLASS=\"TableHeadingColor\">");
980         reportFile.print(" <TD VALIGN=\"TOP\" COLSPAN=" + colSpan + "><FONT SIZE=\"+1\">");
981         reportFile.println("<B>" + title + "</B></FONT></TD>");
982         reportFile.println("</TR>");
983     }
984
985     /**
986      * If a class or package name is considered to be too long for convenient
987      * display, insert <br> in the middle of it at a period.
988      */

989     public String JavaDoc makeTwoRows(String JavaDoc name) {
990         if (name.length() < 30)
991             return name;
992         int idx = name.indexOf(".", 20);
993         if (idx == -1)
994             return name;
995         int len = name.length();
996         String JavaDoc res = name.substring(0, idx+1) + "<br>" + name.substring(idx+1, len);
997         return res;
998     }
999
1000    /**
1001     * Write a table entry for a package, with support for links to Javadoc
1002     * for removed packages.
1003     *
1004     * linkType: 0 - no link by default, 1 = link to Javadoc HTML file, 2 = link to JDiff file
1005     */

1006    public void writePackageTableEntry(String JavaDoc pkgName, int linkType,
1007                                       String JavaDoc possibleComment, boolean useOld) {
1008        if (!useOld) {
1009            reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1010            reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1011            reportFile.println(" <A NAME=\"" + pkgName + "\"></A>"); // Named anchor
1012
}
1013        String JavaDoc shownPkgName = makeTwoRows(pkgName);
1014        if (linkType == 0) {
1015            if (oldDocPrefix == null) {
1016                // No link
1017
reportFile.print(" " + shownPkgName);
1018            } else {
1019                // Call this method again but this time to emit a link to the
1020
// old program element.
1021
writePackageTableEntry(pkgName, 1, possibleComment, true);
1022            }
1023        } else if (linkType == 1) {
1024            // Link to HTML file for the package
1025
String JavaDoc pkgRef = pkgName;
1026            pkgRef = pkgRef.replace('.', '/');
1027            if (useOld)
1028                pkgRef = oldDocPrefix + pkgRef + "/package-summary";
1029            else
1030                pkgRef = newDocPrefix + pkgRef + "/package-summary";
1031            reportFile.println(" <nobr><A HREF=\"" + pkgRef + ".html\" target=\"_top\"><tt>" + shownPkgName + "</tt></A></nobr>");
1032        } else if (linkType == 2) {
1033            reportFile.println(" <nobr><A HREF=\"pkg_" + pkgName + reportFileExt + "\">" + shownPkgName + "</A></nobr>");
1034        }
1035        if (!useOld) {
1036            reportFile.println(" </TD>");
1037            emitComment(pkgName, possibleComment, linkType);
1038            reportFile.println("</TR>");
1039        }
1040    }
1041
1042    /**
1043     * Write a table entry for a class or interface.
1044     *
1045     * linkType: 0 - no link by default, 1 = link to Javadoc HTML file, 2 = link to JDiff file
1046     */

1047    public void writeClassTableEntry(String JavaDoc pkgName, String JavaDoc className,
1048                                     int linkType, boolean isInterface,
1049                                     String JavaDoc possibleComment, boolean useOld) {
1050        if (!useOld) {
1051            reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1052            reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1053            reportFile.println(" <A NAME=\"" + className + "\"></A>"); // Named anchor
1054
}
1055        String JavaDoc fqName = pkgName + "." + className;
1056        String JavaDoc shownClassName = makeTwoRows(className);
1057        if (linkType == 0) {
1058            if (oldDocPrefix == null) {
1059                // No link
1060
if (isInterface)
1061                    reportFile.println(" <I>" + shownClassName + "</I>");
1062                else
1063                    reportFile.println(" " + shownClassName);
1064            } else {
1065                writeClassTableEntry(pkgName, className,
1066                                     1, isInterface,
1067                                     possibleComment, true);
1068            }
1069        } else if (linkType == 1) {
1070            // Link to HTML file for the class
1071
String JavaDoc classRef = fqName;
1072            // Deal with inner classes
1073
if (className.indexOf('.') != -1) {
1074                classRef = pkgName + ".";
1075                classRef = classRef.replace('.', '/');
1076                if (useOld)
1077                    classRef = oldDocPrefix + classRef + className;
1078                else
1079                    classRef = newDocPrefix + classRef + className;
1080            } else {
1081                classRef = classRef.replace('.', '/');
1082                if (useOld)
1083                    classRef = oldDocPrefix + classRef;
1084                else
1085                    classRef = newDocPrefix + classRef;
1086            }
1087            reportFile.print(" <nobr><A HREF=\"" + classRef + ".html\" target=\"_top\"><tt>");
1088            if (isInterface)
1089                reportFile.print("<I>" + shownClassName + "</I>");
1090            else
1091                reportFile.print(shownClassName);
1092            reportFile.println("</tt></A></nobr>");
1093        } else if (linkType == 2) {
1094            reportFile.print(" <nobr><A HREF=\"" + fqName + reportFileExt + "\">");
1095            if (isInterface)
1096                reportFile.print("<I>" + shownClassName + "</I>");
1097            else
1098                reportFile.print(shownClassName);
1099            reportFile.println("</A></nobr>");
1100        }
1101        if (!useOld) {
1102            reportFile.println(" </TD>");
1103            emitComment(fqName, possibleComment, linkType);
1104            reportFile.println("</TR>");
1105        }
1106    }
1107
1108    /**
1109     * Write a table entry for a constructor.
1110     *
1111     * linkType: 0 - no link by default, 1 = link to Javadoc HTML file
1112     */

1113    public void writeCtorTableEntry(String JavaDoc pkgName, String JavaDoc className,
1114                                    String JavaDoc type, int linkType,
1115                                    String JavaDoc possibleComment, boolean useOld) {
1116        String JavaDoc fqName = pkgName + "." + className;
1117        String JavaDoc shownClassName = makeTwoRows(className);
1118        String JavaDoc lt = "removed";
1119        if (linkType ==1)
1120            lt = "added";
1121        String JavaDoc commentID = fqName + ".ctor_" + lt + "(" + type + ")";
1122        if (!useOld) {
1123            reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1124            reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1125            reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1126
}
1127        String JavaDoc shortType = simpleName(type);
1128        if (linkType == 0) {
1129            if (oldDocPrefix == null) {
1130                // No link
1131
reportFile.print(" <nobr>" + shownClassName);
1132                emitTypeWithParens(shortType);
1133                reportFile.println("</nobr>");
1134            } else {
1135                writeCtorTableEntry(pkgName, className,
1136                                    type, 1,
1137                                    possibleComment, true);
1138            }
1139        } else if (linkType == 1) {
1140            // Link to HTML file for the package
1141
String JavaDoc memberRef = fqName.replace('.', '/');
1142            // Deal with inner classes
1143
if (className.indexOf('.') != -1) {
1144                memberRef = pkgName + ".";
1145                memberRef = memberRef.replace('.', '/');
1146                if (useOld) {
1147                    // oldDocPrefix is non-null at this point
1148
memberRef = oldDocPrefix + memberRef + className;
1149                } else {
1150                    memberRef = newDocPrefix + memberRef + className;
1151                }
1152            } else {
1153                if (useOld) {
1154                    // oldDocPrefix is non-null at this point
1155
memberRef = oldDocPrefix + memberRef;
1156                } else {
1157                    memberRef = newDocPrefix + memberRef;
1158                }
1159            }
1160            reportFile.print(" <nobr><A HREF=\"" + memberRef + ".html#" + className +
1161                             "(" + type + ")\" target=\"_top\"><tt>" + shownClassName + "</tt></A>");
1162            emitTypeWithParens(shortType);
1163            reportFile.println("</nobr>");
1164        }
1165        if (!useOld) {
1166            reportFile.println(" </TD>");
1167            emitComment(commentID, possibleComment, linkType);
1168            reportFile.println("</TR>");
1169        }
1170    }
1171
1172    /**
1173     * Write a table entry for a changed constructor.
1174     */

1175    public void writeCtorChangedTableEntry(String JavaDoc pkgName, String JavaDoc className,
1176                                           MemberDiff memberDiff) {
1177        String JavaDoc fqName = pkgName + "." + className;
1178        String JavaDoc newSignature = memberDiff.newType_;
1179        if (newSignature.compareTo("void") == 0)
1180            newSignature = "";
1181        String JavaDoc commentID = fqName + ".ctor_changed(" + newSignature + ")";
1182        reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1183        reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1184        reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1185
String JavaDoc memberRef = fqName.replace('.', '/');
1186        String JavaDoc shownClassName = makeTwoRows(className);
1187        // Deal with inner classes
1188
if (className.indexOf('.') != -1) {
1189            memberRef = pkgName + ".";
1190            memberRef = memberRef.replace('.', '/');
1191            memberRef = newDocPrefix + memberRef + className;
1192        } else {
1193            memberRef = newDocPrefix + memberRef;
1194        }
1195        String JavaDoc newType = memberDiff.newType_;
1196        if (newType.compareTo("void") == 0)
1197            newType = "";
1198        String JavaDoc shortNewType = simpleName(memberDiff.newType_);
1199        // Constructors have the linked name, then the type in parentheses.
1200
reportFile.print(" <nobr><A HREF=\"" + memberRef + ".html#" + className + "(" + newType + ")\" target=\"_top\"><tt>");
1201        reportFile.print(shownClassName);
1202        reportFile.print("</tt></A>");
1203        emitTypeWithParens(shortNewType);
1204        reportFile.println(" </nobr>");
1205        reportFile.println(" </TD>");
1206        
1207        // Report changes in documentation
1208
if (reportDocChanges && memberDiff.documentationChange_ != null) {
1209            String JavaDoc oldMemberRef = null;
1210            String JavaDoc oldType = null;
1211            if (oldDocPrefix != null) {
1212                oldMemberRef = pkgName + "." + className;
1213                oldMemberRef = oldMemberRef.replace('.', '/');
1214                if (className.indexOf('.') != -1) {
1215                    oldMemberRef = pkgName + ".";
1216                    oldMemberRef = oldMemberRef.replace('.', '/');
1217                    oldMemberRef = oldDocPrefix + oldMemberRef + className;
1218                } else {
1219                    oldMemberRef = oldDocPrefix + oldMemberRef;
1220                }
1221                oldType = memberDiff.oldType_;
1222                if (oldType.compareTo("void") == 0)
1223                    oldType = "";
1224            }
1225            if (oldDocPrefix != null)
1226                memberDiff.documentationChange_ += "<A HREF=\"" +
1227                    oldMemberRef + ".html#" + className + "(" + oldType +
1228                    ")\" target=\"_self\"><tt>old</tt></A> to ";
1229            else
1230                memberDiff.documentationChange_ += "<tt>old</tt> to ";
1231            memberDiff.documentationChange_ += "<A HREF=\"" + memberRef +
1232                ".html#" + className + "(" + newType +
1233                ")\" target=\"_self\"><tt>new</tt></A>.<br>";
1234        }
1235
1236        emitChanges(memberDiff, 0);
1237        emitComment(commentID, null, 2);
1238
1239        reportFile.println("</TR>");
1240    }
1241
1242    /**
1243     * Write a table entry for a method.
1244     *
1245     * linkType: 0 - no link by default, 1 = link to Javadoc HTML file
1246     */

1247    public void writeMethodTableEntry(String JavaDoc pkgName, String JavaDoc className,
1248                                      MethodAPI methodAPI, int linkType,
1249                                      String JavaDoc possibleComment, boolean useOld) {
1250        String JavaDoc fqName = pkgName + "." + className;
1251        String JavaDoc signature = methodAPI.getSignature();
1252        String JavaDoc methodName = methodAPI.name_;
1253        String JavaDoc lt = "removed";
1254        if (linkType ==1)
1255            lt = "added";
1256        String JavaDoc commentID = fqName + "." + methodName + "_" + lt + "(" + signature + ")";
1257        if (!useOld) {
1258            reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1259            reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1260            reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1261
}
1262        if (signature.compareTo("void") == 0)
1263            signature = "";
1264        String JavaDoc shortSignature = simpleName(signature);
1265        String JavaDoc returnType = methodAPI.returnType_;
1266        String JavaDoc shortReturnType = simpleName(returnType);
1267        if (linkType == 0) {
1268            if (oldDocPrefix == null) {
1269                // No link
1270
reportFile.print(" <nobr>");
1271                emitType(shortReturnType);
1272                reportFile.print("&nbsp;" + methodName);
1273                emitTypeWithParens(shortSignature);
1274                reportFile.println("</nobr>");
1275            } else {
1276                writeMethodTableEntry(pkgName, className,
1277                                      methodAPI, 1,
1278                                      possibleComment, true);
1279            }
1280        } else if (linkType == 1) {
1281            // Link to HTML file for the package
1282
String JavaDoc memberRef = fqName.replace('.', '/');
1283            // Deal with inner classes
1284
if (className.indexOf('.') != -1) {
1285                memberRef = pkgName + ".";
1286                memberRef = memberRef.replace('.', '/');
1287                if (useOld) {
1288                    // oldDocPrefix is non-null at this point
1289
memberRef = oldDocPrefix + memberRef + className;
1290                } else {
1291                    memberRef = newDocPrefix + memberRef + className;
1292                }
1293            } else {
1294                if (useOld) {
1295                    // oldDocPrefix is non-null at this point
1296
memberRef = oldDocPrefix + memberRef;
1297                } else {
1298                    memberRef = newDocPrefix + memberRef;
1299                }
1300            }
1301            reportFile.print(" <nobr>");
1302            emitType(shortReturnType);
1303            reportFile.print("&nbsp;<A HREF=\"" + memberRef + ".html#" + methodName +
1304               "(" + signature + ")\" target=\"_top\"><tt>" + methodName + "</tt></A>");
1305            emitTypeWithParens(shortSignature);
1306            reportFile.println("</nobr>");
1307        }
1308        if (!useOld) {
1309            reportFile.println(" </TD>");
1310            emitComment(commentID, possibleComment, linkType);
1311            reportFile.println("</TR>");
1312        }
1313    }
1314
1315    /**
1316     * Write a table entry for a changed method.
1317     */

1318    public void writeMethodChangedTableEntry(String JavaDoc pkgName, String JavaDoc className,
1319                                      MemberDiff memberDiff) {
1320        String JavaDoc memberName = memberDiff.name_;
1321        // Generally nowhere to break a member name anyway
1322
// String shownMemberName = makeTwoRows(memberName);
1323
String JavaDoc fqName = pkgName + "." + className;
1324        String JavaDoc newSignature = memberDiff.newSignature_;
1325        String JavaDoc commentID = fqName + "." + memberName + "_changed(" + newSignature + ")";
1326        reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1327
1328        reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1329        reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1330
String JavaDoc memberRef = fqName.replace('.', '/');
1331        // Deal with inner classes
1332
if (className.indexOf('.') != -1) {
1333            memberRef = pkgName + ".";
1334            memberRef = memberRef.replace('.', '/');
1335            memberRef = newDocPrefix + memberRef + className;
1336        } else {
1337            memberRef = newDocPrefix + memberRef;
1338        }
1339        // Javadoc generated HTML has no named anchors for methods
1340
// inherited from other classes, so link to the defining class' method.
1341
// Only copes with non-inner classes.
1342
if (className.indexOf('.') == -1 &&
1343            memberDiff.modifiersChange_ != null &&
1344            memberDiff.modifiersChange_.indexOf("but is now inherited from") != -1) {
1345            memberRef = memberDiff.inheritedFrom_;
1346            memberRef = memberRef.replace('.', '/');
1347            memberRef = newDocPrefix + memberRef;
1348        }
1349        
1350        String JavaDoc newReturnType = memberDiff.newType_;
1351        String JavaDoc shortReturnType = simpleName(newReturnType);
1352        String JavaDoc shortSignature = simpleName(newSignature);
1353        reportFile.print(" <nobr>");
1354        emitTypeWithNoParens(shortReturnType);
1355        reportFile.print("&nbsp;<A HREF=\"" + memberRef + ".html#" +
1356                         memberName + "(" + newSignature + ")\" target=\"_top\"><tt>");
1357        reportFile.print(memberName);
1358        reportFile.print("</tt></A>");
1359        emitTypeWithParens(shortSignature);
1360        reportFile.println(" </nobr>");
1361        reportFile.println(" </TD>");
1362        
1363        // Report changes in documentation
1364
if (reportDocChanges && memberDiff.documentationChange_ != null) {
1365            String JavaDoc oldMemberRef = null;
1366            String JavaDoc oldSignature = null;
1367            if (oldDocPrefix != null) {
1368                oldMemberRef = pkgName + "." + className;
1369                oldMemberRef = oldMemberRef.replace('.', '/');
1370                if (className.indexOf('.') != -1) {
1371                    oldMemberRef = pkgName + ".";
1372                    oldMemberRef = oldMemberRef.replace('.', '/');
1373                    oldMemberRef = oldDocPrefix + oldMemberRef + className;
1374                } else {
1375                    oldMemberRef = oldDocPrefix + oldMemberRef;
1376                }
1377                oldSignature = memberDiff.oldSignature_;
1378            }
1379            if (oldDocPrefix != null)
1380                memberDiff.documentationChange_ += "<A HREF=\"" +
1381                    oldMemberRef + ".html#" + memberName + "(" +
1382                    oldSignature + ")\" target=\"_self\"><tt>old</tt></A> to ";
1383            else
1384                memberDiff.documentationChange_ += "<tt>old</tt> to ";
1385            memberDiff.documentationChange_ += "<A HREF=\"" + memberRef +
1386                ".html#" + memberName + "(" + newSignature +
1387                ")\" target=\"_self\"><tt>new</tt></A>.<br>";
1388        }
1389
1390        emitChanges(memberDiff, 1);
1391        // Get the comment from the parent class if more appropriate
1392
if (memberDiff.modifiersChange_ != null) {
1393            int parentIdx = memberDiff.modifiersChange_.indexOf("now inherited from");
1394            if (parentIdx != -1) {
1395                // Change the commentID to pick up the appropriate method
1396
commentID = memberDiff.inheritedFrom_ + "." + memberName +
1397                    "_changed(" + newSignature + ")";
1398            }
1399        }
1400        emitComment(commentID, null, 2);
1401        
1402        reportFile.println("</TR>");
1403    }
1404
1405    /**
1406     * Write a table entry for a field.
1407     *
1408     * linkType: 0 - no link by default, 1 = link to Javadoc HTML file
1409     */

1410    public void writeFieldTableEntry(String JavaDoc pkgName, String JavaDoc className,
1411                                     FieldAPI fieldAPI, int linkType,
1412                                     String JavaDoc possibleComment, boolean useOld) {
1413        String JavaDoc fqName = pkgName + "." + className;
1414        // Fields can only appear in one table, so no need to specify _added etc
1415
String JavaDoc fieldName = fieldAPI.name_;
1416        // Generally nowhere to break a member name anyway
1417
// String shownFieldName = makeTwoRows(fieldName);
1418
String JavaDoc commentID = fqName + "." + fieldName;
1419        if (!useOld) {
1420            reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1421            reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1422            reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1423
}
1424        String JavaDoc fieldType = fieldAPI.type_;
1425        if (fieldType.compareTo("void") == 0)
1426            fieldType = "";
1427        String JavaDoc shortFieldType = simpleName(fieldType);
1428        if (linkType == 0) {
1429            if (oldDocPrefix == null) {
1430                // No link.
1431
reportFile.print(" ");
1432                emitType(shortFieldType);
1433                reportFile.println("&nbsp;" + fieldName);
1434            } else {
1435                writeFieldTableEntry(pkgName, className,
1436                                     fieldAPI, 1,
1437                                     possibleComment, true);
1438            }
1439        } else if (linkType == 1) {
1440            // Link to HTML file for the package.
1441
String JavaDoc memberRef = fqName.replace('.', '/');
1442            // Deal with inner classes
1443
if (className.indexOf('.') != -1) {
1444                memberRef = pkgName + ".";
1445                memberRef = memberRef.replace('.', '/');
1446                if (useOld)
1447                    memberRef = oldDocPrefix + memberRef + className;
1448                else
1449                    memberRef = newDocPrefix + memberRef + className;
1450            } else {
1451                if (useOld)
1452                    memberRef = oldDocPrefix + memberRef;
1453                else
1454                    memberRef = newDocPrefix + memberRef;
1455            }
1456            reportFile.print(" <nobr>");
1457            emitType(shortFieldType);
1458            reportFile.println("&nbsp;<A HREF=\"" + memberRef + ".html#" + fieldName +
1459               "\" target=\"_top\"><tt>" + fieldName + "</tt></A></nobr>");
1460        }
1461        if (!useOld) {
1462            reportFile.println(" </TD>");
1463            emitComment(commentID, possibleComment, linkType);
1464            reportFile.println("</TR>");
1465        }
1466        }
1467
1468    /**
1469     * Write a table entry for a changed field.
1470     */

1471    public void writeFieldChangedTableEntry(String JavaDoc pkgName, String JavaDoc className,
1472                                            MemberDiff memberDiff) {
1473        String JavaDoc memberName = memberDiff.name_;
1474        // Generally nowhere to break a member name anyway
1475
// String shownMemberName = makeTwoRows(memberName);
1476
String JavaDoc fqName = pkgName + "." + className;
1477        // Fields have unique names in a class
1478
String JavaDoc commentID = fqName + "." + memberName;
1479        reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">");
1480
1481        reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">");
1482        reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor
1483
String JavaDoc memberRef = fqName.replace('.', '/');
1484        // Deal with inner classes
1485
if (className.indexOf('.') != -1) {
1486            memberRef = pkgName + ".";
1487            memberRef = memberRef.replace('.', '/');
1488            memberRef = newDocPrefix + memberRef + className;
1489        } else {
1490            memberRef = newDocPrefix + memberRef;
1491        }
1492        // Javadoc generated HTML has no named anchors for fields
1493
// inherited from other classes, so link to the defining class' field.
1494
// Only copes with non-inner classes.
1495
if (className.indexOf('.') == -1 &&
1496            memberDiff.modifiersChange_ != null &&
1497            memberDiff.modifiersChange_.indexOf("but is now inherited from") != -1) {
1498            memberRef = memberDiff.inheritedFrom_;
1499            memberRef = memberRef.replace('.', '/');
1500            memberRef = newDocPrefix + memberRef;
1501        }
1502
1503        String JavaDoc newType = memberDiff.newType_;
1504        String JavaDoc shortNewType = simpleName(newType);
1505        reportFile.print(" <nobr>");
1506        emitTypeWithNoParens(shortNewType);
1507        reportFile.print("&nbsp;<A HREF=\"" + memberRef + ".html#" +
1508                         memberName + "\" target=\"_top\"><tt>");
1509        reportFile.print(memberName);
1510        reportFile.print("</tt></A></nobr>");
1511        reportFile.println(" </TD>");
1512        
1513        // Report changes in documentation
1514
if (reportDocChanges && memberDiff.documentationChange_ != null) {
1515            String JavaDoc oldMemberRef = null;
1516            if (oldDocPrefix != null) {
1517                oldMemberRef = pkgName + "." + className;
1518                oldMemberRef = oldMemberRef.replace('.', '/');
1519                if (className.indexOf('.') != -1) {
1520                    oldMemberRef = pkgName + ".";
1521                    oldMemberRef = oldMemberRef.replace('.', '/');
1522                    oldMemberRef = oldDocPrefix + oldMemberRef + className;
1523                } else {
1524                    oldMemberRef = oldDocPrefix + oldMemberRef;
1525                }
1526            }
1527            if (oldDocPrefix != null)
1528                memberDiff.documentationChange_ += "<A HREF=\"" +
1529                    oldMemberRef + ".html#" + memberName + "\" target=\"_self\"><tt>old</tt></A> to ";
1530            else
1531                memberDiff.documentationChange_ += "<tt>old</tt> to ";
1532            memberDiff.documentationChange_ += "<A HREF=\"" + memberRef +
1533                ".html#" + memberName + "\" target=\"_self\"><tt>new</tt></A>.<br>";
1534        }
1535
1536        emitChanges(memberDiff, 2);
1537        // Get the comment from the parent class if more appropriate
1538
if (memberDiff.modifiersChange_ != null) {
1539            int parentIdx = memberDiff.modifiersChange_.indexOf("now inherited from");
1540            if (parentIdx != -1) {
1541                // Change the commentID to pick up the appropriate method
1542
commentID = memberDiff.inheritedFrom_ + "." + memberName;
1543            }
1544        }
1545        emitComment(commentID, null, 2);
1546        
1547        reportFile.println("</TR>");
1548    }
1549
1550    /**
1551     * Emit all changes associated with a MemberDiff as an entry in a table.
1552     *
1553     * @param memberType 0 = ctor, 1 = method, 2 = field
1554     */

1555    public void emitChanges(MemberDiff memberDiff, int memberType){
1556        reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"30%\">");
1557        boolean hasContent = false;
1558        // The type or return type changed
1559
if (memberDiff.oldType_.compareTo(memberDiff.newType_) != 0) {
1560            String JavaDoc shortOldType = simpleName(memberDiff.oldType_);
1561            String JavaDoc shortNewType = simpleName(memberDiff.newType_);
1562            if (memberType == 1) {
1563                reportFile.print("Change in return type from ");
1564            } else {
1565                reportFile.print("Change in type from ");
1566            }
1567            if (shortOldType.compareTo(shortNewType) == 0) {
1568                // The types differ in package name, so use the full name
1569
shortOldType = memberDiff.oldType_;
1570                shortNewType = memberDiff.newType_;
1571            }
1572            emitType(shortOldType);
1573            reportFile.print(" to ");
1574            emitType(shortNewType);
1575            reportFile.println(".<br>");
1576            hasContent = true;
1577        }
1578        // The signatures changed - only used by methods
1579
if (memberType == 1 &&
1580            memberDiff.oldSignature_ != null &&
1581            memberDiff.newSignature_ != null &&
1582            memberDiff.oldSignature_.compareTo(memberDiff.newSignature_) != 0) {
1583            String JavaDoc shortOldSignature = simpleName(memberDiff.oldSignature_);
1584            String JavaDoc shortNewSignature = simpleName(memberDiff.newSignature_);
1585            if (shortOldSignature.compareTo(shortNewSignature) == 0) {
1586                // The signatures differ in package names, so use the full form
1587
shortOldSignature = memberDiff.oldSignature_;
1588                shortNewSignature = memberDiff.newSignature_;
1589            }
1590            if (hasContent)
1591                reportFile.print(" ");
1592            reportFile.print("Change in signature from ");
1593            if (shortOldSignature.compareTo("") == 0)
1594                shortOldSignature = "void";
1595            emitType(shortOldSignature);
1596            reportFile.print(" to ");
1597            if (shortNewSignature.compareTo("") == 0)
1598                shortNewSignature = "void";
1599            emitType(shortNewSignature);
1600            reportFile.println(".<br>");
1601            hasContent = true;
1602        }
1603        // The exceptions are only non-null in methods and constructors
1604
if (memberType != 2 &&
1605            memberDiff.oldExceptions_ != null &&
1606            memberDiff.newExceptions_ != null &&
1607            memberDiff.oldExceptions_.compareTo(memberDiff.newExceptions_) != 0) {
1608            if (hasContent)
1609                reportFile.print(" ");
1610            // If either one of the exceptions has no spaces in it, or is
1611
// equal to "no exceptions", then just display the whole
1612
// exceptions texts.
1613
int spaceInOld = memberDiff.oldExceptions_.indexOf(" ");
1614            if (memberDiff.oldExceptions_.compareTo("no exceptions") == 0)
1615                spaceInOld = -1;
1616            int spaceInNew = memberDiff.newExceptions_.indexOf(" ");
1617            if (memberDiff.newExceptions_.compareTo("no exceptions") == 0)
1618                spaceInNew = -1;
1619            if (spaceInOld == -1 || spaceInNew == -1) {
1620                reportFile.print("Change in exceptions thrown from ");
1621                emitException(memberDiff.oldExceptions_);
1622                reportFile.print(" to " );
1623                emitException(memberDiff.newExceptions_);
1624                reportFile.println(".<br>");
1625            } else {
1626                // Too many exceptions become unreadable, so just show the
1627
// individual changes. Catch the case where exceptions are
1628
// just reordered.
1629
boolean firstChange = true;
1630                int numRemoved = 0;
1631                StringTokenizer stOld = new StringTokenizer(memberDiff.oldExceptions_, ", ");
1632                while (stOld.hasMoreTokens()) {
1633                    String JavaDoc oldException = stOld.nextToken();
1634                    if (!memberDiff.newExceptions_.startsWith(oldException) &&
1635                        !(memberDiff.newExceptions_.indexOf(", " + oldException) != -1)) {
1636                        if (firstChange) {
1637                            reportFile.print("Change in exceptions: ");
1638                            firstChange = false;
1639                        }
1640                        if (numRemoved != 0)
1641                            reportFile.print(", ");
1642                        emitException(oldException);
1643                        numRemoved++;
1644                    }
1645                }
1646                if (numRemoved == 1)
1647                    reportFile.print(" was removed.");
1648                else if (numRemoved > 1)
1649                    reportFile.print(" were removed.");
1650                
1651                int numAdded = 0;
1652                StringTokenizer stNew = new StringTokenizer(memberDiff.newExceptions_, ", ");
1653                while (stNew.hasMoreTokens()) {
1654                    String JavaDoc newException = stNew.nextToken();
1655                    if (!memberDiff.oldExceptions_.startsWith(newException) &&
1656                        !(memberDiff.oldExceptions_.indexOf(", " + newException) != -1)) {
1657                        if (firstChange) {
1658                            reportFile.print("Change in exceptions: ");
1659                            firstChange = false;
1660                        }
1661                        if (numAdded != 0)
1662                            reportFile.println(", ");
1663                        else
1664                            reportFile.println(" ");
1665                        emitException(newException);
1666                        numAdded++;
1667                    }
1668                }
1669                if (numAdded == 1)
1670                    reportFile.print(" was added");
1671                else if (numAdded > 1)
1672                    reportFile.print(" were added");
1673                else if (numAdded == 0 && numRemoved == 0 && firstChange)
1674                    reportFile.print("Exceptions were reordered");
1675                reportFile.println(".<br>");
1676            }
1677            // Note the changes between a comma-separated list of Strings
1678
hasContent = true;
1679        }
1680
1681        if (memberDiff.documentationChange_ != null) {
1682            if (hasContent)
1683                reportFile.print(" ");
1684            reportFile.print(memberDiff.documentationChange_);
1685            hasContent = true;
1686        }
1687            
1688        // Last, so no need for a <br>
1689
if (memberDiff.modifiersChange_ != null) {
1690            if (hasContent)
1691                reportFile.print(" ");
1692            reportFile.println(memberDiff.modifiersChange_);
1693            hasContent = true;
1694        }
1695        reportFile.println(" </TD>");
1696    }
1697
1698    /**
1699     * Emit a string which is an exception by surrounding it with
1700     * &lt;code&gt; tags.
1701     * If there is a space in the type, e.g. &quot;String, File&quot;, then
1702     * surround it with parentheses too. Do not add &lt;code&gt; tags or
1703     * parentheses if the String is "no exceptions".
1704     */

1705    public void emitException(String JavaDoc ex) {
1706        if (ex.compareTo("no exceptions") == 0) {
1707            reportFile.print(ex);
1708        } else {
1709            if (ex.indexOf(' ') != -1) {
1710                reportFile.print("(<code>" + ex + "</code>)");
1711            } else {
1712                reportFile.print("<code>" + ex + "</code>");
1713            }
1714        }
1715    }
1716
1717    /**
1718     * Emit a string which is a type by surrounding it with &lt;code&gt; tags.
1719     * If there is a space in the type, e.g. &quot;String, File&quot;, then
1720     * surround it with parentheses too.
1721     */

1722    public void emitType(String JavaDoc type) {
1723        if (type.compareTo("") == 0)
1724            return;
1725        if (type.indexOf(' ') != -1) {
1726            reportFile.print("(<code>" + type + "</code>)");
1727        } else {
1728            reportFile.print("<code>" + type + "</code>");
1729        }
1730    }
1731
1732    /**
1733     * Emit a string which is a type by surrounding it with &lt;code&gt; tags.
1734     * Also surround it with parentheses too. Used to display methods'
1735     * parameters.
1736     * Suggestions for where a browser should break the
1737     * text are provided with &lt;br> and &ltnobr> tags.
1738     */

1739    public static void emitTypeWithParens(String JavaDoc type) {
1740        emitTypeWithParens(type, true);
1741    }
1742
1743    /**
1744     * Emit a string which is a type by surrounding it with &lt;code&gt; tags.
1745     * Also surround it with parentheses too. Used to display methods'
1746     * parameters.
1747     */

1748    public static void emitTypeWithParens(String JavaDoc type, boolean addBreaks) {
1749        if (type.compareTo("") == 0)
1750            reportFile.print("()");
1751        else {
1752            int idx = type.indexOf(", ");
1753            if (!addBreaks || idx == -1) {
1754                reportFile.print("(<code>" + type + "</code>)");
1755            } else {
1756                // Make the browser break text at reasonable places
1757
String JavaDoc sepType = null;
1758                StringTokenizer st = new StringTokenizer(type, ", ");
1759                while (st.hasMoreTokens()) {
1760                    String JavaDoc p = st.nextToken();
1761                    if (sepType == null)
1762                        sepType = p;
1763                    else
1764                        sepType += ",</nobr> " + p + "<nobr>";
1765                }
1766                reportFile.print("(<code>" + sepType + "<nobr></code>)");
1767            }
1768        }
1769    }
1770
1771    /**
1772     * Emit a string which is a type by surrounding it with &lt;code&gt; tags.
1773     * Do not surround it with parentheses. Used to display methods' return
1774     * types and field types.
1775     */

1776    public static void emitTypeWithNoParens(String JavaDoc type) {
1777        if (type.compareTo("") != 0)
1778            reportFile.print("<code>" + type + "</code>");
1779    }
1780
1781    /**
1782     * Return a String with the simple names of the classes in fqName.
1783     * &quot;java.lang.String&quot; becomes &quot;String&quot;,
1784     * &quotjava.lang.String, java.io.File&quot becomes &quotString, File&quot;
1785     * and so on. If fqName is null, return null. If fqName is &quot;&quot;,
1786     * return &quot;&quot;.
1787     */

1788    public static String JavaDoc simpleName(String JavaDoc fqNames) {
1789        if (fqNames == null)
1790            return null;
1791        String JavaDoc res = "";
1792        boolean hasContent = false;
1793        StringTokenizer st = new StringTokenizer(fqNames, ", ");
1794        while (st.hasMoreTokens()) {
1795            String JavaDoc fqName = st.nextToken();
1796            // Assume this will be used inside a <nobr> </nobr> set of tags.
1797
if (hasContent)
1798                res += ", ";
1799            hasContent = true;
1800            int lastDot = fqName.lastIndexOf('.');
1801            if (lastDot < 0) {
1802                res += fqName; // Already as simple as possible
1803
} else {
1804                res += fqName.substring(lastDot+1);
1805            }
1806        }
1807        return res;
1808    }
1809
1810    /**
1811     * Find any existing comment and emit it. Add the new comment to the
1812     * list of new comments. The first instance of the string "@first" in
1813     * a hand-written comment will be replaced by the first sentence from
1814     * the associated doc block, if such exists. Also replace @link by
1815     * an HTML link.
1816     *
1817     * @param commentID The identifier for this comment.
1818     * @param possibleComment A possible comment from another source.
1819     * @param linkType 0 = remove, 1 = add, 2 = change
1820     */

1821    public void emitComment(String JavaDoc commentID, String JavaDoc possibleComment,
1822                            int linkType) {
1823        if (noCommentsOnRemovals && linkType == 0) {
1824            reportFile.println(" <TD>&nbsp;</TD>");
1825            return;
1826        }
1827        if (noCommentsOnAdditions && linkType == 1) {
1828            reportFile.println(" <TD>&nbsp;</TD>");
1829            return;
1830        }
1831        if (noCommentsOnChanges && linkType == 2) {
1832            reportFile.println(" <TD>&nbsp;</TD>");
1833            return;
1834        }
1835
1836        // We have to use this global hash table because the *Diff classes
1837
// do not store the possible comment from the new *API object.
1838
if (!noCommentsOnChanges && possibleComment == null) {
1839            possibleComment = (String JavaDoc)Comments.allPossibleComments.get(commentID);
1840        }
1841        // Just use the first sentence of the possible comment.
1842
if (possibleComment != null) {
1843            int fsidx = RootDocToXML.endOfFirstSentence(possibleComment, false);
1844            if (fsidx != -1 && fsidx != 0)
1845                possibleComment = possibleComment.substring(0, fsidx+1);
1846        }
1847
1848        String JavaDoc comment = Comments.getComment(existingComments_, commentID);
1849        if (comment.compareTo(Comments.placeHolderText) == 0) {
1850            if (possibleComment != null &&
1851                possibleComment.indexOf("InsertOtherCommentsHere") == -1)
1852                reportFile.println(" <TD VALIGN=\"TOP\">" + possibleComment + "</TD>");
1853            else
1854                reportFile.println(" <TD>&nbsp;</TD>");
1855        } else {
1856            int idx = comment.indexOf("@first");
1857            if (idx == -1) {
1858                reportFile.println(" <TD VALIGN=\"TOP\">" + Comments.convertAtLinks(comment, "", null, null) + "</TD>");
1859            } else {
1860                reportFile.print(" <TD VALIGN=\"TOP\">" + comment.substring(0, idx));
1861                if (possibleComment != null &&
1862                    possibleComment.indexOf("InsertOtherCommentsHere") == -1)
1863                    reportFile.print(possibleComment);
1864                reportFile.println(comment.substring(idx + 6) + "</TD>");
1865            }
1866        }
1867        SingleComment newComment = new SingleComment(commentID, comment);
1868        newComments_.addComment(newComment);
1869    }
1870    
1871    /** Write the end of a table. */
1872    public void writeTableEnd() {
1873        reportFile.println("</TABLE>");
1874        reportFile.println("&nbsp;");
1875    }
1876
1877    /** Write a newline out. */
1878    public void writeText() {
1879        reportFile.println();
1880    }
1881
1882    /** Write some text out. */
1883    public void writeText(String JavaDoc text) {
1884        reportFile.println(text);
1885    }
1886
1887    /** Emit some non-breaking space for indentation. */
1888    public void indent(int indent) {
1889        for (int i = 0; i < indent; i++)
1890            reportFile.print("&nbsp;");
1891    }
1892
1893    /**
1894     * The name of the file to which the top-level HTML file is written,
1895     * and also the name of the subdirectory where most of the HTML appears,
1896     * and also a prefix for the names of some of the files in that
1897     * subdirectory.
1898     */

1899    static String JavaDoc reportFileName = "changes";
1900    
1901    /**
1902     * The suffix of the file to which the HTML output is currently being
1903     * written.
1904     */

1905    static String JavaDoc reportFileExt = ".html";
1906    
1907    /**
1908     * The file to which the HTML output is currently being written.
1909     */

1910    static PrintWriter reportFile = null;
1911
1912    /**
1913     * The object which represents the top of the tree of differences
1914     * between two APIs. It is only used indirectly when emitting a
1915     * navigation bar.
1916     */

1917    static APIDiff apiDiff = null;
1918
1919    /**
1920     * If set, then do not suggest comments for removals from the first
1921     * sentence of the doc block of the old API.
1922     */

1923    public static boolean noCommentsOnRemovals = false;
1924
1925    /**
1926     * If set, then do not suggest comments for additions from the first
1927     * sentence of the doc block of the new API.
1928     */

1929    public static boolean noCommentsOnAdditions = false;
1930
1931    /**
1932     * If set, then do not suggest comments for changes from the first
1933     * sentence of the doc block of the new API.
1934     */

1935    public static boolean noCommentsOnChanges = false;
1936
1937    /**
1938     * If set, then report changes in documentation (Javadoc comments)
1939     * between the old and the new API. The default is that this is not set.
1940     */

1941    public static boolean reportDocChanges = false;
1942
1943    /**
1944     * Define the prefix for HTML links to the existing set of Javadoc-
1945     * generated documentation for the new API. E.g. For J2SE1.3.x, use
1946     * "http://java.sun.com/j2se/1.3/docs/api/"
1947     */

1948    public static String JavaDoc newDocPrefix = "../";
1949
1950    /**
1951     * Define the prefix for HTML links to the existing set of Javadoc-
1952     * generated documentation for the old API.
1953     */

1954    public static String JavaDoc oldDocPrefix = null;
1955
1956    /** To generate statistical output, set this to true. */
1957    public static boolean doStats = false;
1958
1959    /**
1960     * The destination directory for output files.
1961     */

1962    public static String JavaDoc outputDir = null;
1963
1964    /**
1965     * The title used on the first page of the report. By default, this is
1966     * &quot;API Differences Between &lt;name of old API&gt; and
1967     * &lt;name of new API&gt;&quot;. It can be
1968     * set by using the -doctitle option.
1969     */

1970    public static String JavaDoc docTitle = null;
1971
1972    /**
1973     * The browser window title for the report. By default, this is
1974     * &quot;API Differences Between &lt;name of old API&gt; and
1975     * &lt;name of new API&gt;&quot;. It can be
1976     * set by using the -windowtitle option.
1977     */

1978    public static String JavaDoc windowTitle = null;
1979
1980    /** The desired background color for JDiff tables. */
1981    static final String JavaDoc bgcolor = "#FFFFFF";
1982
1983    /** Set to enable debugging output. */
1984    private static final boolean trace = false;
1985
1986}
1987
Popular Tags