• 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>");
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>&nbsp;indicates&nbsp;New;&nbsp;<strike>Strike</strike>&nbsp;indicates&nbsp;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>&nbsp;");
501             else
502                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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>&nbsp;");
604             else
605                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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>&nbsp;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>&nbsp;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>&nbsp;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>&nbsp;");
704             else
705                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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&nbsp;<strike>");
722                 h_.emitTypeWithParens(shownType, false);
723                 h_.writeText("</strike>&nbsp;in&nbsp;" + 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&nbsp;<b>");
733                 h_.emitTypeWithParens(shownType, false);
734                 h_.writeText("</b>&nbsp;in&nbsp;" + 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&nbsp;");
744                 h_.emitTypeWithParens(shownType, false);
745                 h_.writeText("&nbsp;in&nbsp;" + 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>&nbsp;");
820             else
821                 h_.writeText("<br><font size=\"+2\">" + Character.toUpperCase(sw) + "</font>&nbsp;");
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("&nbsp;in&nbsp;");
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