1package jdiff; 2 3import java.io.*; 4import java.util.*; 5 6/** 7 * Class to generate colored differences between two sections of HTML text. 8 * 9 * See the file LICENSE.txt for copyright details. 10 * @author Matthew Doar, mdoar@pobox.com 11 */ 12class Diff { 13 14 /** 15 * Save the differences between the two strings in a DiffOutput object 16 * for later use. 17 * 18 * @param id A per-package unique identifier for each documentation 19 * change. 20 */ 21 static String saveDocDiffs(String pkgName, String className, 22 String oldDoc, String newDoc, 23 String id, String title) { 24 // Generate the string which will link to this set of diffs 25 if (noDocDiffs) 26 return "Documentation changed from "; 27 if (oldDoc == null || newDoc == null) { 28 return "Documentation changed from "; 29 } 30 31 // Generate the differences. 32 generateDiffs(pkgName, className, oldDoc, newDoc, id, title); 33 34 return "Documentation <a href=\"" + diffFileName + pkgName + 35 HTMLReportGenerator.reportFileExt + "#" + id + 36 "\">changed</a> from "; 37 } 38 39 /** 40 * Generate the differences. 41 */ 42 static void generateDiffs(String pkgName, String className, 43 String oldDoc, String newDoc, 44 String id, String title) { 45 String[] oldDocWords = parseDoc(oldDoc); 46 String[] newDocWords = parseDoc(newDoc); 47 48 DiffMyers diff = new DiffMyers(oldDocWords, newDocWords); 49 DiffMyers.change script = diff.diff_2(false); 50 script = mergeDiffs(oldDocWords, newDocWords, script); 51 String text = "<A NAME=\"" + id + "\"></A>" + title + "<br><br>"; 52 // Generate the differences in blockquotes to cope with unterminated 53 // HTML tags 54 text += "<blockquote>"; 55 text = addDiffs(oldDocWords, newDocWords, script, text); 56 text += "</blockquote>"; 57 docDiffs.add(new DiffOutput(pkgName, className, id, title, text)); 58 } 59 60 /** 61 * Convert the string to an array of strings, but don't break HTML tags up. 62 */ 63 static String[] parseDoc(String doc) { 64 String delimiters = " .,;:?!(){}[]\"'~@#$%^&*+=_-|\\<>/"; 65 StringTokenizer st = new StringTokenizer(doc, delimiters, true); 66 List docList = new ArrayList(); 67 boolean inTag = false; 68 String tag = null; 69 while (st.hasMoreTokens()) { 70 String tok = st.nextToken(); 71 if (!inTag) { 72 if (tok.compareTo("<") == 0) { 73 tag = tok; 74 if (st.hasMoreTokens()) { 75 // See if this really is a tag 76 tok = st.nextToken(); 77 char ch = tok.charAt(0); 78 if (Character.isLetter(ch) || ch == '/') { 79 inTag = true; 80 tag += tok; 81 } 82 } 83 if (!inTag) 84 docList.add(tag); 85 } else { 86 docList.add(tok); 87 } 88 } else { 89 // Add all tokens to the tag until the closing > is seen 90 if (tok.compareTo(">") == 0) { 91 inTag = false; 92 tag += tok; 93 docList.add(tag); 94 } else { 95 tag += tok; 96 } 97 } 98 } 99 if (inTag) { 100 // An unterminated tag, or more likely, < used instead of < 101 // There are no nested tags such as <a <b>> in HTML 102 docList.add(tag); 103 } 104 String[] docWords = new String[docList.size()]; 105 docWords = (String[])docList.toArray(docWords); 106 return docWords; 107 } 108 109 /** 110 * For improved readability, merge changes of the form 111 * "delete 1, insert 1, space, delete 1, insert 1" 112 * to 113 * "delete 3, insert 3" (including the space). 114 * 115 * @param oldDocWords The original documentation as a String array 116 * @param newDocWords The new documentation as a String array 117 */ 118 static DiffMyers.change mergeDiffs(String[] oldDocWords, String[] newDocWords, 119 DiffMyers.change script) { 120 if (script.link == null) 121 return script; // Only one change 122 DiffMyers.change hunk = script; 123 DiffMyers.change lasthunk = null; // Set to the last potential hunk 124 int startOld = 0; 125 for (; hunk != null; hunk = hunk.link) { 126 int deletes = hunk.deleted; 127 int inserts = hunk.inserted; 128 if (lasthunk == null) { 129 if (deletes == 1 && inserts == 1) { 130 // This is the start of a potential merge 131 lasthunk = hunk; 132 } 133 continue; 134 } else { 135 int first0 = hunk.line0; // Index of first deleted word 136 int first1 = hunk.line1; // Index of first inserted word 137 if (deletes == 1 && inserts == 1 && 138 oldDocWords[first0 - 1].compareTo(" ") == 0 && 139 newDocWords[first1 - 1].compareTo(" ") == 0 && 140 first0 == lasthunk.line0 + lasthunk.deleted + 1 && 141 first1 == lasthunk.line1 + lasthunk.inserted + 1) { 142 // Merge this change into the last change 143 lasthunk.deleted += 2; 144 lasthunk.inserted += 2; 145 lasthunk.link = hunk.link; 146 } else { 147 lasthunk = null; 148 } 149 } 150 } 151 return script; 152 } 153 154 /** 155 * Add the differences to the text passed in. The old documentation is 156 * edited using the edit script provided by the DiffMyers object. 157 * Do not display diffs in HTML tags. 158 * 159 * @param oldDocWords The original documentation as a String array 160 * @param newDocWords The new documentation as a String array 161 * @return The text for this documentation difference 162 */ 163 static String addDiffs(String[] oldDocWords, String[] newDocWords, 164 DiffMyers.change script, String text) { 165 String res = text; 166 DiffMyers.change hunk = script; 167 int startOld = 0; 168 if (trace) { 169 System.out.println("Old Text:"); 170 for (int i = 0; i < oldDocWords.length; i++) { 171 System.out.print(oldDocWords[i]); 172 } 173 System.out.println(":END"); 174 System.out.println("New Text:"); 175 for (int i = 0; i < newDocWords.length; i++) { 176 System.out.print(newDocWords[i]); 177 } 178 System.out.println(":END"); 179 } 180 181 for (; hunk != null; hunk = hunk.link) { 182 int deletes = hunk.deleted; 183 int inserts = hunk.inserted; 184 if (deletes == 0 && inserts == 0) { 185 continue; // Not clear how this would occur, but handle it 186 } 187 188 // Determine the range of word and delimiter numbers involved 189 // in each file. 190 int first0 = hunk.line0; // Index of first deleted word 191 // Index of last deleted word, invalid if deletes == 0 192 int last0 = hunk.line0 + hunk.deleted - 1; 193 int first1 = hunk.line1; // Index of first inserted word 194 // Index of last inserted word, invalid if inserts == 0 195 int last1 = hunk.line1 + hunk.inserted - 1; 196 197 if (trace) { 198 System.out.println("HUNK: "); 199 System.out.println("inserts: " + inserts); 200 System.out.println("deletes: " + deletes); 201 System.out.println("first0: " + first0); 202 System.out.println("last0: " + last0); 203 System.out.println("first1: " + first1); 204 System.out.println("last1: " + last1); 205 } 206 207 // Emit the original document up to this change 208 for (int i = startOld; i < first0; i++) { 209 res += oldDocWords[i]; 210 } 211 // Record where to start the next hunk from 212 startOld = last0 + 1; 213 // Emit the deleted words, but struck through 214 // but do not emit deleted HTML tags 215 if (deletes != 0) { 216 boolean inStrike = false; 217 for (int i = first0; i <= last0; i++) { 218 if (!oldDocWords[i].startsWith("<") && 219 !oldDocWords[i].endsWith(">")) { 220 if (!inStrike) { 221 if (deleteEffect == 0) 222 res += "<strike>"; 223 else if (deleteEffect == 1) 224 res += "<span style=\"background: #FFCCCC\">"; 225 inStrike = true; 226 } 227 res += oldDocWords[i]; 228 } 229 } 230 if (inStrike) { 231 if (deleteEffect == 0) 232 res += "</strike>"; 233 else if (deleteEffect == 1) 234 res += "</span>"; 235 } 236 } 237 // Emit the inserted words, but do not emphasise new HTML tags 238 if (inserts != 0) { 239 boolean inEmph = false; 240 for (int i = first1; i <= last1; i++) { 241 if (!newDocWords[i].startsWith("<") && 242 !newDocWords[i].endsWith(">")) { 243 if (!inEmph) { 244 if (insertEffect == 0) 245 res += "<font color=\"red\">"; 246 else if (insertEffect == 1) 247 res += "<span style=\"background: #FFFF00\">"; 248 inEmph = true; 249 } 250 } 251 res += newDocWords[i]; 252 } 253 if (inEmph) { 254 if (insertEffect == 0) 255 res += "</font>"; 256 else if (insertEffect == 1) 257 res += "</span>"; 258 } 259 } 260 } //for (; hunk != null; hunk = hunk.link) 261 // Print out the remaining part of the old text 262 for (int i = startOld; i < oldDocWords.length; i++) { 263 res += oldDocWords[i]; 264 } 265 return res; 266 } 267 268 /** 269 * Emit all the documentation differences into one file per package. 270 */ 271 static void emitDocDiffs(String fullReportFileName) { 272 Collections.sort(docDiffs); 273 274 DiffOutput[] docDiffsArr = new DiffOutput[docDiffs.size()]; 275 docDiffsArr = (DiffOutput[])docDiffs.toArray(docDiffsArr); 276 277 for (int i = 0; i < docDiffsArr.length; i++) { 278 DiffOutput diffOutput = docDiffsArr[i]; 279 if (currPkgName == null || 280 currPkgName.compareTo(diffOutput.pkgName_) != 0) { 281 // Open a different file for each package, add the HTML header, 282 // the navigation bar and some preamble. 283 if (currPkgName != null) 284 closeDiffFile(); // Close the existing file 285 // Create the HTML link to the previous package 286 String prevPkgName = currPkgName; 287 if (currPkgName != null) { 288 prevPkgName = diffFileName + docDiffsArr[i-1].pkgName_ + 289 HTMLReportGenerator.reportFileExt; 290 } 291 // Set the current package name 292 currPkgName = diffOutput.pkgName_; 293 // Create the HTML link to the next package 294 String nextPkgName = null; 295 for (int j = i; j < docDiffsArr.length; j++) { 296 if (currPkgName.compareTo(docDiffsArr[j].pkgName_) != 0) { 297 nextPkgName = diffFileName + docDiffsArr[j].pkgName_ + 298 HTMLReportGenerator.reportFileExt; 299 break; 300 } 301 } 302 303 String fullDiffFileName = fullReportFileName + 304 JDiff.DIR_SEP + diffFileName + currPkgName + 305 HTMLReportGenerator.reportFileExt; 306 // Create the output file 307 try { 308 FileOutputStream fos = new FileOutputStream(fullDiffFileName); 309 diffFile = new PrintWriter(fos); 310 311 // Write the HTML header 312 diffFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">"); 313 diffFile.println("<HTML>"); 314 diffFile.println("<HEAD>"); 315 diffFile.println("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">"); 316 diffFile.println("<!-- Generated by the JDiff Javadoc doclet -->"); 317 diffFile.println("<!-- (" + JDiff.jDiffLocation + ") -->"); 318// diffFile.println("<!-- on " + new Date() + " -->"); 319 diffFile.println("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">"); 320 diffFile.println("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">"); 321 diffFile.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + "../" + "stylesheet-jdiff.css\" TITLE=\"Style\">"); 322 diffFile.println("<TITLE>"); 323 diffFile.println(currPkgName + " Documentation Differences"); 324 diffFile.println("</TITLE>"); 325 diffFile.println("</HEAD>"); 326 diffFile.println("<BODY>"); 327 328 // Write the navigation bar 329 diffFile.println("<!-- Start of nav bar -->"); 330 diffFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">"); 331 diffFile.println("<TR>"); 332 diffFile.println("<TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">"); 333 diffFile.println(" <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">"); 334 diffFile.println(" <TR ALIGN=\"center\" VALIGN=\"top\">"); 335 // Always have a link to the Javadoc files 336 String pkgRef = currPkgName; 337 pkgRef = pkgRef.replace('.', '/'); 338 pkgRef = HTMLReportGenerator.newDocPrefix + pkgRef + "/package-summary"; 339 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + pkgRef + ".html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><tt>" + APIDiff.newAPIName_ + "</tt></B></FONT></A> </TD>"); 340 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.reportFileName + "-summary" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A> </TD>"); 341 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Package</FONT> </TD>"); 342 diffFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Class</FONT> </TD>"); 343 if (!Diff.noDocDiffs) { 344 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + Diff.diffFileName + "index" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Text Changes</B></FONT></A> </TD>"); 345 } 346 if (HTMLReportGenerator.doStats) { 347 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A> </TD>"); 348 } 349 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A> </TD>"); 350 diffFile.println(" </TR>"); 351 diffFile.println(" </TABLE>"); 352 diffFile.println("</TD>"); 353 354 // The right hand side title 355 diffFile.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>"); 356 diffFile.println("</TR>"); 357 358 // Links for previous and next, and frames and no frames 359 diffFile.println("<TR>"); 360 diffFile.println(" <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">"); 361 if (prevPkgName != null) 362 diffFile.println(" <A HREF=\"" + prevPkgName + "\"><B>PREV PACKAGE</B></A> "); 363 else 364 diffFile.println(" <B>PREV PACKAGE</B> "); 365 if (nextPkgName != null) 366 diffFile.println(" <A HREF=\"" + nextPkgName + "\"><B>NEXT PACKAGE</B></A>"); 367 else 368 diffFile.println(" <B>NEXT PACKAGE</B>"); 369 diffFile.println(" "); 370 diffFile.println(" <A HREF=\"" + "../" + HTMLReportGenerator.reportFileName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A> "); 371 diffFile.println(" <A HREF=\"" + diffFileName + currPkgName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>"); 372 diffFile.println(" <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"> </TD>"); 373 diffFile.println("</TR>"); 374 375 diffFile.println("</TABLE>"); 376 diffFile.println("<HR>"); 377 diffFile.println("<!-- End of nav bar -->"); 378 379 diffFile.println("<h2>"); 380 diffFile.println(currPkgName + " Documentation Differences"); 381 diffFile.println("</h2>"); 382 diffFile.println(); 383 diffFile.println("<blockquote>"); 384 diffFile.println("This file contains all the changes in documentation in the package <code>" + currPkgName + "</code> as colored differences."); 385 if (deleteEffect == 0) 386 diffFile.println("Deletions are shown <strike>like this</strike>, and"); 387 else if (deleteEffect == 1) 388 diffFile.println("Deletions are shown <span style=\"background: #FFCCCC\">like this</span>, and"); 389 if (insertEffect == 0) 390 diffFile.println("additions are shown in red <font color=\"red\">like this</font>."); 391 else if (insertEffect == 1) 392 diffFile.println("additions are shown <span style=\"background: #FFFF00\">like this</span>."); 393 diffFile.println("</blockquote>"); 394 395 diffFile.println("<blockquote>"); 396 diffFile.println("If no deletions or additions are shown in an entry, the HTML tags will be what has changed. The <i>new</i> HTML tags are shown in the differences. "); 397 diffFile.println("If no documentation existed, and then some was added in a later version, this change is noted in the appropriate class pages of differences, but the change is not shown on this page. Only changes in existing text are shown here. "); 398 diffFile.println("Similarly, documentation which was inherited from another class or interface is not shown here."); 399 diffFile.println("</blockquote>"); 400 401 diffFile.println("<blockquote>"); 402 diffFile.println(" Note that an HTML error in the new documentation may cause the display of other documentation changes to be presented incorrectly. For instance, failure to close a <code> tag will cause all subsequent paragraphs to be displayed differently."); 403 diffFile.println("</blockquote>"); 404 diffFile.println("<hr>"); 405 diffFile.println(); 406 407 } catch(IOException e) { 408 System.out.println("IO Error while attempting to create " + fullDiffFileName); 409 System.out.println("Error: " + e.getMessage()); 410 System.exit(1); 411 } 412 } // if (currPkgName == null || currPkgName.compareTo(diffOutput.pkgName_) != 0) 413 // Now add the documentation difference text 414 diffFile.println(diffOutput.text_); 415 // Separate with a horizontal line 416 if (i != docDiffsArr.length - 1 && 417 diffOutput.className_ != null && 418 docDiffsArr[i+1].className_ != null && 419 diffOutput.className_.compareTo(docDiffsArr[i+1].className_) != 0) 420 diffFile.println("<hr align=\"left\" width=\"100%\">"); 421// else 422// diffFile.println("<hr align=\"left\" width=\"50%\">"); 423 } // for (i = 0; 424 if (currPkgName != null) 425 closeDiffFile(); // Close the existing file 426 427 // Emit the single file which is the index to all documentation changes 428 emitDocDiffIndex(fullReportFileName, docDiffsArr); 429 } 430 431 /** 432 * Emit the single file which is the index to all documentation changes. 433 */ 434 public static void emitDocDiffIndex(String fullReportFileName, 435 DiffOutput[] docDiffsArr) { 436 437 String fullDiffFileName = fullReportFileName + 438 JDiff.DIR_SEP + diffFileName + "index" + 439 HTMLReportGenerator.reportFileExt; 440 441 // Create the output file 442 try { 443 FileOutputStream fos = new FileOutputStream(fullDiffFileName); 444 diffFile = new PrintWriter(fos); 445 446 // Write the HTML header 447 diffFile.println("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0 Frameset//EN\"\"" + RootDocToXML.baseURI + "/TR/REC-html40/frameset.dtd\">"); 448 diffFile.println("<HTML>"); 449 diffFile.println("<HEAD>"); 450 diffFile.println("<meta name=\"generator\" content=\"JDiff v" + JDiff.version + "\">"); 451 diffFile.println("<!-- Generated by the JDiff Javadoc doclet -->"); 452 diffFile.println("<!-- (" + JDiff.jDiffLocation + ") -->"); 453// diffFile.println("<!-- on " + new Date() + " -->"); 454 diffFile.println("<meta name=\"description\" content=\"" + JDiff.jDiffDescription + "\">"); 455 diffFile.println("<meta name=\"keywords\" content=\"" + JDiff.jDiffKeywords + "\">"); 456 diffFile.println("<LINK REL=\"stylesheet\" TYPE=\"text/css\" HREF=\"" + "../" + "stylesheet-jdiff.css\" TITLE=\"Style\">"); 457 diffFile.println("<TITLE>"); 458 diffFile.println("All Documentation Differences"); 459 diffFile.println("</TITLE>"); 460 diffFile.println("</HEAD>"); 461 diffFile.println("<BODY>"); 462 463 // Write the navigation bar 464 diffFile.println("<!-- Start of nav bar -->"); 465 diffFile.println("<TABLE summary=\"Navigation bar\" BORDER=\"0\" WIDTH=\"100%\" CELLPADDING=\"1\" CELLSPACING=\"0\">"); 466 diffFile.println("<TR>"); 467 diffFile.println("<TD COLSPAN=2 BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\">"); 468 diffFile.println(" <TABLE summary=\"Navigation bar\" BORDER=\"0\" CELLPADDING=\"0\" CELLSPACING=\"3\">"); 469 diffFile.println(" <TR ALIGN=\"center\" VALIGN=\"top\">"); 470 // Always have a link to the Javadoc files 471 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.newDocPrefix + "index.html\" target=\"_top\"><FONT CLASS=\"NavBarFont1\"><B><tt>" + APIDiff.newAPIName_ + "</tt></B></FONT></A> </TD>"); 472 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"" + HTMLReportGenerator.reportFileName + "-summary" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Overview</B></FONT></A> </TD>"); 473 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Package</FONT> </TD>"); 474 diffFile.println(" <TD BGCOLOR=\"#FFFFFF\" CLASS=\"NavBarCell1\"> <FONT CLASS=\"NavBarFont1\">Class</FONT> </TD>"); 475 if (!Diff.noDocDiffs) { 476 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1Rev\"> <FONT CLASS=\"NavBarFont1Rev\"><B>Text Changes</B></FONT> </TD>"); 477 } 478 if (HTMLReportGenerator.doStats) { 479 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_statistics" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Statistics</B></FONT></A> </TD>"); 480 } 481 diffFile.println(" <TD BGCOLOR=\"#EEEEFF\" CLASS=\"NavBarCell1\"> <A HREF=\"jdiff_help" + HTMLReportGenerator.reportFileExt + "\"><FONT CLASS=\"NavBarFont1\"><B>Help</B></FONT></A> </TD>"); 482 diffFile.println(" </TR>"); 483 diffFile.println(" </TABLE>"); 484 diffFile.println("</TD>"); 485 486 // The right hand side title 487 diffFile.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>"); 488 diffFile.println("</TR>"); 489 490 // Links for frames and no frames 491 diffFile.println("<TR>"); 492 diffFile.println(" <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"><FONT SIZE=\"-2\">"); 493 diffFile.println(" <A HREF=\"" + "../" + HTMLReportGenerator.reportFileName + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>FRAMES</B></A> "); 494 diffFile.println(" <A HREF=\"" + diffFileName + "index" + HTMLReportGenerator.reportFileExt + "\" TARGET=\"_top\"><B>NO FRAMES</B></A></FONT></TD>"); 495 diffFile.println(" <TD BGCOLOR=\"" + HTMLReportGenerator.bgcolor + "\" CLASS=\"NavBarCell2\"> </TD>"); 496 diffFile.println("</TR>"); 497 498 diffFile.println("</TABLE>"); 499 diffFile.println("<HR>"); 500 diffFile.println("<!-- End of nav bar -->"); 501 502 diffFile.println("<h2>"); 503 diffFile.println("All Documentation Differences"); 504 diffFile.println("</h2>"); 505 diffFile.println(); 506 507 // For each package and class, add the first DiffOutput to 508 // the hash table. Used when generating navigation bars. 509 boolean firstPackage = true; // Set for the first package 510 boolean firstClass = true; // Set for first class in a package 511 boolean firstCtor = true; // Set for first ctor in a class 512 boolean firstMethod = true; // Set for first method in a class 513 boolean firstField = true; // Set for first field in a class 514 for (int i = 0; i < docDiffsArr.length; i++) { 515 DiffOutput diffOutput = docDiffsArr[i]; 516 String link = "<a href=\"" + Diff.diffFileName + diffOutput.pkgName_ + HTMLReportGenerator.reportFileExt + "#" + diffOutput.id_ + "\">"; 517 518 // See if the package name changed 519 if (firstPackage || diffOutput.pkgName_.compareTo(docDiffsArr[i-1].pkgName_) != 0) { 520 if (firstPackage) { 521 firstPackage = false; 522 } else { 523 diffFile.println("<br>"); 524 } 525 firstClass = true; 526 firstCtor = true; 527 firstMethod = true; 528 firstField = true; 529 String id = diffOutput.pkgName_ + "!package"; 530 firstDiffOutput.put(id, id); 531 if (diffOutput.className_ == null) { 532 diffFile.println("<A NAME=\"" + id + "\"></A>" + link + "Package <b>" + diffOutput.pkgName_ + "</b></a><br>"); 533 } else { 534 diffFile.println("<A NAME=\"" + id + "\"></A>" + "Package <b>" + diffOutput.pkgName_ + "</b><br>"); 535 } 536 } 537 // See if the class name changed 538 if (diffOutput.className_ != null && 539 (firstClass || 540 diffOutput.className_.compareTo(docDiffsArr[i-1].className_) != 0)) { 541 if (firstClass) { 542 firstClass = false; 543 } else { 544 diffFile.println("<br>"); 545 } 546 firstCtor = true; 547 firstMethod = true; 548 firstField = true; 549 String id = diffOutput.pkgName_ + "." + diffOutput.className_ + "!class"; 550 firstDiffOutput.put(id, id); 551 if (diffOutput.id_.endsWith("!class")) { 552 diffFile.println("<A NAME=\"" + id + "\"></A> Class " + link + diffOutput.className_ + "</a><br>"); 553 } else { 554 diffFile.println("<A NAME=\"" + id + "\"></A> Class " + diffOutput.className_ + "<br>"); 555 } 556 } 557 // Work out what kind of member this is, and 558 // display it appropriately 559 if (diffOutput.className_ != null && 560 !diffOutput.id_.endsWith("!class")) { 561 int ctorIdx = diffOutput.id_.indexOf(".ctor"); 562 if (ctorIdx != -1) { 563 diffFile.println(" " + link + diffOutput.className_ + diffOutput.id_.substring(ctorIdx + 5) + "</a><br>"); 564 } else { 565 int methodIdx = diffOutput.id_.indexOf(".dmethod."); 566 if (methodIdx != -1) { 567 diffFile.println(" " + "Method " + link + diffOutput.id_.substring(methodIdx + 9) + "</a><br>"); 568 } else { 569 int fieldIdx = diffOutput.id_.indexOf(".field."); 570 if (fieldIdx != -1) { 571 diffFile.println(" " + "Field " + link + diffOutput.id_.substring(fieldIdx + 7) + "</a><br>"); 572 } 573 } //if (methodIdx != -1) 574 } //if (ctorIdx != -1) 575 } //diffOutput.className_ != null 576 } 577 } catch(IOException e) { 578 System.out.println("IO Error while attempting to create " + fullDiffFileName); 579 System.out.println("Error: " + e.getMessage()); 580 System.exit(1); 581 } 582 closeDiffFile(); 583 } 584 585 /** 586 * Emit the HTML footer and close the diff file. 587 */ 588 public static void closeDiffFile() { 589 if (diffFile != null) { 590 // Write the HTML footer 591 diffFile.println(); 592 diffFile.println("</BODY>"); 593 diffFile.println("</HTML>"); 594 diffFile.close(); 595 } 596 } 597 598 /** 599 * Current file where documentation differences are written as colored 600 * differences. 601 */ 602 public static PrintWriter diffFile = null; 603 604 /** 605 * Base name of the current file where documentation differences are 606 * written as colored differences. 607 */ 608 public static String diffFileName = "docdiffs_"; 609 610 /** 611 * The name of the current package, used to create diffFileName. 612 */ 613 private static String currPkgName = null; 614 615 /** 616 * If set, then do not generate colored diffs for documentation. 617 * Default is true. 618 */ 619 public static boolean noDocDiffs = true; 620 621 /** 622 * Define the type of emphasis for deleted words. 623 * 0 strikes the words through. 624 * 1 outlines the words in light grey. 625 */ 626 public static int deleteEffect = 0; 627 628 /** 629 * Define the type of emphasis for inserted words. 630 * 0 colors the words red. 631 * 1 outlines the words in yellow, like a highlighter. 632 */ 633 public static int insertEffect = 1; 634 635 /** 636 * For each package and class, the first DiffOutput is added to 637 * this hash table. Used when generating navigation bars. 638 */ 639 public static Hashtable firstDiffOutput = new Hashtable(); 640 641 /** 642 * If set, then show changes in implementation-related modifiers such as 643 * native and synchronized. For more information, see 644 * http://java.sun.com/j2se/1.4.1/docs/tooldocs/solaris/javadoc.html#generatedapideclarations 645 */ 646 public static boolean showAllChanges = false; 647 648 /** The list of documentation differences. */ 649 private static List docDiffs = new ArrayList(); // DiffOutput[] 650 651 /** Set to enable increased logging verbosity for debugging. */ 652 private static boolean trace = false; 653 654} 655