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