1 package jdiff; 2 3 import java.util.*; 4 import java.io.*; 5 6 /** 7 * Emit HTML indexes which appear in the bottom left frame in the report. 8 * All indexes are links to JDiff-generated pages. 9 * 10 * See the file LICENSE.txt for copyright details. 11 * @author Matthew Doar, mdoar@pobox.com 12 */ 13 public class HTMLIndexes { 14 15 /** Constructor. */ HTMLIndexes(HTMLReportGenerator h)16 public HTMLIndexes(HTMLReportGenerator h) { 17 h_ = h; 18 } 19 20 /** The HTMLReportGenerator instance used to write HTML. */ 21 private HTMLReportGenerator h_ = null; 22 23 /** Emit all the bottom left frame index files. */ emitAllBottomLeftFiles(String packagesIndexName, String classesIndexName, String constructorsIndexName, String methodsIndexName, String fieldsIndexName, String allDiffsIndexName, APIDiff apiDiff)24 public void emitAllBottomLeftFiles(String packagesIndexName, 25 String classesIndexName, 26 String constructorsIndexName, 27 String methodsIndexName, 28 String fieldsIndexName, 29 String allDiffsIndexName, 30 APIDiff apiDiff) { 31 32 // indexType values: 0 = removals only, 1 = additions only, 33 // 2 = changes only. 3 = all differences. Run all differences 34 // first for all program element types so we know whether there 35 // are any removals etc for the allDiffs index. 36 emitBottomLeftFile(packagesIndexName, apiDiff, 3, "Package"); 37 emitBottomLeftFile(classesIndexName, apiDiff, 3, "Class"); 38 emitBottomLeftFile(constructorsIndexName, apiDiff, 3, "Constructor"); 39 emitBottomLeftFile(methodsIndexName, apiDiff, 3, "Method"); 40 emitBottomLeftFile(fieldsIndexName, apiDiff, 3, "Field"); 41 // The allindex must be done last, since it uses the results from 42 // the previous ones 43 emitBottomLeftFile(allDiffsIndexName, apiDiff, 3, "All"); 44 // Now generate the other indexes 45 for (int indexType = 0; indexType < 3; indexType++) { 46 emitBottomLeftFile(packagesIndexName, apiDiff, indexType, "Package"); 47 emitBottomLeftFile(classesIndexName, apiDiff, indexType, "Class"); 48 emitBottomLeftFile(constructorsIndexName, apiDiff, indexType, "Constructor"); 49 emitBottomLeftFile(methodsIndexName, apiDiff, indexType, "Method"); 50 emitBottomLeftFile(fieldsIndexName, apiDiff, indexType, "Field"); 51 emitBottomLeftFile(allDiffsIndexName, apiDiff, indexType, "All"); 52 } 53 if (missingSincesFile != null) 54 missingSincesFile.close(); 55 } 56 57 /** 58 * Emit a single bottom left frame with the given kind of differences for 59 * the given program element type in an alphabetical index. 60 * 61 * @param indexBaseName The base name of the index file. 62 * @param apiDiff The root element containing all the API differences. 63 * @param indexType 0 = removals only, 1 = additions only, 64 * 2 = changes only, 3 = all differences, 65 * @param programElementType "Package", "Class", "Constructor", 66 * "Method", "Field" or "All". 67 */ emitBottomLeftFile(String indexBaseName, APIDiff apiDiff, int indexType, String programElementType)68 public void emitBottomLeftFile(String indexBaseName, 69 APIDiff apiDiff, int indexType, 70 String programElementType) { 71 String filename = indexBaseName; 72 try { 73 String title = "Indexes"; 74 if (indexType == 0) { 75 filename += "_removals" + h_.reportFileExt; 76 title = programElementType + " Removals Index"; 77 } else if (indexType == 1) { 78 filename += "_additions" + h_.reportFileExt; 79 title = programElementType + " Additions Index"; 80 } else if (indexType == 2) { 81 filename += "_changes" + h_.reportFileExt; 82 title = programElementType + " Changes Index"; 83 } else if (indexType == 3) { 84 filename += "_all" + h_.reportFileExt; 85 title = programElementType + " Differences Index"; 86 } 87 88 FileOutputStream fos = new FileOutputStream(filename); 89 h_.reportFile = new PrintWriter(fos); 90 h_.writeStartHTMLHeader(); 91 h_.writeHTMLTitle(title); 92 h_.writeStyleSheetRef(); 93 h_.writeText("</HEAD>"); 94 h_.writeText("<BODY class=\"gc-documentation\" style=\"padding:12px;\">"); 95 96 if (programElementType.compareTo("Package") == 0) { 97 emitPackagesIndex(apiDiff, indexType); 98 } else if (programElementType.compareTo("Class") == 0) { 99 emitClassesIndex(apiDiff, indexType); 100 } else if (programElementType.compareTo("Constructor") == 0) { 101 emitConstructorsIndex(apiDiff, indexType); 102 } else if (programElementType.compareTo("Method") == 0) { 103 emitMethodsIndex(apiDiff, indexType); 104 } else if (programElementType.compareTo("Field") == 0) { 105 emitFieldsIndex(apiDiff, indexType); 106 } else if (programElementType.compareTo("All") == 0) { 107 emitAllDiffsIndex(apiDiff, indexType); 108 } else{ 109 System.out.println("Error: unknown program element type."); 110 System.exit(3); 111 } 112 113 h_.writeHTMLFooter(); 114 h_.reportFile.close(); 115 } catch(IOException e) { 116 System.out.println("IO Error while attempting to create " + filename); 117 System.out.println("Error: " + e.getMessage()); 118 System.exit(1); 119 } 120 } 121 122 /** 123 * Generate a small header of letters which link to each section, but 124 * do not emit a linked letter for the current section. Finish the list off 125 * with a link to the top of the index. 126 * Caching the results of this function would save about 10s with large APIs. 127 */ generateLetterIndex(List list, char currChar, boolean larger)128 private void generateLetterIndex(List list, char currChar, boolean larger) { 129 if (larger) 130 return; // Currently not using the larger functionality 131 int size = -2; 132 if (larger) 133 size = -1; 134 Iterator iter = null; 135 if (isAllNames) 136 iter = allNames.iterator(); 137 else 138 iter = list.iterator(); 139 char oldsw = '\0'; 140 while (iter.hasNext()) { 141 Index entry = (Index)(iter.next()); 142 char sw = entry.name_.charAt(0); 143 char swu = Character.toUpperCase(sw); 144 if (swu != Character.toUpperCase(oldsw)) { 145 // Don't emit a reference to the current letter 146 if (Character.toUpperCase(sw) != Character.toUpperCase(currChar)) { 147 if (swu == '_') { 148 h_.writeText("<a href=\"#" + swu + "\"><font size=\"" + size + "\">" + "_" + "</font></a> "); 149 } else { 150 h_.writeText("<a href=\"#" + swu + "\"><font size=\"" + size + "\">" + swu + "</font></a> "); 151 } 152 } 153 oldsw = sw; 154 } 155 } 156 h_.writeText(" <a href=\"#topheader\"><font size=\"" + size + "\">TOP</font></a>"); 157 h_.writeText("<p><div style=\"line-height:1.5em;color:black\">"); 158 } 159 160 /** 161 * Emit a header for an index, including suitable links for removed, 162 * added and changes sub-indexes. 163 */ emitIndexHeader(String indexName, int indexType, boolean hasRemovals, boolean hasAdditions, boolean hasChanges)164 private void emitIndexHeader(String indexName, int indexType, 165 boolean hasRemovals, 166 boolean hasAdditions, boolean hasChanges) { 167 String linkIndexName = indexName.toLowerCase(); 168 boolean isAllDiffs = false; 169 if (indexName.compareTo("All Differences") == 0) { 170 linkIndexName = "alldiffs"; 171 isAllDiffs = true; 172 } 173 h_.writeText("<a NAME=\"topheader\"></a>"); // Named anchor 174 h_.writeText("<table summary=\"Index for " + indexName + "\" width=\"100%\" class=\"jdiffIndex\" border=\"0\" cellspacing=\"0\" cellpadding=\"0\" style=\"padding-bottom:0;margin-bottom:0;\">"); 175 h_.writeText(" <tr>"); 176 h_.writeText(" <th class=\"indexHeader\">"); 177 h_.writeText(" Filter the Index:"); 178 h_.writeText(" </th>"); 179 h_.writeText(" </tr>"); 180 h_.writeText(" <tr>"); 181 h_.writeText(" <td class=\"indexText\" style=\"line-height:1.3em;padding-left:2em;\">"); 182 183 if (indexType == 3) { 184 h_.writeText("<b>" + indexName + "</b>"); } 185 else if (isAllDiffs) { 186 h_.writeText("<a href=\"" + linkIndexName + "_index_all" + h_.reportFileExt + "\" xclass=\"hiddenlink\">" + indexName + "</a>"); 187 } 188 else { 189 h_.writeText("<a href=\"" + linkIndexName + "_index_all" + h_.reportFileExt + "\" class=\"staysblack\">All " + indexName + "</a>"); 190 } 191 192 h_.writeText(" <br>"); 193 194 if (hasRemovals) { 195 if (indexType == 0) { 196 h_.writeText("<b>Removals</b>"); 197 } else { 198 h_.writeText("<A HREF=\"" + linkIndexName + "_index_removals" + h_.reportFileExt + "\" xclass=\"hiddenlink\">Removals</A>"); 199 } 200 } else { 201 h_.writeText("<font color=\"#999999\">Removals</font>"); 202 } 203 204 h_.writeText(" <br>"); 205 206 if (hasAdditions) { 207 if (indexType == 1) { 208 h_.writeText("<b>Additions</b>"); 209 } else { 210 h_.writeText("<A HREF=\"" + linkIndexName + "_index_additions" + h_.reportFileExt + "\"xclass=\"hiddenlink\">Additions</A>"); 211 } 212 } else { 213 h_.writeText("<font color=\"#999999\">Additions</font>"); 214 } 215 216 h_.writeText(" <br>"); 217 218 if (hasChanges) { 219 if (indexType == 2) { 220 h_.writeText("<b>Changes</b>"); 221 } else { 222 h_.writeText("<A HREF=\"" + linkIndexName + "_index_changes" + h_.reportFileExt + "\"xclass=\"hiddenlink\">Changes</A>"); 223 } 224 } else { 225 h_.writeText("<font color=\"#999999\">Changes</font>"); 226 } 227 228 h_.writeText(" </td>"); 229 h_.writeText(" </tr>"); 230 h_.writeText("</table>"); 231 h_.writeText("<div id=\"indexTableCaption\" style=\"background-color:#eee;padding:0 4px 0 4px;font-size:11px;margin-bottom:1em;\">"); 232 h_.writeText("Listed as: <span style=\"color:#069\"><strong>Added</strong></span>, <span style=\"color:#069\"><strike>Removed</strike></span>, <span style=\"color:#069\">Changed</span></font>"); 233 h_.writeText("</div>"); 234 235 } 236 237 /** Emit the index of packages, which appears in the bottom left frame. */ emitPackagesIndex(APIDiff apiDiff, int indexType)238 public void emitPackagesIndex(APIDiff apiDiff, int indexType) { 239 // Add all the names of packages to a new list, to be sorted later 240 packageNames = new ArrayList(); // Index[] 241 boolean hasRemovals = false; 242 if (apiDiff.packagesRemoved.size() != 0) 243 hasRemovals = true; 244 boolean hasAdditions = false; 245 if (apiDiff.packagesAdded.size() != 0) 246 hasAdditions = true; 247 boolean hasChanges = false; 248 if (apiDiff.packagesChanged.size() != 0) 249 hasChanges = true; 250 recordDiffs(hasRemovals, hasAdditions, hasChanges); 251 Iterator iter = apiDiff.packagesRemoved.iterator(); 252 while ((indexType == 3 || indexType == 0) && iter.hasNext()) { 253 PackageAPI pkg = (PackageAPI)(iter.next()); 254 packageNames.add(new Index(pkg.name_, 0)); 255 } 256 iter = apiDiff.packagesAdded.iterator(); 257 while ((indexType == 3 || indexType == 1) && iter.hasNext()) { 258 PackageAPI pkg = (PackageAPI)(iter.next()); 259 packageNames.add(new Index(pkg.name_, 1)); 260 } 261 iter = apiDiff.packagesChanged.iterator(); 262 while ((indexType == 3 || indexType == 2) && iter.hasNext()) { 263 PackageDiff pkg = (PackageDiff)(iter.next()); 264 packageNames.add(new Index(pkg.name_, 2)); 265 } 266 Collections.sort(packageNames); 267 268 // No letter index needed for packages 269 270 // Now emit all the package names and links to their respective files 271 emitIndexHeader("Packages", indexType, hasRemovals, hasAdditions, hasChanges); 272 273 // Extra line because no index is emitted 274 h_.writeText("<br>"); 275 276 // Package names are unique, so no need to check for duplicates. 277 iter = packageNames.iterator(); 278 char oldsw = '\0'; 279 h_.writeText("<div id=\"indexTableEntries\">"); 280 while (iter.hasNext()) { 281 Index pkg = (Index)(iter.next()); 282 oldsw = emitPackageIndexEntry(pkg, oldsw); 283 } 284 } 285 286 /** 287 * Emit an index entry for a package. 288 * Package names are unique, so no need to check for duplicates. 289 */ emitPackageIndexEntry(Index pkg, char oldsw)290 public char emitPackageIndexEntry(Index pkg, char oldsw) { 291 char res = oldsw; 292 // See if we are in a new section of the alphabet 293 char sw = pkg.name_.charAt(0); 294 if (Character.toUpperCase(sw) != Character.toUpperCase(oldsw)) { 295 // No need to emit section letters for packages 296 res = sw; 297 // Add the named anchor for this new letter 298 h_.writeText("<A NAME=\"" + Character.toUpperCase(res) + "\"></A>"); 299 } 300 // Package names are unique, so no need to check for duplicates. 301 if (pkg.changeType_ == 0) { 302 h_.writeText("<A HREF=\"" + h_.reportFileName + "-summary" + h_.reportFileExt + "#" + pkg.name_ + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + pkg.name_ + "</strike></A><br>"); 303 } else if (pkg.changeType_ == 1) { 304 h_.writeText("<A HREF=\"" + h_.reportFileName + "-summary" + h_.reportFileExt + "#" + pkg.name_ + "\" class=\"hiddenlink\" target=\"rightframe\"><b>" + pkg.name_ + "</b></A><br>"); 305 } else if (pkg.changeType_ == 2) { 306 h_.writeText("<A HREF=\"pkg_" + pkg.name_ + h_.reportFileExt + "\" class=\"hiddenlink\" target=\"rightframe\">" + pkg.name_ + "</A><br>"); 307 } 308 return res; 309 } 310 311 /** 312 * Emit all the entries and links for the given iterator 313 * to their respective files. 314 */ emitIndexEntries(Iterator iter)315 public void emitIndexEntries(Iterator iter) { 316 char oldsw = '\0'; 317 int multipleMarker = 0; 318 Index currIndex = null; // The entry which is emitted 319 while (iter.hasNext()) { 320 // The next entry after the current one 321 Index nextIndex = (Index)(iter.next()); 322 if (currIndex == null) { 323 currIndex = nextIndex; // Prime the pump 324 } else { 325 if (nextIndex.name_.compareTo(currIndex.name_) == 0) { 326 // It's a duplicate index, so emit the name and then 327 // the indented entries 328 if (multipleMarker == 0) 329 multipleMarker = 1; // Start of a duplicate index 330 else if (multipleMarker == 1) 331 multipleMarker = 2; // Inside a duplicate index 332 oldsw = emitIndexEntry(currIndex, oldsw, multipleMarker); 333 } else { 334 if (multipleMarker == 1) 335 multipleMarker = 2; // Inside a duplicate index 336 oldsw = emitIndexEntry(currIndex, oldsw, multipleMarker); 337 multipleMarker = 0; // Not in a duplicate index any more 338 } 339 currIndex = nextIndex; 340 } 341 } 342 // Emit the last entry left in currIndex 343 if (multipleMarker == 1) 344 multipleMarker = 2; // Inside a duplicate index 345 if (currIndex != null) 346 oldsw = emitIndexEntry(currIndex, oldsw, multipleMarker); 347 } 348 349 /** 350 * Whether to log all missing @since tags to a file or not. 351 * If false, just warn the user. 352 */ 353 public static boolean logMissingSinces = true; 354 355 /** The file used to output details of missing @since tags. */ 356 public static PrintWriter missingSincesFile = null; 357 358 /** 359 * Emit elements in the given iterator which were added and 360 * missing @since tags. 361 */ emitMissingSinces(Iterator iter)362 public void emitMissingSinces(Iterator iter) { 363 // if (!logMissingSinces) 364 // return; 365 if (missingSincesFile == null) { 366 String sinceFileName = h_.outputDir + JDiff.DIR_SEP + "missingSinces.txt"; 367 try { 368 FileOutputStream fos = new FileOutputStream(sinceFileName); 369 missingSincesFile = new PrintWriter(fos); 370 } catch (IOException e) { 371 System.out.println("IO Error while attempting to create " + sinceFileName); 372 System.out.println("Error: " + e.getMessage()); 373 System.exit(1); 374 } 375 } 376 while (iter.hasNext()) { 377 Index currIndex = (Index)(iter.next()); 378 // Only display information about added elements 379 if (currIndex.changeType_ != 1) 380 continue; 381 String programElementType = currIndex.ename_; 382 String details = null; 383 if (programElementType.compareTo("class") == 0) { 384 details = currIndex.pkgName_ + "." + currIndex.name_; 385 if (currIndex.isInterface_) 386 details = details + " Interface"; 387 else 388 details = details + " Class"; 389 } else if (programElementType.compareTo("constructor") == 0) { 390 details = currIndex.pkgName_ + "." + currIndex.name_ + " Constructor (" + currIndex.type_ + ")"; 391 } else if (programElementType.compareTo("method") == 0) { 392 details = currIndex.pkgName_ + "." + currIndex.className_ + " " + "Method " + currIndex.name_ + "(" + currIndex.type_ + ")"; 393 } else if (programElementType.compareTo("field") == 0) { 394 details = currIndex.pkgName_ + "." + currIndex.className_ + " " + "Field " + currIndex.name_; 395 } else { 396 System.out.println("Error: unknown program element type"); 397 System.exit(3); 398 } 399 if (currIndex.doc_ == null) { 400 if (logMissingSinces) 401 missingSincesFile.println("NO DOC BLOCK: " + details); 402 else 403 System.out.println("Warning: the doc block for the new element: " + details + " is missing, so there is no @since tag"); 404 } else if (currIndex.doc_.indexOf("@since") != -1) { 405 if (logMissingSinces) 406 missingSincesFile.println("OK: " + details); 407 } else { 408 if (logMissingSinces) 409 missingSincesFile.println("MISSING @SINCE TAG: " + details); 410 else 411 System.out.println("Warning: the doc block for the new element: " + details + " is missing an @since tag"); 412 } 413 } 414 } 415 416 /** 417 * Emit a single entry and the link to its file. 418 * 419 * @param programElementType "Class", "Constructor", 420 * "Method", or "Field". 421 */ emitIndexEntry(Index currIndex, char oldsw, int multipleMarker)422 public char emitIndexEntry(Index currIndex, char oldsw, int multipleMarker) { 423 String programElementType = currIndex.ename_; 424 if (programElementType.compareTo("class") == 0) { 425 return emitClassIndexEntry(currIndex, oldsw, multipleMarker); 426 } else if (programElementType.compareTo("constructor") == 0) { 427 return emitCtorIndexEntry(currIndex, oldsw, multipleMarker); 428 } else if (programElementType.compareTo("method") == 0) { 429 return emitMethodIndexEntry(currIndex, oldsw, multipleMarker); 430 } else if (programElementType.compareTo("field") == 0) { 431 return emitFieldIndexEntry(currIndex, oldsw, multipleMarker); 432 } else { 433 System.out.println("Error: unknown program element type"); 434 System.exit(3); 435 } 436 return '\0'; 437 } 438 439 /** Emit the index of classes, which appears in the bottom left frame. */ emitClassesIndex(APIDiff apiDiff, int indexType)440 public void emitClassesIndex(APIDiff apiDiff, int indexType) { 441 // Add all the names of classes to a new list, to be sorted later 442 classNames = new ArrayList(); // Index[] 443 boolean hasRemovals = false; 444 boolean hasAdditions = false; 445 boolean hasChanges = false; 446 Iterator iter = apiDiff.packagesChanged.iterator(); 447 while (iter.hasNext()) { 448 PackageDiff pkgDiff = (PackageDiff)(iter.next()); 449 if (pkgDiff.classesRemoved.size() != 0) 450 hasRemovals = true; 451 if (pkgDiff.classesAdded.size() != 0) 452 hasAdditions = true; 453 if (pkgDiff.classesChanged.size() != 0) 454 hasChanges = true; 455 recordDiffs(hasRemovals, hasAdditions, hasChanges); 456 String pkgName = pkgDiff.name_; 457 Iterator iterClass = pkgDiff.classesRemoved.iterator(); 458 while ((indexType == 3 || indexType == 0) && iterClass.hasNext()) { 459 ClassAPI cls = (ClassAPI)(iterClass.next()); 460 classNames.add(new Index(cls.name_, 0, pkgName, cls.isInterface_)); 461 } 462 iterClass = pkgDiff.classesAdded.iterator(); 463 while ((indexType == 3 || indexType == 1) && iterClass.hasNext()) { 464 ClassAPI cls = (ClassAPI)(iterClass.next()); 465 Index idx = new Index(cls.name_, 1, pkgName, cls.isInterface_); 466 idx.doc_ = cls.doc_; // Used for checking @since 467 classNames.add(idx); 468 } 469 iterClass = pkgDiff.classesChanged.iterator(); 470 while ((indexType == 3 || indexType == 2) && iterClass.hasNext()) { 471 ClassDiff cls = (ClassDiff)(iterClass.next()); 472 classNames.add(new Index(cls.name_, 2, pkgName, cls.isInterface_)); 473 } 474 } 475 Collections.sort(classNames); 476 emitIndexHeader("Classes", indexType, hasRemovals, hasAdditions, hasChanges); 477 emitIndexEntries(classNames.iterator()); 478 if (indexType == 1) 479 emitMissingSinces(classNames.iterator()); 480 } 481 482 /** Emit an index entry for a class. */ emitClassIndexEntry(Index cls, char oldsw, int multipleMarker)483 public char emitClassIndexEntry(Index cls, char oldsw, 484 int multipleMarker) { 485 char res = oldsw; 486 String className = cls.pkgName_ + "." + cls.name_; 487 String classRef = cls.pkgName_ + "." + cls.name_; 488 boolean isInterface = cls.isInterface_; 489 // See if we are in a new section of the alphabet 490 char sw = cls.name_.charAt(0); 491 if (Character.toUpperCase(sw) != Character.toUpperCase(oldsw)) { 492 res = sw; 493 // Add the named anchor for this new letter 494 h_.writeText("<A NAME=\"" + Character.toUpperCase(res) + "\"></A>"); 495 if (sw == '_') 496 h_.writeText("<br><b>_</b> "); 497 else 498 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font> "); 499 generateLetterIndex(classNames, sw, false); 500 } 501 // Deal with displaying duplicate indexes 502 if (multipleMarker == 1) { 503 h_.writeText("<i>" + cls.name_ + "</i><br>"); 504 } 505 if (multipleMarker != 0) 506 h_.indent(INDENT_SIZE); 507 if (cls.changeType_ == 0) { 508 // Emit a reference to the correct place for the class in the 509 // JDiff page for the package 510 h_.writeText("<A HREF=\"pkg_" + cls.pkgName_ + h_.reportFileExt + 511 "#" + cls.name_ + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + cls.name_ + "</strike></A><br>"); 512 } else if (cls.changeType_ == 1) { 513 String cn = cls.name_; 514 if (multipleMarker != 0) 515 cn = cls.pkgName_; 516 if (isInterface) 517 h_.writeText("<A HREF=\"pkg_" + cls.pkgName_ + h_.reportFileExt + "#" + cls.name_ + "\" class=\"hiddenlink\" target=\"rightframe\"><b><i>" + cn + "</i></b></A><br>"); 518 else 519 h_.writeText("<A HREF=\"pkg_" + cls.pkgName_ + h_.reportFileExt + "#" + cls.name_ + "\" class=\"hiddenlink\" target=\"rightframe\"><b>" + cn + "</b></A><br>"); 520 } else if (cls.changeType_ == 2) { 521 String cn = cls.name_; 522 if (multipleMarker != 0) 523 cn = cls.pkgName_; 524 if (isInterface) 525 h_.writeText("<A HREF=\"" + classRef + h_.reportFileExt + "\" class=\"hiddenlink\" target=\"rightframe\"><i>" + cn + "</i></A><br>"); 526 else 527 h_.writeText("<A HREF=\"" + classRef + h_.reportFileExt + "\" class=\"hiddenlink\" target=\"rightframe\">" + cn + "</A><br>"); 528 } 529 return res; 530 } 531 532 /** 533 * Emit the index of all constructors, which appears in the bottom left 534 * frame. 535 */ emitConstructorsIndex(APIDiff apiDiff, int indexType)536 public void emitConstructorsIndex(APIDiff apiDiff, int indexType) { 537 // Add all the names of constructors to a new list, to be sorted later 538 ctorNames = new ArrayList(); // Index[] 539 boolean hasRemovals = false; 540 boolean hasAdditions = false; 541 boolean hasChanges = false; 542 Iterator iter = apiDiff.packagesChanged.iterator(); 543 while (iter.hasNext()) { 544 PackageDiff pkgDiff = (PackageDiff)(iter.next()); 545 String pkgName = pkgDiff.name_; 546 Iterator iterClass = pkgDiff.classesChanged.iterator(); 547 while (iterClass.hasNext()) { 548 ClassDiff classDiff = (ClassDiff)(iterClass.next()); 549 if (classDiff.ctorsRemoved.size() != 0) 550 hasRemovals = true; 551 if (classDiff.ctorsAdded.size() != 0) 552 hasAdditions = true; 553 if (classDiff.ctorsChanged.size() != 0) 554 hasChanges = true; 555 recordDiffs(hasRemovals, hasAdditions, hasChanges); 556 String className = classDiff.name_; 557 Iterator iterCtor = classDiff.ctorsRemoved.iterator(); 558 while ((indexType == 3 || indexType == 0) && iterCtor.hasNext()) { 559 ConstructorAPI ctor = (ConstructorAPI)(iterCtor.next()); 560 ctorNames.add(new Index(className, 0, pkgName, ctor.getSignature())); 561 } 562 iterCtor = classDiff.ctorsAdded.iterator(); 563 while ((indexType == 3 || indexType == 1) && iterCtor.hasNext()) { 564 ConstructorAPI ctor = (ConstructorAPI)(iterCtor.next()); 565 Index idx = new Index(className, 1, pkgName, ctor.getSignature()); 566 idx.doc_ = ctor.doc_; // Used for checking @since 567 ctorNames.add(idx); 568 } 569 iterCtor = classDiff.ctorsChanged.iterator(); 570 while ((indexType == 3 || indexType == 2) && iterCtor.hasNext()) { 571 MemberDiff ctor = (MemberDiff)(iterCtor.next()); 572 ctorNames.add(new Index(className, 2, pkgName, ctor.newType_)); 573 } 574 } 575 } 576 Collections.sort(ctorNames); 577 emitIndexHeader("Constructors", indexType, hasRemovals, hasAdditions, hasChanges); 578 emitIndexEntries(ctorNames.iterator()); 579 if (indexType == 1) 580 emitMissingSinces(ctorNames.iterator()); 581 } 582 583 /** Emit an index entry for a constructor. */ emitCtorIndexEntry(Index ctor, char oldsw, int multipleMarker)584 public char emitCtorIndexEntry(Index ctor, char oldsw, int multipleMarker) { 585 char res = oldsw; 586 String className = ctor.pkgName_ + "." + ctor.name_; 587 String memberRef = ctor.pkgName_ + "." + ctor.name_; 588 String type = ctor.type_; 589 if (type.compareTo("void") == 0) 590 type = ""; 591 String shownType = HTMLReportGenerator.simpleName(type); 592 // See if we are in a new section of the alphabet 593 char sw = ctor.name_.charAt(0); 594 if (Character.toUpperCase(sw) != Character.toUpperCase(oldsw)) { 595 res = sw; 596 // Add the named anchor for this new letter 597 h_.writeText("<A NAME=\"" + Character.toUpperCase(res) + "\"></A>"); 598 if (sw == '_') 599 h_.writeText("<br><b>_</b> "); 600 else 601 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font> "); 602 generateLetterIndex(ctorNames, sw, false); 603 } 604 // Deal with displaying duplicate indexes 605 if (multipleMarker == 1) { 606 h_.writeText("<i>" + ctor.name_ + "</i><br>"); 607 } 608 if (multipleMarker != 0) 609 h_.indent(INDENT_SIZE); 610 // Deal with each type of difference 611 // The output displayed for unique or duplicate entries is the same 612 // for constructors. 613 if (ctor.changeType_ == 0) { 614 String commentID = className + ".ctor_removed(" + type + ")"; 615 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + ctor.name_ + "</strike>"); 616 h_.emitTypeWithParens(shownType, false); 617 h_.writeText("</A></nobr> constructor<br>"); 618 } else if (ctor.changeType_ == 1) { 619 String commentID = className + ".ctor_added(" + type + ")"; 620 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><b>" + ctor.name_ + "</b>"); 621 h_.emitTypeWithParens(shownType, false); 622 h_.writeText("</A></nobr> constructor<br>"); 623 } else if (ctor.changeType_ == 2) { 624 String commentID = className + ".ctor_changed(" + type + ")"; 625 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + ctor.name_); 626 h_.emitTypeWithParens(shownType, false); 627 h_.writeText("</A></nobr> constructor<br>"); 628 } 629 return res; 630 } 631 632 /** 633 * Emit the index of all methods, which appears in the bottom left frame. 634 */ emitMethodsIndex(APIDiff apiDiff, int indexType)635 public void emitMethodsIndex(APIDiff apiDiff, int indexType) { 636 // Add all the names of methods to a new list, to be sorted later 637 methNames = new ArrayList(); // Index[] 638 boolean hasRemovals = false; 639 boolean hasAdditions = false; 640 boolean hasChanges = false; 641 Iterator iter = apiDiff.packagesChanged.iterator(); 642 while (iter.hasNext()) { 643 PackageDiff pkgDiff = (PackageDiff)(iter.next()); 644 String pkgName = pkgDiff.name_; 645 Iterator iterClass = pkgDiff.classesChanged.iterator(); 646 while (iterClass.hasNext()) { 647 ClassDiff classDiff = (ClassDiff)(iterClass.next()); 648 if (classDiff.methodsRemoved.size() != 0) 649 hasRemovals = true; 650 if (classDiff.methodsAdded.size() != 0) 651 hasAdditions = true; 652 if (classDiff.methodsChanged.size() != 0) 653 hasChanges = true; 654 recordDiffs(hasRemovals, hasAdditions, hasChanges); 655 String className = classDiff.name_; 656 Iterator iterMeth = classDiff.methodsRemoved.iterator(); 657 while ((indexType == 3 || indexType == 0) && iterMeth.hasNext()) { 658 MethodAPI meth = (MethodAPI)(iterMeth.next()); 659 methNames.add(new Index(meth.name_, 0, pkgName, className, meth.getSignature())); 660 } 661 iterMeth = classDiff.methodsAdded.iterator(); 662 while ((indexType == 3 || indexType == 1) && iterMeth.hasNext()) { 663 MethodAPI meth = (MethodAPI)(iterMeth.next()); 664 Index idx = new Index(meth.name_, 1, pkgName, className, meth.getSignature()); 665 idx.doc_ = meth.doc_; // Used for checking @since 666 methNames.add(idx); 667 } 668 iterMeth = classDiff.methodsChanged.iterator(); 669 while ((indexType == 3 || indexType == 2) && iterMeth.hasNext()) { 670 MemberDiff meth = (MemberDiff)(iterMeth.next()); 671 methNames.add(new Index(meth.name_, 2, pkgName, className, meth.newSignature_)); 672 } 673 } 674 } 675 Collections.sort(methNames); 676 emitIndexHeader("Methods", indexType, hasRemovals, hasAdditions, hasChanges); 677 emitIndexEntries(methNames.iterator()); 678 if (indexType == 1) 679 emitMissingSinces(methNames.iterator()); 680 } 681 682 /** Emit an index entry for a method. */ emitMethodIndexEntry(Index meth, char oldsw, int multipleMarker)683 public char emitMethodIndexEntry(Index meth, char oldsw, 684 int multipleMarker) { 685 char res = oldsw; 686 String className = meth.pkgName_ + "." + meth.className_; 687 String memberRef = meth.pkgName_ + "." + meth.className_; 688 String type = meth.type_; 689 if (type.compareTo("void") == 0) 690 type = ""; 691 String shownType = HTMLReportGenerator.simpleName(type); 692 // See if we are in a new section of the alphabet 693 char sw = meth.name_.charAt(0); 694 if (Character.toUpperCase(sw) != Character.toUpperCase(oldsw)) { 695 res = sw; 696 // Add the named anchor for this new letter 697 h_.writeText("<A NAME=\"" + Character.toUpperCase(res) + "\"></A>"); 698 if (sw == '_') 699 h_.writeText("<br><b>_</b> "); 700 else 701 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font> "); 702 generateLetterIndex(methNames, sw, false); 703 } 704 // Deal with displaying duplicate indexes 705 if (multipleMarker == 1) { 706 h_.writeText("<i>" + meth.name_ + "</i><br>"); 707 } 708 if (multipleMarker != 0) 709 h_.indent(INDENT_SIZE); 710 // Deal with each type of difference 711 if (meth.changeType_ == 0) { 712 String commentID = className + "." + meth.name_ + "_removed(" + type + ")"; 713 if (multipleMarker == 0) { 714 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + meth.name_ + "</strike>"); 715 h_.emitTypeWithParens(shownType, false); 716 } else { 717 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">type <strike>"); 718 h_.emitTypeWithParens(shownType, false); 719 h_.writeText("</strike> in " + className); 720 } 721 h_.writeText("</A></nobr><br>"); 722 } else if (meth.changeType_ == 1) { 723 String commentID = className + "." + meth.name_ + "_added(" + type + ")"; 724 if (multipleMarker == 0) { 725 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><b>" + meth.name_ + "</b>"); 726 h_.emitTypeWithParens(shownType, false); 727 } else { 728 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">type <b>"); 729 h_.emitTypeWithParens(shownType, false); 730 h_.writeText("</b> in " + className); 731 } 732 h_.writeText("</A></nobr><br>"); 733 } else if (meth.changeType_ == 2) { 734 String commentID = className + "." + meth.name_ + "_changed(" + type + ")"; 735 if (multipleMarker == 0) { 736 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + meth.name_); 737 h_.emitTypeWithParens(shownType, false); 738 } else { 739 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">type "); 740 h_.emitTypeWithParens(shownType, false); 741 h_.writeText(" in " + className); 742 } 743 h_.writeText("</A></nobr><br>"); 744 } 745 return res; 746 } 747 748 /** 749 * Emit the index of all fields, which appears in the bottom left frame. 750 */ emitFieldsIndex(APIDiff apiDiff, int indexType)751 public void emitFieldsIndex(APIDiff apiDiff, int indexType) { 752 // Add all the names of fields to a new list, to be sorted later 753 fieldNames = new ArrayList(); // Index[] 754 boolean hasRemovals = false; 755 boolean hasAdditions = false; 756 boolean hasChanges = false; 757 Iterator iter = apiDiff.packagesChanged.iterator(); 758 while (iter.hasNext()) { 759 PackageDiff pkgDiff = (PackageDiff)(iter.next()); 760 String pkgName = pkgDiff.name_; 761 Iterator iterClass = pkgDiff.classesChanged.iterator(); 762 while (iterClass.hasNext()) { 763 ClassDiff classDiff = (ClassDiff)(iterClass.next()); 764 if (classDiff.fieldsRemoved.size() != 0) 765 hasRemovals = true; 766 if (classDiff.fieldsAdded.size() != 0) 767 hasAdditions = true; 768 if (classDiff.fieldsChanged.size() != 0) 769 hasChanges = true; 770 recordDiffs(hasRemovals, hasAdditions, hasChanges); 771 String className = classDiff.name_; 772 Iterator iterField = classDiff.fieldsRemoved.iterator(); 773 while ((indexType == 3 || indexType == 0) && iterField.hasNext()) { 774 FieldAPI fld = (FieldAPI)(iterField.next()); 775 fieldNames.add(new Index(fld.name_, 0, pkgName, className, fld.type_, true)); 776 } 777 iterField = classDiff.fieldsAdded.iterator(); 778 while ((indexType == 3 || indexType == 1) && iterField.hasNext()) { 779 FieldAPI fld = (FieldAPI)(iterField.next()); 780 Index idx = new Index(fld.name_, 1, pkgName, className, fld.type_, true); 781 idx.doc_ = fld.doc_; // Used for checking @since 782 fieldNames.add(idx); 783 } 784 iterField = classDiff.fieldsChanged.iterator(); 785 while ((indexType == 3 || indexType == 2) && iterField.hasNext()) { 786 MemberDiff fld = (MemberDiff)(iterField.next()); 787 fieldNames.add(new Index(fld.name_, 2, pkgName, className, fld.newType_, true)); 788 } 789 } 790 } 791 Collections.sort(fieldNames); 792 emitIndexHeader("Fields", indexType, hasRemovals, hasAdditions, hasChanges); 793 emitIndexEntries(fieldNames.iterator()); 794 if (indexType == 1) 795 emitMissingSinces(fieldNames.iterator()); 796 } 797 798 /** Emit an index entry for a field. */ emitFieldIndexEntry(Index fld, char oldsw, int multipleMarker)799 public char emitFieldIndexEntry(Index fld, char oldsw, 800 int multipleMarker) { 801 char res = oldsw; 802 String className = fld.pkgName_ + "." + fld.className_; 803 String memberRef = fld.pkgName_ + "." + fld.className_; 804 String type = fld.type_; 805 if (type.compareTo("void") == 0) 806 type = ""; 807 String shownType = HTMLReportGenerator.simpleName(type); 808 // See if we are in a new section of the alphabet 809 char sw = fld.name_.charAt(0); 810 if (Character.toUpperCase(sw) != Character.toUpperCase(oldsw)) { 811 res = sw; 812 // Add the named anchor for this new letter 813 h_.writeText("<A NAME=\"" + Character.toUpperCase(res) + "\"></A>"); 814 if (sw == '_') 815 h_.writeText("<br><b>_</b> "); 816 else 817 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font> "); 818 generateLetterIndex(fieldNames, sw, false); 819 } 820 // Deal with displaying duplicate indexes 821 if (multipleMarker == 1) { 822 h_.writeText("<i>" + fld.name_ + "</i><br>"); 823 } 824 if (multipleMarker != 0) { 825 h_.writeText("<nobr> in "); 826 } 827 // Deal with each type of difference 828 if (fld.changeType_ == 0) { 829 String commentID = className + "." + fld.name_; 830 if (multipleMarker == 0) { 831 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + fld.name_ + "</strike></A>"); 832 h_.writeText("</nobr><br>"); 833 } else { 834 h_.writeText("<A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\"><strike>" + className + "</strike></A>"); 835 h_.writeText("</nobr><br>"); 836 } 837 } else if (fld.changeType_ == 1) { 838 String commentID = className + "." + fld.name_; 839 if (multipleMarker == 0) { 840 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + fld.name_ + "</A>"); 841 h_.writeText("</nobr><br>"); 842 } else { 843 h_.writeText("<A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + className + "</A>"); 844 h_.writeText("</nobr><br>"); 845 } 846 } else if (fld.changeType_ == 2) { 847 String commentID = className + "." + fld.name_; 848 if (multipleMarker == 0) { 849 h_.writeText("<nobr><A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + fld.name_ + "</A>"); 850 h_.writeText("</nobr><br>"); 851 } else { 852 h_.writeText("<A HREF=\"" + memberRef + h_.reportFileExt + "#" + commentID + "\" class=\"hiddenlink\" target=\"rightframe\">" + className + "</A>"); 853 h_.writeText("</nobr><br>"); 854 } 855 } 856 return res; 857 } 858 859 /** 860 * Emit the index of all changes, which appears in the bottom left frame. 861 * Has to be run after all the other indexes have been written, since it 862 * uses data from when they are generated. 863 */ emitAllDiffsIndex(APIDiff apiDiff, int indexType)864 public void emitAllDiffsIndex(APIDiff apiDiff, int indexType) { 865 allNames = new ArrayList(); // Index[] 866 // Add all the changes into one big list, and sort it by name, 867 // ignoring case 868 allNames.addAll(packageNames); 869 allNames.addAll(classNames); 870 allNames.addAll(ctorNames); 871 allNames.addAll(methNames); 872 allNames.addAll(fieldNames); 873 // Compares two Index objects' names, ignoring case differences. 874 Collections.sort(allNames); 875 876 emitIndexHeader("All Differences", indexType, atLeastOneRemoval, 877 atLeastOneAddition, atLeastOneChange); 878 879 // Tell generateLetterIndex to use allNames as the list when 880 // using the other methods to generate the indexes. 881 isAllNames = true; 882 883 // Now emit a line for each entry in the list in the appropriate 884 // format for each program element 885 Iterator iter = allNames.iterator(); 886 char oldsw = '\0'; 887 int multipleMarker = 0; 888 Index currIndex = null; // The entry which is emitted 889 while (iter.hasNext()) { 890 // The next entry after the current one 891 Index nextIndex = (Index)(iter.next()); 892 if (currIndex == null) { 893 currIndex = nextIndex; // Prime the pump 894 } else { 895 if (nextIndex.name_.compareTo(currIndex.name_) == 0) { 896 // It's a duplicate index, so emit the name and then 897 // the indented entries 898 if (multipleMarker == 0) 899 multipleMarker = 1; // Start of a duplicate index 900 else if (multipleMarker == 1) 901 multipleMarker = 2; // Inside a duplicate index 902 oldsw = emitIndexEntryForAny(currIndex, oldsw, multipleMarker); 903 } else { 904 if (multipleMarker == 1) 905 multipleMarker = 2; // Inside a duplicate index 906 oldsw = emitIndexEntryForAny(currIndex, oldsw, multipleMarker); 907 multipleMarker = 0; // Not in a duplicate index any more 908 } 909 currIndex = nextIndex; 910 } 911 } 912 // Emit the last entry left in currIndex 913 if (multipleMarker == 1) 914 multipleMarker = 2; // Inside a duplicate index 915 if (currIndex != null) 916 oldsw = emitIndexEntryForAny(currIndex, oldsw, multipleMarker); 917 918 // Tell generateLetterIndex to stop using allNames as the list when 919 // using the other methods to generate the indexes. 920 isAllNames = false; 921 } 922 923 /** Call the appropriate *IndexEntry method for each entry. */ emitIndexEntryForAny(Index currIndex, char oldsw, int multipleMarker)924 public char emitIndexEntryForAny(Index currIndex, char oldsw, 925 int multipleMarker) { 926 if (currIndex.ename_.compareTo("package") == 0) { 927 h_.writeText("<!-- Package " + currIndex.name_ + " -->"); 928 return emitPackageIndexEntry(currIndex, oldsw); 929 } else if (currIndex.ename_.compareTo("class") == 0) { 930 h_.writeText("<!-- Class " + currIndex.name_ + " -->"); 931 return emitClassIndexEntry(currIndex, oldsw, multipleMarker); 932 } else if (currIndex.ename_.compareTo("constructor") == 0) { 933 h_.writeText("<!-- Constructor " + currIndex.name_ + " -->"); 934 return emitCtorIndexEntry(currIndex, oldsw, multipleMarker); 935 } else if (currIndex.ename_.compareTo("method") == 0) { 936 h_.writeText("<!-- Method " + currIndex.name_ + " -->"); 937 return emitMethodIndexEntry(currIndex, oldsw, multipleMarker); 938 } else if (currIndex.ename_.compareTo("field") == 0) { 939 h_.writeText("<!-- Field " + currIndex.name_ + " -->"); 940 return emitFieldIndexEntry(currIndex, oldsw, multipleMarker); 941 } 942 return '\0'; 943 } 944 945 /** The list of all changes for all program elements. */ 946 private List allNames = null; // Index[] 947 948 /** The list of all package changes. */ 949 private List packageNames = null; // Index[] 950 951 /** The list of all class changes. */ 952 private List classNames = null; // Index[] 953 954 /** The list of all constructor changes. */ 955 private List ctorNames = null; // Index[] 956 957 /** The list of all method changes. */ 958 private List methNames = null; // Index[] 959 960 /** The list of all field changes. */ 961 private List fieldNames = null; // Index[] 962 963 /** If set, then use allNames to generate the letter indexes. */ 964 private boolean isAllNames = false; 965 966 /** 967 * If any of the parameters are set, then set the respective atLeastOne 968 * variable, used to generate the links at the top of the allDiffs index. 969 * Never unset an atLeastOne variable. 970 */ recordDiffs(boolean hasRemovals, boolean hasAdditions, boolean hasChanges)971 private void recordDiffs(boolean hasRemovals, boolean hasAdditions, 972 boolean hasChanges) { 973 if (hasRemovals) 974 atLeastOneRemoval = true; 975 if (hasAdditions) 976 atLeastOneAddition = true; 977 if (hasChanges) 978 atLeastOneChange = true; 979 } 980 981 /** Set if there was at least one removal in the entire API. */ 982 private boolean atLeastOneRemoval = false; 983 984 /** Set if there was at least one addition in the entire API. */ 985 private boolean atLeastOneAddition = false; 986 987 /** Set if there was at least one change in the entire API. */ 988 private boolean atLeastOneChange = false; 989 990 /** 991 * The number of non-breaking spaces to indent a duplicate indexes' 992 * entries by. 993 */ 994 private final int INDENT_SIZE = 2; 995 } 996 997 /** 998 * Class used to produce indexes of packages and classes. 999 * 1000 * See the file LICENSE.txt for copyright details. 1001 * @author Matthew Doar, mdoar@pobox.com 1002 */ 1003 class Index implements Comparable { 1004 1005 /** The name of the program element this Index object represents. */ 1006 public String ename_ = null; 1007 1008 /** Name of the changed package, class or member. */ 1009 public String name_ = null; 1010 1011 /** Type of change. 0 = remove, 1 = add, 2 = change. */ 1012 public int changeType_; 1013 1014 /** Name of the changed package if name_ is a class name. */ 1015 public String pkgName_ = null; 1016 1017 /** Set if this class is an interface. */ 1018 public boolean isInterface_= false; 1019 1020 /** The doc block of added elements, default is null. */ 1021 public String doc_ = null; 1022 1023 /** 1024 * The new member type. For methods, this is the signature. 1025 */ 1026 public String type_ = null; 1027 1028 /** 1029 * The class name. Only used by methods. 1030 */ 1031 public String className_ = null; 1032 1033 /** Constructor for packages. */ Index(String name, int changeType)1034 public Index(String name, int changeType) { 1035 ename_ = "package"; 1036 name_ = name; 1037 changeType_ = changeType; 1038 } 1039 1040 /** Constructor for classes. */ Index(String name, int changeType, String pkgName, boolean isInterface)1041 public Index(String name, int changeType, String pkgName, boolean isInterface) { 1042 ename_ = "class"; 1043 name_ = name; 1044 changeType_ = changeType; 1045 pkgName_ = pkgName; 1046 isInterface_ = isInterface; 1047 } 1048 1049 /** Constructor for constructors. */ Index(String name, int changeType, String pkgName, String type)1050 public Index(String name, int changeType, String pkgName, String type) { 1051 ename_ = "constructor"; 1052 name_ = name; 1053 changeType_ = changeType; 1054 pkgName_ = pkgName; 1055 type_ = type; 1056 } 1057 1058 /** Constructor for methods. */ Index(String name, int changeType, String pkgName, String className, String type)1059 public Index(String name, int changeType, String pkgName, 1060 String className, String type) { 1061 ename_ = "method"; 1062 name_ = name; 1063 changeType_ = changeType; 1064 pkgName_ = pkgName; 1065 className_ = className; 1066 type_ = type; 1067 } 1068 1069 /** 1070 * Constructor for fields. 1071 * 1072 * The boolean <code>fld</code> is simply there to differentiate this 1073 * constructor from the one for methods. 1074 */ Index(String name, int changeType, String pkgName, String className, String type, boolean fld)1075 public Index(String name, int changeType, String pkgName, 1076 String className, String type, boolean fld) { 1077 ename_ = "field"; 1078 name_ = name; 1079 changeType_ = changeType; 1080 pkgName_ = pkgName; 1081 className_ = className; 1082 type_ = type; 1083 } 1084 1085 1086 /** Compare two Index objects by their simple names, ignoring case. */ compareTo(Object o)1087 public int compareTo(Object o) { 1088 return name_.compareToIgnoreCase(((Index)o).name_); 1089 } 1090 1091 } 1092 1093