1 package jdiff; 2 3 import java.util.*; 4 import java.io.*; 5 import java.text.*; 6 7 /** 8 * Emit HTML based on the changes between two sets of APIs. 9 * 10 * See the file LICENSE.txt for copyright details. 11 * @author Matthew Doar, mdoar@pobox.com 12 */ 13 public class HTMLReportGenerator { 14 15 /** Default constructor. */ HTMLReportGenerator()16 public HTMLReportGenerator() { 17 } 18 19 /** The Comments object for existing comments. */ 20 private Comments existingComments_ = null; 21 22 /** 23 * The Comments object for freshly regenerated comments. 24 * This is populated during the generation of the report, 25 * and should be like existingComments_ but with unused comments 26 * marked as such, so that they can be commented out in XML when 27 * the new comments are written out to the comments file. 28 */ 29 private Comments newComments_ = null; 30 31 /** 32 * Accessor method for the freshly generated Comments object. 33 * The list of comments is sorted before the object is returned. 34 */ getNewComments()35 public Comments getNewComments() { 36 Collections.sort(newComments_.commentsList_); 37 return newComments_; 38 } 39 40 /** Generate the report. */ generate(APIComparator comp, Comments existingComments)41 public void generate(APIComparator comp, Comments existingComments) { 42 String fullReportFileName = reportFileName; 43 if (outputDir != null) 44 fullReportFileName = outputDir + JDiff.DIR_SEP + reportFileName; 45 System.out.println("JDiff: generating HTML report into the file '" + fullReportFileName + reportFileExt + "' and the subdirectory '" + fullReportFileName + "'"); 46 // May be null if no comments file exists yet 47 existingComments_ = existingComments; 48 // Where the new comments will be placed 49 newComments_ = new Comments(); 50 // Writing to multiple files, so make sure the subdirectory exists 51 File opdir = new File(fullReportFileName); 52 if (!opdir.mkdir() && !opdir.exists()) { 53 System.out.println("Error: could not create the subdirectory '" + fullReportFileName + "'"); 54 System.exit(3); 55 } 56 57 // Emit the documentation difference files 58 if (!Diff.noDocDiffs) { 59 // Documentation differences, one file per package 60 Diff.emitDocDiffs(fullReportFileName); 61 } 62 63 // This is the top-level summary file, first in the right hand frame 64 // or linked at the start to if no frames are used. 65 String changesSummaryName = fullReportFileName + JDiff.DIR_SEP + 66 reportFileName + "-summary" + reportFileExt; 67 apiDiff = comp.apiDiff; 68 try { 69 FileOutputStream fos = new FileOutputStream(changesSummaryName); 70 reportFile = new PrintWriter(fos); 71 writeStartHTMLHeader(); 72 // Write out the title in he HTML header 73 String oldAPIName = "Old API"; 74 if (apiDiff.oldAPIName_ != null) 75 oldAPIName = apiDiff.oldAPIName_; 76 String newAPIName = "New API"; 77 if (apiDiff.newAPIName_ != null) 78 newAPIName = apiDiff.newAPIName_; 79 if (windowTitle == null) 80 writeHTMLTitle("Android API Differences Report"); 81 else 82 writeHTMLTitle(windowTitle); 83 writeStyleSheetRef(); 84 writeText("</HEAD>"); 85 86 writeText("<body class=\"gc-documentation\">"); 87 88 // writeText("<div class=\"g-section g-tpl-180\">"); 89 // Add the nav bar for the summary page 90 writeNavigationBar(reportFileName + "-summary", null, null, 91 null, 0, true, 92 apiDiff.packagesRemoved.size() != 0, 93 apiDiff.packagesAdded.size() != 0, 94 apiDiff.packagesChanged.size() != 0); 95 96 // Write the title in the body with some formatting 97 if (docTitle == null) { 98 //writeText("<center>"); 99 writeText(" <div id=\"titleAligner\" style=\"vertical-align:top;padding:1em;margin-left:0;text-align:left;\">"); 100 writeText(" <H1 class=\"pagecontenth1\">API Differences Report</H1>"); 101 writeText(" </div>"); 102 } else { 103 writeText(" <div id=\"titleAligner\" style=\"vertical-align:top;padding:1em;margin-left:0;text-align:left;\">"); 104 writeText(" <H1 class=\"pagecontenth1\">" + docTitle + "</H1>"); 105 writeText(" </div>"); 106 } 107 108 writeText("<p>This document details the changes in the Android framework API. It shows "); 109 writeText("additions, modifications, and removals for packages, classes, methods, and "); 110 writeText("fields. Each reference to an API change includes a brief description of the "); 111 writeText("API and an explanation of the change and suggested workaround, where available.</p>"); 112 113 writeText("<p>The differences described in this report are based a comparison of the APIs "); 114 writeText("whose versions are specified in the upper-right corner of this page. It compares a "); 115 writeText("newer \"to\" API to an older \"from\" version, noting any changes relative to the "); 116 writeText("older API. So, for example, indicated API removals are no longer present in the \"to\" "); 117 writeText("API.</p>"); 118 119 writeText("<p>To navigate the report, use the \"Select a Diffs Index\" and \"Filter the Index\" "); 120 writeText("controls on the left. The report uses text formatting to indicate <em>interface names</em>, "); 121 writeText("<a href= ><tt>links to reference documentation</tt></a>, and <a href= >links to change "); 122 writeText("description</a>. </p>"); 123 124 writeText("<p>For more information about the Android framework API and SDK, "); 125 writeText("see the <a href=\"http://code.google.com/android/index.html\" target=\"_top\">Android product site</a>.</p>"); 126 127 // Write the contents and the other files as well 128 writeReport(apiDiff); 129 writeHTMLFooter(); 130 reportFile.close(); 131 } catch(IOException e) { 132 System.out.println("IO Error while attempting to create " + changesSummaryName); 133 System.out.println("Error: " + e.getMessage()); 134 System.exit(1); 135 } 136 137 // Now generate all the other files for multiple frames. 138 // 139 // The top-level changes.html frames file where everything starts. 140 String tln = fullReportFileName + reportFileExt; 141 // The file for the top-left frame. 142 String tlf = fullReportFileName + JDiff.DIR_SEP + 143 "jdiff_topleftframe" + reportFileExt; 144 // The default file for the bottom-left frame is the one with the 145 // most information in it. 146 String allDiffsIndexName = fullReportFileName + JDiff.DIR_SEP + 147 "alldiffs_index"; 148 // Other indexes for the bottom-left frame. 149 String packagesIndexName = fullReportFileName + JDiff.DIR_SEP + 150 "packages_index"; 151 String classesIndexName = fullReportFileName + JDiff.DIR_SEP + 152 "classes_index"; 153 String constructorsIndexName = fullReportFileName + JDiff.DIR_SEP + 154 "constructors_index"; 155 String methodsIndexName = fullReportFileName + JDiff.DIR_SEP + 156 "methods_index"; 157 String fieldsIndexName = fullReportFileName + JDiff.DIR_SEP + 158 "fields_index"; 159 160 HTMLFiles hf = new HTMLFiles(this); 161 hf.emitTopLevelFile(tln, apiDiff); 162 hf.emitTopLeftFile(tlf); 163 hf.emitHelp(fullReportFileName, apiDiff); 164 hf.emitStylesheet(); 165 166 HTMLIndexes h = new HTMLIndexes(this); 167 h.emitAllBottomLeftFiles(packagesIndexName, classesIndexName, 168 constructorsIndexName, methodsIndexName, 169 fieldsIndexName, allDiffsIndexName, apiDiff); 170 171 if (doStats) { 172 // The file for the statistical report. 173 String sf = fullReportFileName + JDiff.DIR_SEP + 174 "jdiff_statistics" + reportFileExt; 175 HTMLStatistics stats = new HTMLStatistics(this); 176 stats.emitStatistics(sf, apiDiff); 177 } 178 } 179 180 /** 181 * Write the HTML report. 182 * 183 * The top section describes all the packages added (with links) and 184 * removed, and the changed packages section has links which takes you 185 * to a section for each package. This pattern continues for classes and 186 * constructors, methods and fields. 187 */ writeReport(APIDiff apiDiff)188 public void writeReport(APIDiff apiDiff) { 189 190 // Report packages which were removed in the new API 191 if (apiDiff.packagesRemoved.size() != 0) { 192 writeTableStart("Removed Packages", 2); 193 Iterator iter = apiDiff.packagesRemoved.iterator(); 194 while (iter.hasNext()) { 195 PackageAPI pkgAPI = (PackageAPI)(iter.next()); 196 String pkgName = pkgAPI.name_; 197 if (trace) System.out.println("Package " + pkgName + " was removed."); 198 writePackageTableEntry(pkgName, 0, pkgAPI.doc_, false); 199 } 200 writeTableEnd(); 201 } 202 203 // Report packages which were added in the new API 204 if (apiDiff.packagesAdded.size() != 0) { 205 writeTableStart("Added Packages", 2); 206 Iterator iter = apiDiff.packagesAdded.iterator(); 207 while (iter.hasNext()) { 208 PackageAPI pkgAPI = (PackageAPI)(iter.next()); 209 String pkgName = pkgAPI.name_; 210 if (trace) System.out.println("Package " + pkgName + " was added."); 211 writePackageTableEntry(pkgName, 1, pkgAPI.doc_, false); 212 } 213 writeTableEnd(); 214 } 215 216 // Report packages which were changed in the new API 217 if (apiDiff.packagesChanged.size() != 0) { 218 // Emit a table of changed packages, with links to the file 219 // for each package. 220 writeTableStart("Changed Packages", 3); 221 Iterator iter = apiDiff.packagesChanged.iterator(); 222 while (iter.hasNext()) { 223 PackageDiff pkgDiff = (PackageDiff)(iter.next()); 224 String pkgName = pkgDiff.name_; 225 if (trace) System.out.println("Package " + pkgName + " was changed."); 226 writePackageTableEntry(pkgName, 2, null, false); 227 } 228 writeTableEnd(); 229 writeText("<!-- End of API section -->"); 230 231 // Now emit a separate file for each changed package. 232 writeText("<!-- Start of packages section -->"); 233 PackageDiff[] pkgDiffs = new PackageDiff[apiDiff.packagesChanged.size()]; 234 pkgDiffs = (PackageDiff[])apiDiff.packagesChanged.toArray(pkgDiffs); 235 for (int i = 0; i < pkgDiffs.length; i++) { 236 reportChangedPackage(pkgDiffs, i); 237 } 238 } 239 writeText("</div><!-- end pagecontent -->"); 240 writeText("</div><!-- end codesitecontent -->"); 241 writeText("<div style=\"padding-left: 10px; padding-right: 10px; margin-top: 0; padding-bottom: 15px;\">"); 242 writeText(" <table style=\"width: 100%; border: none;\"><tr>"); 243 writeText(" <td style=\"text-align:center;font-size: 10pt; border: none; color: ccc;\"> "); 244 writeText(" <span>©2008 Google - "); 245 writeText(" <a href=\"http://code.google.com\">Code Home</a> - "); 246 writeText(" <a href=\"http://www.google.com/accounts/TOS\">Site Terms of Service</a> - "); 247 writeText(" <a href=\"http://www.google.com/privacy.html\">Privacy Policy</a> "); 248 writeText(" </span>"); 249 writeText(" <div style=\"position:relative;margin-top:-2em;" ); 250 writeText(" font-size:8pt;color:aaa;text-align:right;\">"); 251 writeText(" <em>Generated by <a href=\"http://www.jdiff.org/\">JDiff</a></em><br><img "); 252 writeText(" align=\"right\" src=\"../../../assets/jdiff_logo.gif\">"); 253 writeText(" </span>"); 254 writeText(" </td>"); 255 writeText(" </tr></table>"); 256 writeText("</div>"); 257 writeText("</div><!-- end gc-containter -->"); 258 } 259 260 /** 261 * Write out the details of a changed package in a separate file. 262 */ reportChangedPackage(PackageDiff[] pkgDiffs, int pkgIndex)263 public void reportChangedPackage(PackageDiff[] pkgDiffs, int pkgIndex) { 264 PackageDiff pkgDiff = pkgDiffs[pkgIndex]; 265 String pkgName = pkgDiff.name_; 266 267 PrintWriter oldReportFile = null; 268 oldReportFile = reportFile; 269 String localReportFileName = null; 270 try { 271 // Prefix package files with pkg_ because there may be a class 272 // with the same name. 273 localReportFileName = reportFileName + JDiff.DIR_SEP + "pkg_" + pkgName + reportFileExt; 274 if (outputDir != null) 275 localReportFileName = outputDir + JDiff.DIR_SEP + localReportFileName; 276 FileOutputStream fos = new FileOutputStream(localReportFileName); 277 reportFile = new PrintWriter(fos); 278 writeStartHTMLHeader(); 279 writeHTMLTitle(pkgName); 280 writeStyleSheetRef(); 281 writeText("</HEAD>"); 282 writeText("<BODY>"); 283 } catch(IOException e) { 284 System.out.println("IO Error while attempting to create " + localReportFileName); 285 System.out.println("Error: "+ e.getMessage()); 286 System.exit(1); 287 } 288 289 String pkgRef = pkgName; 290 pkgRef = pkgRef.replace('.', '/'); 291 pkgRef = newDocPrefix + pkgRef + "/package-summary"; 292 // A link to the package in the new API 293 String linkedPkgName = "<A HREF=\"" + pkgRef + ".html\" target=\"_top\"><font size=\"+1\"><tt>" + pkgName + "</tt></font></A>"; 294 String prevPkgRef = null; 295 if (pkgIndex != 0) { 296 prevPkgRef = "pkg_" + pkgDiffs[pkgIndex-1].name_ + reportFileExt; 297 } 298 // Create the HTML link to the next package 299 String nextPkgRef = null; 300 if (pkgIndex < pkgDiffs.length - 1) { 301 nextPkgRef = "pkg_" + pkgDiffs[pkgIndex+1].name_ + reportFileExt; 302 } 303 304 writeSectionHeader("Package " + linkedPkgName, pkgName, 305 prevPkgRef, nextPkgRef, 306 null, 1, 307 pkgDiff.classesRemoved.size() != 0, 308 pkgDiff.classesAdded.size() != 0, 309 pkgDiff.classesChanged.size() != 0); 310 311 // Report changes in documentation 312 if (reportDocChanges && pkgDiff.documentationChange_ != null) { 313 String pkgDocRef = pkgName + "/package-summary"; 314 pkgDocRef = pkgDocRef.replace('.', '/'); 315 String oldPkgRef = pkgDocRef; 316 String newPkgRef = pkgDocRef; 317 if (oldDocPrefix != null) 318 oldPkgRef = oldDocPrefix + oldPkgRef; 319 else 320 oldPkgRef = null; 321 newPkgRef = newDocPrefix + newPkgRef; 322 if (oldPkgRef != null) 323 pkgDiff.documentationChange_ += "<A HREF=\"" + oldPkgRef + 324 ".html#package_description\" target=\"_self\"><font size=\"+1\"><tt>old</tt></font></A> to "; 325 else 326 pkgDiff.documentationChange_ += "<font size=\"+1\"><tt>old</tt></font> to "; 327 pkgDiff.documentationChange_ += "<A HREF=\"" + newPkgRef + 328 ".html#package_description\" target=\"_self\"><font size=\"+1\"><tt>new</tt></font></A>. "; 329 writeText(pkgDiff.documentationChange_); 330 } 331 332 // Report classes which were removed in the new API 333 if (pkgDiff.classesRemoved.size() != 0) { 334 // Determine the title for this section 335 boolean hasClasses = false; 336 boolean hasInterfaces = false; 337 Iterator iter = pkgDiff.classesRemoved.iterator(); 338 while (iter.hasNext()) { 339 ClassAPI classAPI = (ClassAPI)(iter.next()); 340 if (classAPI.isInterface_) 341 hasInterfaces = true; 342 else 343 hasClasses = true; 344 } 345 if (hasInterfaces && hasClasses) 346 writeTableStart("Removed Classes and Interfaces", 2); 347 else if (!hasInterfaces && hasClasses) 348 writeTableStart("Removed Classes", 2); 349 else if (hasInterfaces && !hasClasses) 350 writeTableStart("Removed Interfaces", 2); 351 // Emit the table entries 352 iter = pkgDiff.classesRemoved.iterator(); 353 while (iter.hasNext()) { 354 ClassAPI classAPI = (ClassAPI)(iter.next()); 355 String className = classAPI.name_; 356 if (trace) System.out.println("Class/Interface " + className + " was removed."); 357 writeClassTableEntry(pkgName, className, 0, classAPI.isInterface_, classAPI.doc_, false); 358 } 359 writeTableEnd(); 360 } 361 362 // Report classes which were added in the new API 363 if (pkgDiff.classesAdded.size() != 0) { 364 // Determine the title for this section 365 boolean hasClasses = false; 366 boolean hasInterfaces = false; 367 Iterator iter = pkgDiff.classesAdded.iterator(); 368 while (iter.hasNext()) { 369 ClassAPI classAPI = (ClassAPI)(iter.next()); 370 if (classAPI.isInterface_) 371 hasInterfaces = true; 372 else 373 hasClasses = true; 374 } 375 if (hasInterfaces && hasClasses) 376 writeTableStart("Added Classes and Interfaces", 2); 377 else if (!hasInterfaces && hasClasses) 378 writeTableStart("Added Classes", 2); 379 else if (hasInterfaces && !hasClasses) 380 writeTableStart("Added Interfaces", 2); 381 // Emit the table entries 382 iter = pkgDiff.classesAdded.iterator(); 383 while (iter.hasNext()) { 384 ClassAPI classAPI = (ClassAPI)(iter.next()); 385 String className = classAPI.name_; 386 if (trace) System.out.println("Class/Interface " + className + " was added."); 387 writeClassTableEntry(pkgName, className, 1, classAPI.isInterface_, classAPI.doc_, false); 388 } 389 writeTableEnd(); 390 } 391 392 // Report classes which were changed in the new API 393 if (pkgDiff.classesChanged.size() != 0) { 394 // Determine the title for this section 395 boolean hasClasses = false; 396 boolean hasInterfaces = false; 397 Iterator iter = pkgDiff.classesChanged.iterator(); 398 while (iter.hasNext()) { 399 ClassDiff classDiff = (ClassDiff)(iter.next()); 400 if (classDiff.isInterface_) 401 hasInterfaces = true; 402 else 403 hasClasses = true; 404 } 405 if (hasInterfaces && hasClasses) 406 writeTableStart("Changed Classes and Interfaces", 2); 407 else if (!hasInterfaces && hasClasses) 408 writeTableStart("Changed Classes", 2); 409 else if (hasInterfaces && !hasClasses) 410 writeTableStart("Changed Interfaces", 2); 411 // Emit a table of changed classes, with links to the file 412 // for each class. 413 iter = pkgDiff.classesChanged.iterator(); 414 while (iter.hasNext()) { 415 ClassDiff classDiff = (ClassDiff)(iter.next()); 416 String className = classDiff.name_; 417 if (trace) System.out.println("Package " + pkgDiff.name_ + ", class/Interface " + className + " was changed."); 418 writeClassTableEntry(pkgName, className, 2, classDiff.isInterface_, null, false); 419 } 420 writeTableEnd(); 421 // Now emit a separate file for each changed class and interface. 422 ClassDiff[] classDiffs = new ClassDiff[pkgDiff.classesChanged.size()]; 423 classDiffs = (ClassDiff[])pkgDiff.classesChanged.toArray(classDiffs); 424 for (int k = 0; k < classDiffs.length; k++) { 425 reportChangedClass(pkgName, classDiffs, k); 426 } 427 } 428 429 writeSectionFooter(pkgName, prevPkgRef, nextPkgRef, null, 1); 430 writeHTMLFooter(); 431 reportFile.close(); 432 reportFile = oldReportFile; 433 } 434 435 /** 436 * Write out the details of a changed class in a separate file. 437 */ reportChangedClass(String pkgName, ClassDiff[] classDiffs, int classIndex)438 public void reportChangedClass(String pkgName, ClassDiff[] classDiffs, int classIndex) { 439 ClassDiff classDiff = classDiffs[classIndex]; 440 String className = classDiff.name_; 441 442 PrintWriter oldReportFile = null; 443 oldReportFile = reportFile; 444 String localReportFileName = null; 445 try { 446 localReportFileName = reportFileName + JDiff.DIR_SEP + pkgName + "." + className + reportFileExt; 447 if (outputDir != null) 448 localReportFileName = outputDir + JDiff.DIR_SEP + localReportFileName; 449 FileOutputStream fos = new FileOutputStream(localReportFileName); 450 reportFile = new PrintWriter(fos); 451 writeStartHTMLHeader(); 452 writeHTMLTitle(pkgName + "." + className); 453 writeStyleSheetRef(); 454 writeText("</HEAD>"); 455 writeText("<BODY>"); 456 } catch(IOException e) { 457 System.out.println("IO Error while attempting to create " + localReportFileName); 458 System.out.println("Error: "+ e.getMessage()); 459 System.exit(1); 460 } 461 462 String classRef = pkgName + "." + className; 463 classRef = classRef.replace('.', '/'); 464 if (className.indexOf('.') != -1) { 465 classRef = pkgName + "."; 466 classRef = classRef.replace('.', '/'); 467 classRef = newDocPrefix + classRef + className; 468 } else { 469 classRef = newDocPrefix + classRef; 470 } 471 // A link to the class in the new API 472 String linkedClassName = "<A HREF=\"" + classRef + ".html\" target=\"_top\"><font size=\"+1\"><tt>" + className + "</tt></font></A>"; 473 String lcn = pkgName + "." + linkedClassName; 474 //Links to the previous and next classes 475 String prevClassRef = null; 476 if (classIndex != 0) { 477 prevClassRef = pkgName + "." + classDiffs[classIndex-1].name_ + reportFileExt; 478 } 479 // Create the HTML link to the next package 480 String nextClassRef = null; 481 if (classIndex < classDiffs.length - 1) { 482 nextClassRef = pkgName + "." + classDiffs[classIndex+1].name_ + reportFileExt; 483 } 484 485 if (classDiff.isInterface_) 486 lcn = "Interface " + lcn; 487 else 488 lcn = "Class " + lcn; 489 boolean hasCtors = classDiff.ctorsRemoved.size() != 0 || 490 classDiff.ctorsAdded.size() != 0 || 491 classDiff.ctorsChanged.size() != 0; 492 boolean hasMethods = classDiff.methodsRemoved.size() != 0 || 493 classDiff.methodsAdded.size() != 0 || 494 classDiff.methodsChanged.size() != 0; 495 boolean hasFields = classDiff.fieldsRemoved.size() != 0 || 496 classDiff.fieldsAdded.size() != 0 || 497 classDiff.fieldsChanged.size() != 0; 498 writeSectionHeader(lcn, pkgName, prevClassRef, nextClassRef, 499 className, 2, 500 hasCtors, hasMethods, hasFields); 501 502 if (classDiff.inheritanceChange_ != null) 503 writeText("<p><font xsize=\"+1\">" + classDiff.inheritanceChange_ + "</font>"); 504 505 // Report changes in documentation 506 if (reportDocChanges && classDiff.documentationChange_ != null) { 507 String oldClassRef = null; 508 if (oldDocPrefix != null) { 509 oldClassRef = pkgName + "." + className; 510 oldClassRef = oldClassRef.replace('.', '/'); 511 if (className.indexOf('.') != -1) { 512 oldClassRef = pkgName + "."; 513 oldClassRef = oldClassRef.replace('.', '/'); 514 oldClassRef = oldDocPrefix + oldClassRef + className; 515 } else { 516 oldClassRef = oldDocPrefix + oldClassRef; 517 } 518 } 519 if (oldDocPrefix != null) 520 classDiff.documentationChange_ += "<A HREF=\"" + oldClassRef + 521 ".html\" target=\"_self\"><font size=\"+1\"><tt>old</tt></font></A> to "; 522 else 523 classDiff.documentationChange_ += "<font size=\"+1\"><tt>old</tt></font> to "; 524 classDiff.documentationChange_ += "<A HREF=\"" + classRef + 525 ".html\" target=\"_self\"><font size=\"+1\"><tt>new</tt></font></A>. "; 526 writeText(classDiff.documentationChange_); 527 } 528 529 if (classDiff.modifiersChange_ != null) 530 writeText("<p>" + classDiff.modifiersChange_); 531 532 reportAllCtors(pkgName, classDiff); 533 reportAllMethods(pkgName, classDiff); 534 reportAllFields(pkgName, classDiff); 535 536 writeSectionFooter(pkgName, prevClassRef, nextClassRef, className, 2); 537 writeHTMLFooter(); 538 reportFile.close(); 539 reportFile = oldReportFile; 540 } 541 542 /** 543 * Write out the details of constructors in a class. 544 */ reportAllCtors(String pkgName, ClassDiff classDiff)545 public void reportAllCtors(String pkgName, ClassDiff classDiff) { 546 String className = classDiff.name_; 547 writeText("<a NAME=\"constructors\"></a>"); // Named anchor 548 // Report ctors which were removed in the new API 549 if (classDiff.ctorsRemoved.size() != 0) { 550 writeTableStart("Removed Constructors", 2); 551 Iterator iter = classDiff.ctorsRemoved.iterator(); 552 while (iter.hasNext()) { 553 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next()); 554 String ctorType = ctorAPI.type_; 555 if (ctorType.compareTo("void") == 0) 556 ctorType = ""; 557 String id = className + "(" + ctorType + ")"; 558 if (trace) System.out.println("Constructor " + id + " was removed."); 559 writeCtorTableEntry(pkgName, className, ctorType, 0, ctorAPI.doc_, false); 560 } 561 writeTableEnd(); 562 } 563 564 // Report ctors which were added in the new API 565 if (classDiff.ctorsAdded.size() != 0) { 566 writeTableStart("Added Constructors", 2); 567 Iterator iter = classDiff.ctorsAdded.iterator(); 568 while (iter.hasNext()) { 569 ConstructorAPI ctorAPI = (ConstructorAPI)(iter.next()); 570 String ctorType = ctorAPI.type_; 571 if (ctorType.compareTo("void") == 0) 572 ctorType = ""; 573 String id = className + "(" + ctorType + ")"; 574 if (trace) System.out.println("Constructor " + id + " was added."); 575 writeCtorTableEntry(pkgName, className, ctorType, 1, ctorAPI.doc_, false); 576 } 577 writeTableEnd(); 578 } 579 580 // Report ctors which were changed in the new API 581 if (classDiff.ctorsChanged.size() != 0) { 582 // Emit a table of changed classes, with links to the section 583 // for each class. 584 writeTableStart("Changed Constructors", 3); 585 Iterator iter = classDiff.ctorsChanged.iterator(); 586 while (iter.hasNext()) { 587 MemberDiff memberDiff = (MemberDiff)(iter.next()); 588 if (trace) System.out.println("Constructor for " + className + 589 " was changed from " + memberDiff.oldType_ + " to " + 590 memberDiff.newType_); 591 writeCtorChangedTableEntry(pkgName, className, memberDiff); 592 } 593 writeTableEnd(); 594 } 595 } 596 597 /** 598 * Write out the details of methods in a class. 599 */ reportAllMethods(String pkgName, ClassDiff classDiff)600 public void reportAllMethods(String pkgName, ClassDiff classDiff) { 601 writeText("<a NAME=\"methods\"></a>"); // Named anchor 602 String className = classDiff.name_; 603 // Report methods which were removed in the new API 604 if (classDiff.methodsRemoved.size() != 0) { 605 writeTableStart("Removed Methods", 2); 606 Iterator iter = classDiff.methodsRemoved.iterator(); 607 while (iter.hasNext()) { 608 MethodAPI methodAPI = (MethodAPI)(iter.next()); 609 String methodName = methodAPI.name_ + "(" + methodAPI.getSignature() + ")"; 610 if (trace) System.out.println("Method " + methodName + " was removed."); 611 writeMethodTableEntry(pkgName, className, methodAPI, 0, methodAPI.doc_, false); 612 } 613 writeTableEnd(); 614 } 615 616 // Report methods which were added in the new API 617 if (classDiff.methodsAdded.size() != 0) { 618 writeTableStart("Added Methods", 2); 619 Iterator iter = classDiff.methodsAdded.iterator(); 620 while (iter.hasNext()) { 621 MethodAPI methodAPI = (MethodAPI)(iter.next()); 622 String methodName = methodAPI.name_ + "(" + methodAPI.getSignature() + ")"; 623 if (trace) System.out.println("Method " + methodName + " was added."); 624 writeMethodTableEntry(pkgName, className, methodAPI, 1, methodAPI.doc_, false); 625 } 626 writeTableEnd(); 627 } 628 629 // Report methods which were changed in the new API 630 if (classDiff.methodsChanged.size() != 0) { 631 // Emit a table of changed methods. 632 writeTableStart("Changed Methods", 3); 633 Iterator iter = classDiff.methodsChanged.iterator(); 634 while (iter.hasNext()) { 635 MemberDiff memberDiff = (MemberDiff)(iter.next()); 636 if (trace) System.out.println("Method " + memberDiff.name_ + 637 " was changed."); 638 writeMethodChangedTableEntry(pkgName, className, memberDiff); 639 } 640 writeTableEnd(); 641 } 642 } 643 644 /** 645 * Write out the details of fields in a class. 646 */ reportAllFields(String pkgName, ClassDiff classDiff)647 public void reportAllFields(String pkgName, ClassDiff classDiff) { 648 writeText("<a NAME=\"fields\"></a>"); // Named anchor 649 String className = classDiff.name_; 650 // Report fields which were removed in the new API 651 if (classDiff.fieldsRemoved.size() != 0) { 652 writeTableStart("Removed Fields", 2); 653 Iterator iter = classDiff.fieldsRemoved.iterator(); 654 while (iter.hasNext()) { 655 FieldAPI fieldAPI = (FieldAPI)(iter.next()); 656 String fieldName = fieldAPI.name_; 657 if (trace) System.out.println("Field " + fieldName + " was removed."); 658 writeFieldTableEntry(pkgName, className, fieldAPI, 0, fieldAPI.doc_, false); 659 } 660 writeTableEnd(); 661 } 662 663 // Report fields which were added in the new API 664 if (classDiff.fieldsAdded.size() != 0) { 665 writeTableStart("Added Fields", 2); 666 Iterator iter = classDiff.fieldsAdded.iterator(); 667 while (iter.hasNext()) { 668 FieldAPI fieldAPI = (FieldAPI)(iter.next()); 669 String fieldName = fieldAPI.name_; 670 if (trace) System.out.println("Field " + fieldName + " was added."); 671 writeFieldTableEntry(pkgName, className, fieldAPI, 1, fieldAPI.doc_, false); 672 } 673 writeTableEnd(); 674 } 675 676 // Report fields which were changed in the new API 677 if (classDiff.fieldsChanged.size() != 0) { 678 // Emit a table of changed classes, with links to the section 679 // for each class. 680 writeTableStart("Changed Fields", 3); 681 Iterator iter = classDiff.fieldsChanged.iterator(); 682 while (iter.hasNext()) { 683 MemberDiff memberDiff = (MemberDiff)(iter.next()); 684 if (trace) System.out.println("Field " + pkgName + "." + className + "." + memberDiff.name_ + " was changed from " + memberDiff.oldType_ + " to " + memberDiff.newType_); 685 writeFieldChangedTableEntry(pkgName, className, memberDiff); 686 } 687 writeTableEnd(); 688 } 689 690 } 691 692 /** 693 * Write the start of the HTML header, together with the current 694 * date and time in an HTML comment. 695 */ writeStartHTMLHeaderWithDate()696 public void writeStartHTMLHeaderWithDate() { 697 writeStartHTMLHeader(true); 698 } 699 700 /** Write the start of the HTML header. */ writeStartHTMLHeader()701 public void writeStartHTMLHeader() { 702 writeStartHTMLHeader(false); 703 } 704 705 /** Write the start of the HTML header. */ writeStartHTMLHeader(boolean addDate)706 public void writeStartHTMLHeader(boolean addDate) { 707 writeText("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">"); 708 writeText("<HTML>"); 709 writeText("<HEAD>"); 710 writeText("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">"); 711 writeText("<!-- Generated by the JDiff Javadoc doclet -->"); 712 writeText("<!-- (" + JDiff.jDiffLocation + ") -->"); 713 if (addDate) 714 writeText("<!-- on " + new Date() + " -->"); 715 writeText("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">"); 716 writeText("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">"); 717 } 718 719 /** Write the HTML title */ writeHTMLTitle(String title)720 public void writeHTMLTitle(String title) { 721 writeText("<TITLE>"); 722 writeText(title); 723 writeText("</TITLE>"); 724 } 725 726 /** 727 * Write the HTML style sheet reference for files in the subdirectory. 728 */ writeStyleSheetRef()729 public void writeStyleSheetRef() { 730 writeStyleSheetRef(false); 731 } 732 733 /** 734 * Write the HTML style sheet reference. If inSameDir is set, don't add 735 * "../" to the location. 736 */ 737 writeStyleSheetRef(boolean inSameDir)738 public void writeStyleSheetRef(boolean inSameDir) { 739 if (inSameDir) { 740 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/codesite.css\" />"); 741 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/codesearch.css\" />"); 742 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/semantic_headers.css\" />"); 743 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/style.css\" />"); 744 writeText("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"stylesheet-jdiff.css\" TITLE=\"Style\">"); 745 } 746 else { 747 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/codesite.css\" />"); 748 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/codesearch.css\" />"); 749 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/codesite/semantic_headers.css\" />"); 750 writeText("<link rel=\"stylesheet\" type=\"text/css\" href=\"../../../assets/style.css\" />"); 751 writeText("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"../stylesheet-jdiff.css\" TITLE=\"Style\">"); 752 } 753 // This doesn't work in non-windows browsers, so have to change the stylesheet 754 // writeText("<!-- Override the color choice for the navigation bar -->"); 755 // writeText("<STYLE>"); 756 // //writeText(".NavBarCell1 { background-color:#FFFF99;} /* palegoldenrod */"); 757 // writeText(".NavBarCell1 { background-color:#FFFFCC;} /* */"); 758 // writeText("</STYLE>"); 759 } 760 761 /** Write the HTML footer. */ writeHTMLFooter()762 public void writeHTMLFooter() { 763 writeText("<script src=\"http://www.google-analytics.com/ga.js\" type=\"text/javascript\">"); 764 writeText("</script>"); 765 writeText("<script type=\"text/javascript\">"); 766 writeText(" try {"); 767 writeText(" var pageTracker = _gat._getTracker(\"UA-18071-1\");"); 768 writeText(" pageTracker._setAllowAnchor(true);"); 769 writeText(" pageTracker._initData();"); 770 writeText(" pageTracker._trackPageview();"); 771 writeText(" } catch(e) {}"); 772 writeText("</script>"); 773 writeText("</BODY>"); 774 writeText("</HTML>"); 775 } 776 777 /** 778 * Write a section header, which includes a navigation bar. 779 * 780 * @param title Title of the header. Contains any links necessary. 781 * @param packageName The name of the current package, with no slashes or 782 * links in it. May be null 783 * @param prevElemLink An HTML link to the previous element (a package or 784 * class). May be null. 785 * @param nextElemLink An HTML link to the next element (a package or 786 * class). May be null. 787 * @param className The name of the current class, with no slashes or 788 * links in it. May be null. 789 * @param level 0 = overview, 1 = package, 2 = class/interface 790 */ writeSectionHeader(String title, String packageName, String prevElemLink, String nextElemLink, String className, int level, boolean hasRemovals, boolean hasAdditions, boolean hasChanges)791 public void writeSectionHeader(String title, String packageName, 792 String prevElemLink, String nextElemLink, 793 String className, int level, 794 boolean hasRemovals, 795 boolean hasAdditions, 796 boolean hasChanges) { 797 writeNavigationBar(packageName, prevElemLink, nextElemLink, 798 className, level, true, 799 hasRemovals, hasAdditions, hasChanges); 800 if (level != 0) { 801 reportFile.println("<H2>"); 802 reportFile.println(title); 803 reportFile.println("</H2>"); 804 } 805 } 806 807 /** 808 * Write a section footer, which includes a navigation bar. 809 * 810 * @param packageName The name of the current package, with no slashes or 811 * links in it. may be null 812 * @param prevElemLink An HTML link to the previous element (a package or 813 * class). May be null. 814 * @param nextElemLink An HTML link to the next element (a package or 815 * class). May be null. 816 * @param className The name of the current class, with no slashes or 817 * links in it. May be null 818 * @param level 0 = overview, 1 = package, 2 = class/interface 819 */ writeSectionFooter(String packageName, String prevElemLink, String nextElemLink, String className, int level)820 public void writeSectionFooter(String packageName, 821 String prevElemLink, String nextElemLink, 822 String className, int level) { 823 writeText("</div><!-- end codesitecontent -->"); 824 writeText("<div style=\"padding-left: 10px; padding-right: 10px; margin-top: 0; padding-bottom: 15px;\">"); 825 writeText(" <table style=\"width: 100%; border: none;\"><tr>"); 826 writeText(" <td style=\"text-align:center;font-size: 10pt; border: none; color: ccc;\"> "); 827 writeText(" <span>©2008 Google - "); 828 writeText(" <a href=\"http://code.google.com\">Code Home</a> - "); 829 writeText(" <a href=\"http://www.google.com/accounts/TOS\">Site Terms of Service</a> - "); 830 writeText(" <a href=\"http://www.google.com/privacy.html\">Privacy Policy</a> "); 831 writeText(" </span>"); 832 writeText(" <div style=\"xborder:1px solid red;position:relative;margin-top:-2em;" ); 833 writeText(" font-size:8pt;color:aaa;text-align:right;\">"); 834 writeText(" <em>Generated by <a href=\"http://www.jdiff.org/\">JDiff</a></em><br><img "); 835 writeText(" align=\"right\" src=\"../../../assets/jdiff_logo.gif\">"); 836 writeText(" </span>"); 837 writeText(" </td>"); 838 writeText(" </tr></table>"); 839 writeText("</div>"); 840 writeText("</div><!-- end gc-containter -->"); 841 /* 842 reportFile.println("<HR>"); 843 writeNavigationBar(packageName, prevElemLink, nextElemLink, 844 className, level, false, 845 false, false, false); 846 */ 847 } 848 849 /** 850 * Write a navigation bar section header. 851 * 852 * @param pkgName The name of the current package, with no slashes or 853 * links in it. 854 * @param prevElemLink An HTML link to the previous element (a package or 855 * class). May be null. 856 * @param nextElemLink An HTML link to the next element (a package or 857 * class). May be null. 858 * @param className The name of the current class, with no slashes or 859 * links in it. May be null. 860 * @param level 0 = overview, 1 = package, 2 = class/interface 861 */ 862 writeNavigationBar(String pkgName, String prevElemLink, String nextElemLink, String className, int level, boolean upperNavigationBar, boolean hasRemovals, boolean hasAdditions, boolean hasChanges)863 public void writeNavigationBar(String pkgName, 864 String prevElemLink, String nextElemLink, 865 String className, int level, 866 boolean upperNavigationBar, 867 boolean hasRemovals, boolean hasAdditions, 868 boolean hasChanges) { 869 870 String oldAPIName = "Old API"; 871 if (apiDiff.oldAPIName_ != null) 872 oldAPIName = apiDiff.oldAPIName_; 873 String newAPIName = "New API"; 874 if (apiDiff.newAPIName_ != null) 875 newAPIName = apiDiff.newAPIName_; 876 877 SimpleDateFormat formatter 878 = new SimpleDateFormat ("yyyy.MM.dd HH:mm"); 879 Date day = new Date(); 880 881 reportFile.println("<!-- Start of nav bar -->"); 882 883 reportFile.println("<div id=\"gc-container\" style=\"padding-left:1em;padding-right:1em;\" id=\"pagecontent\">"); 884 reportFile.println("<a name=\"top\"></a>"); 885 reportFile.println("<div id=\"gc-header\">"); 886 reportFile.println(" <div id=\"logo\" style=\"padding-left:1em;\">"); 887 reportFile.println(" <a href=\"../../../documentation.html\" target=\"_top\"><img style=\"border: 0;\" src=\"../../../assets-google/android-logo-sm.gif\" \"/></a>"); 888 reportFile.println(" </div> <!-- End logo -->"); 889 reportFile.println(" <div class=\"and-diff-id\">"); 890 reportFile.println(" <table class=\"diffspectable\">"); 891 reportFile.println(" <tr>"); 892 reportFile.println(" <td colspan=\"2\" class=\"diffspechead\">API Diff Specification</td>"); 893 reportFile.println(" </tr>"); 894 reportFile.println(" <tr>"); 895 reportFile.println(" <td class=\"diffspec\" style=\"padding-top:.25em\">To Version:</td>"); 896 reportFile.println(" <td class=\"diffvaluenew\" style=\"padding-top:.25em\">" + newAPIName + "</td>"); 897 reportFile.println(" </tr>"); 898 reportFile.println(" <tr>"); 899 reportFile.println(" <td class=\"diffspec\">From Version:</td>"); 900 reportFile.println(" <td class=\"diffvalueold\">" + oldAPIName + "</td>"); 901 reportFile.println(" </tr>"); 902 // reportFile.println(" <tr>"); 903 // reportFile.println(" <td class=\"diffspec\">Product Type:</td>"); 904 // reportFile.println(" <td class=\"diffvalue\">Generic</td>"); 905 // reportFile.println(" </tr>"); 906 reportFile.println(" <tr>"); 907 reportFile.println(" <td class=\"diffspec\">Generated</td>"); 908 reportFile.println(" <td class=\"diffvalue\">" + formatter.format( day ) + "</td>"); 909 reportFile.println(" </tr>"); 910 reportFile.println(" </table>"); 911 reportFile.println(" </div> <!-- End and-diff-id -->"); 912 913 if (doStats) { 914 reportFile.println(" <div class=\"and-diff-id\">"); 915 reportFile.println(" <table class=\"diffspectable\">"); 916 reportFile.println(" <tr>"); 917 reportFile.println(" <td class=\"diffspec\" colspan=\"2\"><a href=\"jdiff_statistics.html\">Statistics</a></div>"); 918 reportFile.println(" </tr>"); 919 reportFile.println(" </table>"); 920 reportFile.println(" </div> <!-- End and-diff-id -->"); 921 } 922 923 reportFile.println("</div> <!-- End gc-header -->"); 924 reportFile.println("<div id=\"codesiteContent\" style=\"margin-top: 70px;margin-bottom:80px;\">"); 925 926 /* 927 reportFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">"); 928 reportFile.println(" <TR>"); 929 reportFile.println(" <TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">"); 930 reportFile.println(" <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">"); 931 reportFile.println(" <TR ALIGN=\"center\" VALIGN=\"top\">"); 932 boolean atOverview = (level == 0); 933 boolean atPackage = (level == 1); 934 boolean atClass = (level == 2); 935 936 // Always have a link to the Javadoc files 937 if (atOverview) { 938 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + newDocPrefix + "index.html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><font size=\"+1\"><tt>" + apiDiff.newAPIName_ + "</tt></font></B></FONT></A> </TD>"); 939 } else if (atPackage) { 940 String pkgRef = pkgName; 941 pkgRef = pkgRef.replace('.', '/'); 942 pkgRef = newDocPrefix + pkgRef + "/package-summary"; 943 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + pkgRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><font size=\"+1\"><tt>" + apiDiff.newAPIName_ + "</tt></font></B></FONT></A> </TD>"); 944 } else if (atClass) { 945 String classRef = pkgName + "." + className; 946 classRef = classRef.replace('.', '/'); 947 if (className.indexOf('.') != -1) { 948 classRef = pkgName + "."; 949 classRef = classRef.replace('.', '/'); 950 classRef = newDocPrefix + classRef + className; 951 } else { 952 classRef = newDocPrefix + classRef; 953 } 954 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + classRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><font size=\"+1\"><tt>" + apiDiff.newAPIName_ + "</tt></font></B></FONT></A> </TD>"); 955 } 956 957 if (atOverview) { 958 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> <FONT CLASS=\"NavBarFont1Rev\"><B>Overview</B></FONT> </TD>"); 959 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Package</FONT> </TD>"); 960 reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Class</FONT> </TD>"); 961 } 962 963 String changesSummaryName = reportFileName + "-summary" + reportFileExt; 964 if (atPackage) { 965 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + changesSummaryName + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A> </TD>"); 966 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> <FONT CLASS=\"NavBarFont1Rev\"><B>Package</B></FONT> </TD>"); 967 reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Class</FONT> </TD>"); 968 } 969 if (atClass) { 970 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + changesSummaryName + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A> </TD>"); 971 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"pkg_" + pkgName + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Package</B></FONT></A> </TD>"); 972 reportFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1Rev\"> <FONT CLASS=\"NavBarFont1Rev\"><B>Class</B></FONT> </TD>"); 973 } 974 975 if (!Diff.noDocDiffs) { 976 if (atPackage) { 977 String id = (String)Diff.firstDiffOutput.get(pkgName + "!package"); 978 if (id != null) 979 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "#" + id + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A> </TD>"); 980 else 981 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Text Changes</FONT> </TD>"); 982 } else if (atClass) { 983 String id = (String)Diff.firstDiffOutput.get(pkgName + "." + className + "!class"); 984 if (id != null) 985 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "#" + id + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A> </TD>"); 986 else 987 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Text Changes</FONT> </TD>"); 988 } else { 989 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A> </TD>"); 990 } 991 } 992 993 if (doStats) { 994 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A> </TD>"); 995 } 996 997 // Always have a link to the JDiff help file 998 reportFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A> </TD>"); 999 reportFile.println(" </TR>"); 1000 reportFile.println(" </TABLE>"); 1001 reportFile.println(" </TD>"); 1002 1003 // The right hand side title, only added at the top 1004 if (upperNavigationBar) { 1005 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>"); 1006 } else { 1007 reportFile.println(" <TD ALIGN=\"right\" VALIGN=\"top\" ROWSPAN=3></TD>"); 1008 } 1009 reportFile.println("</TR>"); 1010 1011 // Links for frames and no frames 1012 reportFile.println("<TR>"); 1013 1014 // All of the previous and next links, and the frames and non-frames 1015 // links are in one table cell 1016 reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">"); 1017 // Display links to the previous and next packages or classes 1018 if (atPackage || atClass) { 1019 String elemName = "CLASS"; 1020 if (className == null) { 1021 elemName = "PACKAGE"; 1022 } 1023 if (prevElemLink == null) { 1024 reportFile.println(" <B>PREV " + elemName + "</B> "); 1025 } else { 1026 reportFile.println(" <A HREF=\"" + prevElemLink + "\"><B>PREV " + elemName + "</B></A>"); 1027 } 1028 if (nextElemLink == null) { 1029 reportFile.println(" <B>NEXT " + elemName + "</B> "); 1030 } else { 1031 reportFile.println(" <A HREF=\"" + nextElemLink + "\"><B>NEXT " + elemName + "</B></A>"); 1032 } 1033 reportFile.println(" "); 1034 } else { 1035 reportFile.println(" "); 1036 } 1037 // Links for frames and non-frames. 1038 reportFile.println(" <A HREF=\"" + "../" + reportFileName + reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A> "); 1039 if (className == null) { 1040 if (level == 0) { 1041 reportFile.println(" <A HREF=\"" + pkgName + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>"); 1042 } else { 1043 reportFile.println(" <A HREF=\"pkg_" + pkgName + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>"); 1044 } 1045 } else { 1046 reportFile.println(" <A HREF=\"" + pkgName + "." + className + reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>"); 1047 } 1048 1049 // All of the details links are in one table cell 1050 if (atClass) { 1051 // Links to a class page's sections 1052 // The meaning of these three variable is overloaded 1053 boolean hasCtors = hasRemovals; 1054 boolean hasMethods = hasAdditions; 1055 boolean hasFields = hasChanges; 1056 if (hasCtors || hasMethods || hasFields) { 1057 reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell3\"><FONT SIZE=\"-2\"> DETAIL: "); 1058 if (hasCtors) { 1059 reportFile.println("<a href=\"#constructors\">CONSTRUCTORS</a> | "); 1060 } else { 1061 reportFile.println("CONSTRUCTORS | "); 1062 } 1063 if (hasMethods) { 1064 reportFile.println("<a href=\"#methods\">METHODS</a> | "); 1065 } else { 1066 reportFile.println("METHODS | "); 1067 } 1068 if (hasFields) { 1069 reportFile.println("<a href=\"#fields\">FIELDS</a>"); 1070 } else { 1071 reportFile.println("FIELDS"); 1072 } 1073 reportFile.println(" </FONT></TD>"); 1074 } else { 1075 // Make the end of the table line match the length of the top 1076 reportFile.println("<TD BGCOLOR=\"0xFFFFFF\" CLASS=\"NavBarCell3\"></TD>"); 1077 } 1078 } else { 1079 // Links to a package page's sections 1080 if (hasRemovals || hasAdditions || hasChanges) { 1081 reportFile.println(" <TD BGCOLOR=\"" + bgcolor + "\" CLASS=\"NavBarCell3\"><FONT SIZE=\"-2\"> DETAIL: "); 1082 if (hasRemovals) { 1083 reportFile.println("<a href=\"#Removed\">REMOVED</a> | "); 1084 } else { 1085 reportFile.println("REMOVED | "); 1086 } 1087 if (hasAdditions) { 1088 reportFile.println("<a href=\"#Added\">ADDED</a> | "); 1089 } else { 1090 reportFile.println("ADDED | "); 1091 } 1092 if (hasChanges) { 1093 reportFile.println("<a href=\"#Changed\">CHANGED</a>"); 1094 } else { 1095 reportFile.println("CHANGED"); 1096 } 1097 reportFile.println(" </FONT></TD>"); 1098 } else { 1099 // Make the end of the table line match the length of the top 1100 reportFile.println("<TD BGCOLOR=\"0xFFFFFF\" CLASS=\"NavBarCell3\"></TD>"); 1101 } 1102 } 1103 1104 reportFile.println("</TR>"); 1105 reportFile.println("</TABLE>"); 1106 reportFile.println("<HR>"); 1107 reportFile.println("<!-- End of nav bar -->"); 1108 */ 1109 } 1110 1111 /** Write the start of a table. */ writeTableStart(String title, int colSpan)1112 public void writeTableStart(String title, int colSpan) { 1113 reportFile.println("<p>"); 1114 // Assumes that the first word of the title categorizes the table type 1115 // and that there is a space after the first word in the title 1116 int idx = title.indexOf(' '); 1117 String namedAnchor = title.substring(0, idx); 1118 reportFile.println("<a NAME=\"" + namedAnchor + "\"></a>"); // Named anchor 1119 reportFile.println("<TABLE summary=\"" + title+ "\" WIDTH=\"100%\">"); 1120 reportFile.println("<TR>"); 1121 reportFile.print(" <TH VALIGN=\"TOP\" COLSPAN=" + colSpan + ">"); 1122 reportFile.println(title + "</FONT></TD>"); 1123 reportFile.println("</TH>"); 1124 } 1125 1126 /** 1127 * If a class or package name is considered to be too long for convenient 1128 * display, insert <br> in the middle of it at a period. 1129 */ makeTwoRows(String name)1130 public String makeTwoRows(String name) { 1131 if (name.length() < 30) 1132 return name; 1133 int idx = name.indexOf(".", 20); 1134 if (idx == -1) 1135 return name; 1136 int len = name.length(); 1137 String res = name.substring(0, idx+1) + "<br>" + name.substring(idx+1, len); 1138 return res; 1139 } 1140 1141 /** 1142 * Write a table entry for a package, with support for links to Javadoc 1143 * for removed packages. 1144 * 1145 * linkType: 0 - no link by default, 1 = link to Javadoc HTML file, 2 = link to JDiff file 1146 */ writePackageTableEntry(String pkgName, int linkType, String possibleComment, boolean useOld)1147 public void writePackageTableEntry(String pkgName, int linkType, 1148 String possibleComment, boolean useOld) { 1149 if (!useOld) { 1150 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1151 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1152 reportFile.println(" <A NAME=\"" + pkgName + "\"></A>"); // Named anchor 1153 } 1154 //String shownPkgName = makeTwoRows(pkgName); 1155 if (linkType == 0) { 1156 if (oldDocPrefix == null) { 1157 // No link 1158 reportFile.print(" " + pkgName); 1159 } else { 1160 // Call this method again but this time to emit a link to the 1161 // old program element. 1162 writePackageTableEntry(pkgName, 1, possibleComment, true); 1163 } 1164 } else if (linkType == 1) { 1165 // Link to HTML file for the package 1166 String pkgRef = pkgName; 1167 pkgRef = pkgRef.replace('.', '/'); 1168 if (useOld) 1169 pkgRef = oldDocPrefix + pkgRef + "/package-summary"; 1170 else 1171 pkgRef = newDocPrefix + pkgRef + "/package-summary"; 1172 reportFile.println(" <nobr><A HREF=\"" + pkgRef + ".html\" target=\"_top\"><font size=\"+1\"><tt>" + pkgName + "</tt></font></A></nobr>"); 1173 } else if (linkType == 2) { 1174 reportFile.println(" <nobr><A HREF=\"pkg_" + pkgName + reportFileExt + "\">" + pkgName + "</A></nobr>"); 1175 } 1176 if (!useOld) { 1177 reportFile.println(" </TD>"); 1178 emitComment(pkgName, possibleComment, linkType); 1179 reportFile.println("</TR>"); 1180 } 1181 } 1182 1183 /** 1184 * Write a table entry for a class or interface. 1185 * 1186 * linkType: 0 - no link by default, 1 = link to Javadoc HTML file, 2 = link to JDiff file 1187 */ writeClassTableEntry(String pkgName, String className, int linkType, boolean isInterface, String possibleComment, boolean useOld)1188 public void writeClassTableEntry(String pkgName, String className, 1189 int linkType, boolean isInterface, 1190 String possibleComment, boolean useOld) { 1191 if (!useOld) { 1192 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1193 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1194 reportFile.println(" <A NAME=\"" + className + "\"></A>"); // Named anchor 1195 } 1196 String fqName = pkgName + "." + className; 1197 String shownClassName = makeTwoRows(className); 1198 if (linkType == 0) { 1199 if (oldDocPrefix == null) { 1200 // No link 1201 if (isInterface) 1202 reportFile.println(" <I>" + shownClassName + "</I>"); 1203 else 1204 reportFile.println(" " + shownClassName); 1205 } else { 1206 writeClassTableEntry(pkgName, className, 1207 1, isInterface, 1208 possibleComment, true); 1209 } 1210 } else if (linkType == 1) { 1211 // Link to HTML file for the class 1212 String classRef = fqName; 1213 // Deal with inner classes 1214 if (className.indexOf('.') != -1) { 1215 classRef = pkgName + "."; 1216 classRef = classRef.replace('.', '/'); 1217 if (useOld) 1218 classRef = oldDocPrefix + classRef + className; 1219 else 1220 classRef = newDocPrefix + classRef + className; 1221 } else { 1222 classRef = classRef.replace('.', '/'); 1223 if (useOld) 1224 classRef = oldDocPrefix + classRef; 1225 else 1226 classRef = newDocPrefix + classRef; 1227 } 1228 reportFile.print(" <nobr><A HREF=\"" + classRef + ".html\" target=\"_top\"><font size=\"+1\"><tt>"); 1229 if (isInterface) 1230 reportFile.print("<I>" + shownClassName + "</I>"); 1231 else 1232 reportFile.print(shownClassName); 1233 reportFile.println("</tt></font></A></nobr>"); 1234 } else if (linkType == 2) { 1235 reportFile.print(" <nobr><A HREF=\"" + fqName + reportFileExt + "\">"); 1236 if (isInterface) 1237 reportFile.print("<I>" + shownClassName + "</I>"); 1238 else 1239 reportFile.print(shownClassName); 1240 reportFile.println("</A></nobr>"); 1241 } 1242 if (!useOld) { 1243 reportFile.println(" </TD>"); 1244 emitComment(fqName, possibleComment, linkType); 1245 reportFile.println("</TR>"); 1246 } 1247 } 1248 1249 /** 1250 * Write a table entry for a constructor. 1251 * 1252 * linkType: 0 - no link by default, 1 = link to Javadoc HTML file 1253 */ writeCtorTableEntry(String pkgName, String className, String type, int linkType, String possibleComment, boolean useOld)1254 public void writeCtorTableEntry(String pkgName, String className, 1255 String type, int linkType, 1256 String possibleComment, boolean useOld) { 1257 String fqName = pkgName + "." + className; 1258 String shownClassName = makeTwoRows(className); 1259 String lt = "removed"; 1260 if (linkType ==1) 1261 lt = "added"; 1262 String commentID = fqName + ".ctor_" + lt + "(" + type + ")"; 1263 if (!useOld) { 1264 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1265 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1266 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1267 } 1268 String shortType = simpleName(type); 1269 if (linkType == 0) { 1270 if (oldDocPrefix == null) { 1271 // No link 1272 reportFile.print(" <nobr>" + pkgName); 1273 emitTypeWithParens(shortType); 1274 reportFile.println("</nobr>"); 1275 } else { 1276 writeCtorTableEntry(pkgName, className, 1277 type, 1, 1278 possibleComment, true); 1279 } 1280 } else if (linkType == 1) { 1281 // Link to HTML file for the package 1282 String 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><A HREF=\"" + memberRef + ".html#" + className + 1302 "(" + type + ")\" target=\"_top\"><font size=\"+1\"><tt>" + shownClassName + "</tt></font></A>"); 1303 emitTypeWithParens(shortType); 1304 reportFile.println("</nobr>"); 1305 } 1306 if (!useOld) { 1307 reportFile.println(" </TD>"); 1308 emitComment(commentID, possibleComment, linkType); 1309 reportFile.println("</TR>"); 1310 } 1311 } 1312 1313 /** 1314 * Write a table entry for a changed constructor. 1315 */ writeCtorChangedTableEntry(String pkgName, String className, MemberDiff memberDiff)1316 public void writeCtorChangedTableEntry(String pkgName, String className, 1317 MemberDiff memberDiff) { 1318 String fqName = pkgName + "." + className; 1319 String newSignature = memberDiff.newType_; 1320 if (newSignature.compareTo("void") == 0) 1321 newSignature = ""; 1322 String commentID = fqName + ".ctor_changed(" + newSignature + ")"; 1323 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1324 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1325 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1326 String memberRef = fqName.replace('.', '/'); 1327 String shownClassName = makeTwoRows(className); 1328 // Deal with inner classes 1329 if (className.indexOf('.') != -1) { 1330 memberRef = pkgName + "."; 1331 memberRef = memberRef.replace('.', '/'); 1332 memberRef = newDocPrefix + memberRef + className; 1333 } else { 1334 memberRef = newDocPrefix + memberRef; 1335 } 1336 String newType = memberDiff.newType_; 1337 if (newType.compareTo("void") == 0) 1338 newType = ""; 1339 String shortNewType = simpleName(memberDiff.newType_); 1340 // Constructors have the linked name, then the type in parentheses. 1341 reportFile.print(" <nobr><A HREF=\"" + memberRef + ".html#" + className + "(" + newType + ")\" target=\"_top\"><font size=\"+1\"><tt>"); 1342 reportFile.print(shownClassName); 1343 reportFile.print("</tt></font></A>"); 1344 emitTypeWithParens(shortNewType); 1345 reportFile.println(" </nobr>"); 1346 reportFile.println(" </TD>"); 1347 1348 // Report changes in documentation 1349 if (reportDocChanges && memberDiff.documentationChange_ != null) { 1350 String oldMemberRef = null; 1351 String oldType = null; 1352 if (oldDocPrefix != null) { 1353 oldMemberRef = pkgName + "." + className; 1354 oldMemberRef = oldMemberRef.replace('.', '/'); 1355 if (className.indexOf('.') != -1) { 1356 oldMemberRef = pkgName + "."; 1357 oldMemberRef = oldMemberRef.replace('.', '/'); 1358 oldMemberRef = oldDocPrefix + oldMemberRef + className; 1359 } else { 1360 oldMemberRef = oldDocPrefix + oldMemberRef; 1361 } 1362 oldType = memberDiff.oldType_; 1363 if (oldType.compareTo("void") == 0) 1364 oldType = ""; 1365 } 1366 if (oldDocPrefix != null) 1367 memberDiff.documentationChange_ += "<A HREF=\"" + 1368 oldMemberRef + ".html#" + className + "(" + oldType + 1369 ")\" target=\"_self\"><font size=\"+1\"><tt>old</tt></font></A> to "; 1370 else 1371 memberDiff.documentationChange_ += "<font size=\"+1\"><tt>old</tt></font> to "; 1372 memberDiff.documentationChange_ += "<A HREF=\"" + memberRef + 1373 ".html#" + className + "(" + newType + 1374 ")\" target=\"_self\"><font size=\"+1\"><tt>new</tt></font></A>.<br>"; 1375 } 1376 1377 emitChanges(memberDiff, 0); 1378 emitComment(commentID, null, 2); 1379 1380 reportFile.println("</TR>"); 1381 } 1382 1383 /** 1384 * Write a table entry for a method. 1385 * 1386 * linkType: 0 - no link by default, 1 = link to Javadoc HTML file 1387 */ writeMethodTableEntry(String pkgName, String className, MethodAPI methodAPI, int linkType, String possibleComment, boolean useOld)1388 public void writeMethodTableEntry(String pkgName, String className, 1389 MethodAPI methodAPI, int linkType, 1390 String possibleComment, boolean useOld) { 1391 String fqName = pkgName + "." + className; 1392 String signature = methodAPI.getSignature(); 1393 String methodName = methodAPI.name_; 1394 String lt = "removed"; 1395 if (linkType ==1) 1396 lt = "added"; 1397 String commentID = fqName + "." + methodName + "_" + lt + "(" + signature + ")"; 1398 if (!useOld) { 1399 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1400 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1401 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1402 } 1403 if (signature.compareTo("void") == 0) 1404 signature = ""; 1405 String shortSignature = simpleName(signature); 1406 String returnType = methodAPI.returnType_; 1407 String shortReturnType = simpleName(returnType); 1408 if (linkType == 0) { 1409 if (oldDocPrefix == null) { 1410 // No link 1411 reportFile.print(" <nobr>"); 1412 emitType(shortReturnType); 1413 reportFile.print(" " + methodName); 1414 emitTypeWithParens(shortSignature); 1415 reportFile.println("</nobr>"); 1416 } else { 1417 writeMethodTableEntry(pkgName, className, 1418 methodAPI, 1, 1419 possibleComment, true); 1420 } 1421 } else if (linkType == 1) { 1422 // Link to HTML file for the package 1423 String memberRef = fqName.replace('.', '/'); 1424 // Deal with inner classes 1425 if (className.indexOf('.') != -1) { 1426 memberRef = pkgName + "."; 1427 memberRef = memberRef.replace('.', '/'); 1428 if (useOld) { 1429 // oldDocPrefix is non-null at this point 1430 memberRef = oldDocPrefix + memberRef + className; 1431 } else { 1432 memberRef = newDocPrefix + memberRef + className; 1433 } 1434 } else { 1435 if (useOld) { 1436 // oldDocPrefix is non-null at this point 1437 memberRef = oldDocPrefix + memberRef; 1438 } else { 1439 memberRef = newDocPrefix + memberRef; 1440 } 1441 } 1442 reportFile.print(" <nobr>"); 1443 emitType(shortReturnType); 1444 reportFile.print(" <A HREF=\"" + memberRef + ".html#" + methodName + 1445 "(" + signature + ")\" target=\"_top\"><font size=\"+1\"><tt>" + methodName + "</tt></font></A>"); 1446 emitTypeWithParens(shortSignature); 1447 reportFile.println("</nobr>"); 1448 } 1449 if (!useOld) { 1450 reportFile.println(" </TD>"); 1451 emitComment(commentID, possibleComment, linkType); 1452 reportFile.println("</TR>"); 1453 } 1454 } 1455 1456 /** 1457 * Write a table entry for a changed method. 1458 */ writeMethodChangedTableEntry(String pkgName, String className, MemberDiff memberDiff)1459 public void writeMethodChangedTableEntry(String pkgName, String className, 1460 MemberDiff memberDiff) { 1461 String memberName = memberDiff.name_; 1462 // Generally nowhere to break a member name anyway 1463 // String shownMemberName = makeTwoRows(memberName); 1464 String fqName = pkgName + "." + className; 1465 String newSignature = memberDiff.newSignature_; 1466 String commentID = fqName + "." + memberName + "_changed(" + newSignature + ")"; 1467 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1468 1469 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1470 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1471 String memberRef = fqName.replace('.', '/'); 1472 // Deal with inner classes 1473 if (className.indexOf('.') != -1) { 1474 memberRef = pkgName + "."; 1475 memberRef = memberRef.replace('.', '/'); 1476 memberRef = newDocPrefix + memberRef + className; 1477 } else { 1478 memberRef = newDocPrefix + memberRef; 1479 } 1480 // Javadoc generated HTML has no named anchors for methods 1481 // inherited from other classes, so link to the defining class' method. 1482 // Only copes with non-inner classes. 1483 if (className.indexOf('.') == -1 && 1484 memberDiff.modifiersChange_ != null && 1485 memberDiff.modifiersChange_.indexOf("but is now inherited from") != -1) { 1486 memberRef = memberDiff.inheritedFrom_; 1487 memberRef = memberRef.replace('.', '/'); 1488 memberRef = newDocPrefix + memberRef; 1489 } 1490 1491 String newReturnType = memberDiff.newType_; 1492 String shortReturnType = simpleName(newReturnType); 1493 String shortSignature = simpleName(newSignature); 1494 reportFile.print(" <nobr>"); 1495 emitTypeWithNoParens(shortReturnType); 1496 reportFile.print(" <A HREF=\"" + memberRef + ".html#" + 1497 memberName + "(" + newSignature + ")\" target=\"_top\"><font size=\"+1\"><tt>"); 1498 reportFile.print(memberName); 1499 reportFile.print("</tt></font></A>"); 1500 emitTypeWithParens(shortSignature); 1501 reportFile.println(" </nobr>"); 1502 reportFile.println(" </TD>"); 1503 1504 // Report changes in documentation 1505 if (reportDocChanges && memberDiff.documentationChange_ != null) { 1506 String oldMemberRef = null; 1507 String oldSignature = null; 1508 if (oldDocPrefix != null) { 1509 oldMemberRef = pkgName + "." + className; 1510 oldMemberRef = oldMemberRef.replace('.', '/'); 1511 if (className.indexOf('.') != -1) { 1512 oldMemberRef = pkgName + "."; 1513 oldMemberRef = oldMemberRef.replace('.', '/'); 1514 oldMemberRef = oldDocPrefix + oldMemberRef + className; 1515 } else { 1516 oldMemberRef = oldDocPrefix + oldMemberRef; 1517 } 1518 oldSignature = memberDiff.oldSignature_; 1519 } 1520 if (oldDocPrefix != null) 1521 memberDiff.documentationChange_ += "<A HREF=\"" + 1522 oldMemberRef + ".html#" + memberName + "(" + 1523 oldSignature + ")\" target=\"_self\"><font size=\"+1\"><tt>old</tt></font></A> to "; 1524 else 1525 memberDiff.documentationChange_ += "<font size=\"+1\"><tt>old</tt></font> to "; 1526 memberDiff.documentationChange_ += "<A HREF=\"" + memberRef + 1527 ".html#" + memberName + "(" + newSignature + 1528 ")\" target=\"_self\"><font size=\"+1\"><tt>new</tt></font></A>.<br>"; 1529 } 1530 1531 emitChanges(memberDiff, 1); 1532 // Get the comment from the parent class if more appropriate 1533 if (memberDiff.modifiersChange_ != null) { 1534 int parentIdx = memberDiff.modifiersChange_.indexOf("now inherited from"); 1535 if (parentIdx != -1) { 1536 // Change the commentID to pick up the appropriate method 1537 commentID = memberDiff.inheritedFrom_ + "." + memberName + 1538 "_changed(" + newSignature + ")"; 1539 } 1540 } 1541 emitComment(commentID, null, 2); 1542 1543 reportFile.println("</TR>"); 1544 } 1545 1546 /** 1547 * Write a table entry for a field. 1548 * 1549 * linkType: 0 - no link by default, 1 = link to Javadoc HTML file 1550 */ writeFieldTableEntry(String pkgName, String className, FieldAPI fieldAPI, int linkType, String possibleComment, boolean useOld)1551 public void writeFieldTableEntry(String pkgName, String className, 1552 FieldAPI fieldAPI, int linkType, 1553 String possibleComment, boolean useOld) { 1554 String fqName = pkgName + "." + className; 1555 // Fields can only appear in one table, so no need to specify _added etc 1556 String fieldName = fieldAPI.name_; 1557 // Generally nowhere to break a member name anyway 1558 // String shownFieldName = makeTwoRows(fieldName); 1559 String commentID = fqName + "." + fieldName; 1560 if (!useOld) { 1561 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1562 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1563 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1564 } 1565 String fieldType = fieldAPI.type_; 1566 if (fieldType.compareTo("void") == 0) 1567 fieldType = ""; 1568 String shortFieldType = simpleName(fieldType); 1569 if (linkType == 0) { 1570 if (oldDocPrefix == null) { 1571 // No link. 1572 reportFile.print(" "); 1573 emitType(shortFieldType); 1574 reportFile.println(" " + fieldName); 1575 } else { 1576 writeFieldTableEntry(pkgName, className, 1577 fieldAPI, 1, 1578 possibleComment, true); 1579 } 1580 } else if (linkType == 1) { 1581 // Link to HTML file for the package. 1582 String memberRef = fqName.replace('.', '/'); 1583 // Deal with inner classes 1584 if (className.indexOf('.') != -1) { 1585 memberRef = pkgName + "."; 1586 memberRef = memberRef.replace('.', '/'); 1587 if (useOld) 1588 memberRef = oldDocPrefix + memberRef + className; 1589 else 1590 memberRef = newDocPrefix + memberRef + className; 1591 } else { 1592 if (useOld) 1593 memberRef = oldDocPrefix + memberRef; 1594 else 1595 memberRef = newDocPrefix + memberRef; 1596 } 1597 reportFile.print(" <nobr>"); 1598 emitType(shortFieldType); 1599 reportFile.println(" <A HREF=\"" + memberRef + ".html#" + fieldName + 1600 "\" target=\"_top\"><font size=\"+1\"><tt>" + fieldName + "</tt></font></A></nobr>"); 1601 } 1602 if (!useOld) { 1603 reportFile.println(" </TD>"); 1604 emitComment(commentID, possibleComment, linkType); 1605 reportFile.println("</TR>"); 1606 } 1607 } 1608 1609 /** 1610 * Write a table entry for a changed field. 1611 */ writeFieldChangedTableEntry(String pkgName, String className, MemberDiff memberDiff)1612 public void writeFieldChangedTableEntry(String pkgName, String className, 1613 MemberDiff memberDiff) { 1614 String memberName = memberDiff.name_; 1615 // Generally nowhere to break a member name anyway 1616 // String shownMemberName = makeTwoRows(memberName); 1617 String fqName = pkgName + "." + className; 1618 // Fields have unique names in a class 1619 String commentID = fqName + "." + memberName; 1620 reportFile.println("<TR BGCOLOR=\"" + bgcolor + "\" CLASS=\"TableRowColor\">"); 1621 1622 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"25%\">"); 1623 reportFile.println(" <A NAME=\"" + commentID + "\"></A>"); // Named anchor 1624 String memberRef = fqName.replace('.', '/'); 1625 // Deal with inner classes 1626 if (className.indexOf('.') != -1) { 1627 memberRef = pkgName + "."; 1628 memberRef = memberRef.replace('.', '/'); 1629 memberRef = newDocPrefix + memberRef + className; 1630 } else { 1631 memberRef = newDocPrefix + memberRef; 1632 } 1633 // Javadoc generated HTML has no named anchors for fields 1634 // inherited from other classes, so link to the defining class' field. 1635 // Only copes with non-inner classes. 1636 if (className.indexOf('.') == -1 && 1637 memberDiff.modifiersChange_ != null && 1638 memberDiff.modifiersChange_.indexOf("but is now inherited from") != -1) { 1639 memberRef = memberDiff.inheritedFrom_; 1640 memberRef = memberRef.replace('.', '/'); 1641 memberRef = newDocPrefix + memberRef; 1642 } 1643 1644 String newType = memberDiff.newType_; 1645 String shortNewType = simpleName(newType); 1646 reportFile.print(" <nobr>"); 1647 emitTypeWithNoParens(shortNewType); 1648 reportFile.print(" <A HREF=\"" + memberRef + ".html#" + 1649 memberName + "\" target=\"_top\"><font size=\"+1\"><tt>"); 1650 reportFile.print(memberName); 1651 reportFile.print("</tt></font></A></nobr>"); 1652 reportFile.println(" </TD>"); 1653 1654 // Report changes in documentation 1655 if (reportDocChanges && memberDiff.documentationChange_ != null) { 1656 String oldMemberRef = null; 1657 if (oldDocPrefix != null) { 1658 oldMemberRef = pkgName + "." + className; 1659 oldMemberRef = oldMemberRef.replace('.', '/'); 1660 if (className.indexOf('.') != -1) { 1661 oldMemberRef = pkgName + "."; 1662 oldMemberRef = oldMemberRef.replace('.', '/'); 1663 oldMemberRef = oldDocPrefix + oldMemberRef + className; 1664 } else { 1665 oldMemberRef = oldDocPrefix + oldMemberRef; 1666 } 1667 } 1668 if (oldDocPrefix != null) 1669 memberDiff.documentationChange_ += "<A HREF=\"" + 1670 oldMemberRef + ".html#" + memberName + "\" target=\"_self\"><font size=\"+1\"><tt>old</tt></font></A> to "; 1671 else 1672 memberDiff.documentationChange_ += "<font size=\"+1\"><tt>old</tt></font> to "; 1673 memberDiff.documentationChange_ += "<A HREF=\"" + memberRef + 1674 ".html#" + memberName + "\" target=\"_self\"><font size=\"+1\"><tt>new</tt></font></A>.<br>"; 1675 } 1676 1677 emitChanges(memberDiff, 2); 1678 // Get the comment from the parent class if more appropriate 1679 if (memberDiff.modifiersChange_ != null) { 1680 int parentIdx = memberDiff.modifiersChange_.indexOf("now inherited from"); 1681 if (parentIdx != -1) { 1682 // Change the commentID to pick up the appropriate method 1683 commentID = memberDiff.inheritedFrom_ + "." + memberName; 1684 } 1685 } 1686 emitComment(commentID, null, 2); 1687 1688 reportFile.println("</TR>"); 1689 } 1690 1691 /** 1692 * Emit all changes associated with a MemberDiff as an entry in a table. 1693 * 1694 * @param memberType 0 = ctor, 1 = method, 2 = field 1695 */ emitChanges(MemberDiff memberDiff, int memberType)1696 public void emitChanges(MemberDiff memberDiff, int memberType){ 1697 reportFile.println(" <TD VALIGN=\"TOP\" WIDTH=\"30%\">"); 1698 boolean hasContent = false; 1699 // The type or return type changed 1700 if (memberDiff.oldType_.compareTo(memberDiff.newType_) != 0) { 1701 String shortOldType = simpleName(memberDiff.oldType_); 1702 String shortNewType = simpleName(memberDiff.newType_); 1703 if (memberType == 1) { 1704 reportFile.print("Change in return type from "); 1705 } else { 1706 reportFile.print("Change in type from "); 1707 } 1708 if (shortOldType.compareTo(shortNewType) == 0) { 1709 // The types differ in package name, so use the full name 1710 shortOldType = memberDiff.oldType_; 1711 shortNewType = memberDiff.newType_; 1712 } 1713 emitType(shortOldType); 1714 reportFile.print(" to "); 1715 emitType(shortNewType); 1716 reportFile.println(".<br>"); 1717 hasContent = true; 1718 } 1719 // The signatures changed - only used by methods 1720 if (memberType == 1 && 1721 memberDiff.oldSignature_ != null && 1722 memberDiff.newSignature_ != null && 1723 memberDiff.oldSignature_.compareTo(memberDiff.newSignature_) != 0) { 1724 String shortOldSignature = simpleName(memberDiff.oldSignature_); 1725 String shortNewSignature = simpleName(memberDiff.newSignature_); 1726 if (shortOldSignature.compareTo(shortNewSignature) == 0) { 1727 // The signatures differ in package names, so use the full form 1728 shortOldSignature = memberDiff.oldSignature_; 1729 shortNewSignature = memberDiff.newSignature_; 1730 } 1731 if (hasContent) 1732 reportFile.print(" "); 1733 reportFile.print("Change in signature from "); 1734 if (shortOldSignature.compareTo("") == 0) 1735 shortOldSignature = "void"; 1736 emitType(shortOldSignature); 1737 reportFile.print(" to "); 1738 if (shortNewSignature.compareTo("") == 0) 1739 shortNewSignature = "void"; 1740 emitType(shortNewSignature); 1741 reportFile.println(".<br>"); 1742 hasContent = true; 1743 } 1744 // The exceptions are only non-null in methods and constructors 1745 if (memberType != 2 && 1746 memberDiff.oldExceptions_ != null && 1747 memberDiff.newExceptions_ != null && 1748 memberDiff.oldExceptions_.compareTo(memberDiff.newExceptions_) != 0) { 1749 if (hasContent) 1750 reportFile.print(" "); 1751 // If either one of the exceptions has no spaces in it, or is 1752 // equal to "no exceptions", then just display the whole 1753 // exceptions texts. 1754 int spaceInOld = memberDiff.oldExceptions_.indexOf(" "); 1755 if (memberDiff.oldExceptions_.compareTo("no exceptions") == 0) 1756 spaceInOld = -1; 1757 int spaceInNew = memberDiff.newExceptions_.indexOf(" "); 1758 if (memberDiff.newExceptions_.compareTo("no exceptions") == 0) 1759 spaceInNew = -1; 1760 if (spaceInOld == -1 || spaceInNew == -1) { 1761 reportFile.print("Change in exceptions thrown from "); 1762 emitException(memberDiff.oldExceptions_); 1763 reportFile.print(" to " ); 1764 emitException(memberDiff.newExceptions_); 1765 reportFile.println(".<br>"); 1766 } else { 1767 // Too many exceptions become unreadable, so just show the 1768 // individual changes. Catch the case where exceptions are 1769 // just reordered. 1770 boolean firstChange = true; 1771 int numRemoved = 0; 1772 StringTokenizer stOld = new StringTokenizer(memberDiff.oldExceptions_, ", "); 1773 while (stOld.hasMoreTokens()) { 1774 String oldException = stOld.nextToken(); 1775 if (!memberDiff.newExceptions_.startsWith(oldException) && 1776 !(memberDiff.newExceptions_.indexOf(", " + oldException) != -1)) { 1777 if (firstChange) { 1778 reportFile.print("Change in exceptions: "); 1779 firstChange = false; 1780 } 1781 if (numRemoved != 0) 1782 reportFile.print(", "); 1783 emitException(oldException); 1784 numRemoved++; 1785 } 1786 } 1787 if (numRemoved == 1) 1788 reportFile.print(" was removed."); 1789 else if (numRemoved > 1) 1790 reportFile.print(" were removed."); 1791 1792 int numAdded = 0; 1793 StringTokenizer stNew = new StringTokenizer(memberDiff.newExceptions_, ", "); 1794 while (stNew.hasMoreTokens()) { 1795 String newException = stNew.nextToken(); 1796 if (!memberDiff.oldExceptions_.startsWith(newException) && 1797 !(memberDiff.oldExceptions_.indexOf(", " + newException) != -1)) { 1798 if (firstChange) { 1799 reportFile.print("Change in exceptions: "); 1800 firstChange = false; 1801 } 1802 if (numAdded != 0) 1803 reportFile.println(", "); 1804 else 1805 reportFile.println(" "); 1806 emitException(newException); 1807 numAdded++; 1808 } 1809 } 1810 if (numAdded == 1) 1811 reportFile.print(" was added"); 1812 else if (numAdded > 1) 1813 reportFile.print(" were added"); 1814 else if (numAdded == 0 && numRemoved == 0 && firstChange) 1815 reportFile.print("Exceptions were reordered"); 1816 reportFile.println(".<br>"); 1817 } 1818 // Note the changes between a comma-separated list of Strings 1819 hasContent = true; 1820 } 1821 1822 if (memberDiff.documentationChange_ != null) { 1823 if (hasContent) 1824 reportFile.print(" "); 1825 reportFile.print(memberDiff.documentationChange_); 1826 hasContent = true; 1827 } 1828 1829 // Last, so no need for a <br> 1830 if (memberDiff.modifiersChange_ != null) { 1831 if (hasContent) 1832 reportFile.print(" "); 1833 reportFile.println(memberDiff.modifiersChange_); 1834 hasContent = true; 1835 } 1836 reportFile.println(" </TD>"); 1837 } 1838 1839 /** 1840 * Emit a string which is an exception by surrounding it with 1841 * <code> tags. 1842 * If there is a space in the type, e.g. "String, File", then 1843 * surround it with parentheses too. Do not add <code> tags or 1844 * parentheses if the String is "no exceptions". 1845 */ emitException(String ex)1846 public void emitException(String ex) { 1847 if (ex.compareTo("no exceptions") == 0) { 1848 reportFile.print(ex); 1849 } else { 1850 if (ex.indexOf(' ') != -1) { 1851 reportFile.print("(<code>" + ex + "</code>)"); 1852 } else { 1853 reportFile.print("<code>" + ex + "</code>"); 1854 } 1855 } 1856 } 1857 1858 /** 1859 * Emit a string which is a type by surrounding it with <code> tags. 1860 * If there is a space in the type, e.g. "String, File", then 1861 * surround it with parentheses too. 1862 */ emitType(String type)1863 public void emitType(String type) { 1864 if (type.compareTo("") == 0) 1865 return; 1866 if (type.indexOf(' ') != -1) { 1867 reportFile.print("(<code>" + type + "</code>)"); 1868 } else { 1869 reportFile.print("<code>" + type + "</code>"); 1870 } 1871 } 1872 1873 /** 1874 * Emit a string which is a type by surrounding it with <code> tags. 1875 * Also surround it with parentheses too. Used to display methods' 1876 * parameters. 1877 * Suggestions for where a browser should break the 1878 * text are provided with <br> and <nobr> tags. 1879 */ emitTypeWithParens(String type)1880 public static void emitTypeWithParens(String type) { 1881 emitTypeWithParens(type, true); 1882 } 1883 1884 /** 1885 * Emit a string which is a type by surrounding it with <code> tags. 1886 * Also surround it with parentheses too. Used to display methods' 1887 * parameters. 1888 */ emitTypeWithParens(String type, boolean addBreaks)1889 public static void emitTypeWithParens(String type, boolean addBreaks) { 1890 if (type.compareTo("") == 0) 1891 reportFile.print("()"); 1892 else { 1893 int idx = type.indexOf(", "); 1894 if (!addBreaks || idx == -1) { 1895 reportFile.print("(<code>" + type + "</code>)"); 1896 } else { 1897 // Make the browser break text at reasonable places 1898 String sepType = null; 1899 StringTokenizer st = new StringTokenizer(type, ", "); 1900 while (st.hasMoreTokens()) { 1901 String p = st.nextToken(); 1902 if (sepType == null) 1903 sepType = p; 1904 else 1905 sepType += ",</nobr> " + p + "<nobr>"; 1906 } 1907 reportFile.print("(<code>" + sepType + "<nobr></code>)"); 1908 } 1909 } 1910 } 1911 1912 /** 1913 * Emit a string which is a type by surrounding it with <code> tags. 1914 * Do not surround it with parentheses. Used to display methods' return 1915 * types and field types. 1916 */ emitTypeWithNoParens(String type)1917 public static void emitTypeWithNoParens(String type) { 1918 if (type.compareTo("") != 0) 1919 reportFile.print("<code>" + type + "</code>"); 1920 } 1921 1922 /** 1923 * Return a String with the simple names of the classes in fqName. 1924 * "java.lang.String" becomes "String", 1925 * "java.lang.String, java.io.File" becomes "String, File" 1926 * and so on. If fqName is null, return null. If fqName is "", 1927 * return "". 1928 */ simpleName(String fqNames)1929 public static String simpleName(String fqNames) { 1930 if (fqNames == null) 1931 return null; 1932 String res = ""; 1933 boolean hasContent = false; 1934 // We parse the string step by step to ensure we take 1935 // fqNames that contains generics parameter in a whole. 1936 ArrayList<String> fqNamesList = new ArrayList<String>(); 1937 int genericParametersDepth = 0; 1938 StringBuffer buffer = new StringBuffer(); 1939 for (int i=0; i<fqNames.length(); i++) { 1940 char c = fqNames.charAt(i); 1941 if ('<' == c) { 1942 genericParametersDepth++; 1943 } 1944 if ('>' == c) { 1945 genericParametersDepth--; 1946 } 1947 if (',' != c || genericParametersDepth > 0) { 1948 buffer.append(c); 1949 } else if (',' == c) { 1950 fqNamesList.add(buffer.toString().trim()); 1951 buffer = new StringBuffer(buffer.length()); 1952 } 1953 } 1954 fqNamesList.add(buffer.toString().trim()); 1955 for (String fqName : fqNamesList) { 1956 // Assume this will be used inside a <nobr> </nobr> set of tags. 1957 if (hasContent) 1958 res += ", "; 1959 hasContent = true; 1960 // Look for text within '<' and '>' in case this is a invocation of a generic 1961 1962 int firstBracket = fqName.indexOf('<'); 1963 int lastBracket = fqName.lastIndexOf('>'); 1964 String genericParameter = null; 1965 if (firstBracket != -1 && lastBracket != -1) { 1966 genericParameter = simpleName(fqName.substring(firstBracket + 1, lastBracket)); 1967 fqName = fqName.substring(0, firstBracket); 1968 } 1969 1970 int lastDot = fqName.lastIndexOf('.'); 1971 if (lastDot < 0) { 1972 res += fqName; // Already as simple as possible 1973 } else { 1974 res += fqName.substring(lastDot+1); 1975 } 1976 if (genericParameter != null) 1977 res += "<" + genericParameter + ">"; 1978 } 1979 return res; 1980 } 1981 1982 /** 1983 * Find any existing comment and emit it. Add the new comment to the 1984 * list of new comments. The first instance of the string "@first" in 1985 * a hand-written comment will be replaced by the first sentence from 1986 * the associated doc block, if such exists. Also replace @link by 1987 * an HTML link. 1988 * 1989 * @param commentID The identifier for this comment. 1990 * @param possibleComment A possible comment from another source. 1991 * @param linkType 0 = remove, 1 = add, 2 = change 1992 */ emitComment(String commentID, String possibleComment, int linkType)1993 public void emitComment(String commentID, String possibleComment, 1994 int linkType) { 1995 if (noCommentsOnRemovals && linkType == 0) { 1996 reportFile.println(" <TD> </TD>"); 1997 return; 1998 } 1999 if (noCommentsOnAdditions && linkType == 1) { 2000 reportFile.println(" <TD> </TD>"); 2001 return; 2002 } 2003 if (noCommentsOnChanges && linkType == 2) { 2004 reportFile.println(" <TD> </TD>"); 2005 return; 2006 } 2007 2008 // We have to use this global hash table because the *Diff classes 2009 // do not store the possible comment from the new *API object. 2010 if (!noCommentsOnChanges && possibleComment == null) { 2011 possibleComment = (String)Comments.allPossibleComments.get(commentID); 2012 } 2013 // Just use the first sentence of the possible comment. 2014 if (possibleComment != null) { 2015 int fsidx = RootDocToXML.endOfFirstSentence(possibleComment, false); 2016 if (fsidx != -1 && fsidx != 0) 2017 possibleComment = possibleComment.substring(0, fsidx+1); 2018 } 2019 2020 String comment = Comments.getComment(existingComments_, commentID); 2021 if (comment.compareTo(Comments.placeHolderText) == 0) { 2022 if (possibleComment != null && 2023 possibleComment.indexOf("InsertOtherCommentsHere") == -1) 2024 reportFile.println(" <TD VALIGN=\"TOP\">" + possibleComment + "</TD>"); 2025 else 2026 reportFile.println(" <TD> </TD>"); 2027 } else { 2028 int idx = comment.indexOf("@first"); 2029 if (idx == -1) { 2030 reportFile.println(" <TD VALIGN=\"TOP\">" + Comments.convertAtLinks(comment, "", null, null) + "</TD>"); 2031 } else { 2032 reportFile.print(" <TD VALIGN=\"TOP\">" + comment.substring(0, idx)); 2033 if (possibleComment != null && 2034 possibleComment.indexOf("InsertOtherCommentsHere") == -1) 2035 reportFile.print(possibleComment); 2036 reportFile.println(comment.substring(idx + 6) + "</TD>"); 2037 } 2038 } 2039 SingleComment newComment = new SingleComment(commentID, comment); 2040 newComments_.addComment(newComment); 2041 } 2042 2043 /** Write the end of a table. */ writeTableEnd()2044 public void writeTableEnd() { 2045 reportFile.println("</TABLE>"); 2046 reportFile.println(" "); 2047 } 2048 2049 /** Write a newline out. */ writeText()2050 public void writeText() { 2051 reportFile.println(); 2052 } 2053 2054 /** Write some text out. */ writeText(String text)2055 public void writeText(String text) { 2056 reportFile.println(text); 2057 } 2058 2059 /** Emit some non-breaking space for indentation. */ indent(int indent)2060 public void indent(int indent) { 2061 for (int i = 0; i < indent; i++) 2062 reportFile.print(" "); 2063 } 2064 2065 /** 2066 * The name of the file to which the top-level HTML file is written, 2067 * and also the name of the subdirectory where most of the HTML appears, 2068 * and also a prefix for the names of some of the files in that 2069 * subdirectory. 2070 */ 2071 static String reportFileName = "changes"; 2072 2073 /** 2074 * The suffix of the file to which the HTML output is currently being 2075 * written. 2076 */ 2077 static String reportFileExt = ".html"; 2078 2079 /** 2080 * The file to which the HTML output is currently being written. 2081 */ 2082 static PrintWriter reportFile = null; 2083 2084 /** 2085 * The object which represents the top of the tree of differences 2086 * between two APIs. It is only used indirectly when emitting a 2087 * navigation bar. 2088 */ 2089 static APIDiff apiDiff = null; 2090 2091 /** 2092 * If set, then do not suggest comments for removals from the first 2093 * sentence of the doc block of the old API. 2094 */ 2095 public static boolean noCommentsOnRemovals = false; 2096 2097 /** 2098 * If set, then do not suggest comments for additions from the first 2099 * sentence of the doc block of the new API. 2100 */ 2101 public static boolean noCommentsOnAdditions = false; 2102 2103 /** 2104 * If set, then do not suggest comments for changes from the first 2105 * sentence of the doc block of the new API. 2106 */ 2107 public static boolean noCommentsOnChanges = false; 2108 2109 /** 2110 * If set, then report changes in documentation (Javadoc comments) 2111 * between the old and the new API. The default is that this is not set. 2112 */ 2113 public static boolean reportDocChanges = false; 2114 2115 /** 2116 * Define the prefix for HTML links to the existing set of Javadoc- 2117 * generated documentation for the new API. E.g. For J2SE1.3.x, use 2118 * "http://java.sun.com/j2se/1.3/docs/api/" 2119 */ 2120 public static String newDocPrefix = "../"; 2121 2122 /** 2123 * Define the prefix for HTML links to the existing set of Javadoc- 2124 * generated documentation for the old API. 2125 */ 2126 public static String oldDocPrefix = null; 2127 2128 /** To generate statistical output, set this to true. */ 2129 public static boolean doStats = false; 2130 2131 /** 2132 * The destination directory for output files. 2133 */ 2134 public static String outputDir = null; 2135 2136 /** 2137 * The destination directory for comments files (if not specified, uses outputDir) 2138 */ 2139 public static String commentsDir = null; 2140 2141 /** 2142 * The title used on the first page of the report. By default, this is 2143 * "API Differences Between <name of old API> and 2144 * <name of new API>". It can be 2145 * set by using the -doctitle option. 2146 */ 2147 public static String docTitle = null; 2148 2149 /** 2150 * The browser window title for the report. By default, this is 2151 * "API Differences Between <name of old API> and 2152 * <name of new API>". It can be 2153 * set by using the -windowtitle option. 2154 */ 2155 public static String windowTitle = null; 2156 2157 /** The desired background color for JDiff tables. */ 2158 static final String bgcolor = "#FFFFFF"; 2159 2160 /** Set to enable debugging output. */ 2161 private static final boolean trace = false; 2162 2163 } 2164