• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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>&nbsp;");
497             else
498                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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>&nbsp;");
600             else
601                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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>&nbsp;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>&nbsp;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>&nbsp;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>&nbsp;");
700             else
701                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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&nbsp;<strike>");
718                 h_.emitTypeWithParens(shownType, false);
719                 h_.writeText("</strike>&nbsp;in&nbsp;" + 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&nbsp;<b>");
729                 h_.emitTypeWithParens(shownType, false);
730                 h_.writeText("</b>&nbsp;in&nbsp;" + 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&nbsp;");
740                 h_.emitTypeWithParens(shownType, false);
741                 h_.writeText("&nbsp;in&nbsp;" + 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>&nbsp;");
816             else
817                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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>&nbsp;in&nbsp;");
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