Imported Upstream version 4.8.1
[platform/upstream/gcc48.git] / libjava / classpath / tools / gnu / classpath / tools / doclets / htmldoclet / HtmlDoclet.java
1 /* gnu.classpath.tools.doclets.htmldoclet.HtmlDoclet
2    Copyright (C) 2004, 2012 Free Software Foundation, Inc.
3
4 This file is part of GNU Classpath.
5
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
19 02111-1307 USA.
20
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37
38 package gnu.classpath.tools.doclets.htmldoclet;
39
40 import gnu.classpath.tools.IOToolkit;
41
42 import gnu.classpath.tools.doclets.AbstractDoclet;
43 import gnu.classpath.tools.doclets.DocletConfigurationException;
44 import gnu.classpath.tools.doclets.DocletOption;
45 import gnu.classpath.tools.doclets.DocletOptionFile;
46 import gnu.classpath.tools.doclets.DocletOptionFlag;
47 import gnu.classpath.tools.doclets.DocletOptionString;
48 import gnu.classpath.tools.doclets.PackageGroup;
49 import gnu.classpath.tools.doclets.TagletPrinter;
50 import gnu.classpath.tools.doclets.InlineTagRenderer;
51
52 import gnu.classpath.tools.doclets.xmldoclet.HtmlRepairer;
53
54 import gnu.classpath.tools.taglets.GnuExtendedTaglet;
55 import gnu.classpath.tools.taglets.TagletContext;
56
57 import gnu.classpath.tools.java2xhtml.Java2xhtml;
58
59 import gnu.classpath.tools.StringToolkit;
60
61 import com.sun.javadoc.*;
62 import com.sun.tools.doclets.Taglet;
63
64 import java.io.ByteArrayInputStream;
65 import java.io.File;
66 import java.io.FileInputStream;
67 import java.io.FileNotFoundException;
68 import java.io.FileOutputStream;
69 import java.io.FileReader;
70 import java.io.FileWriter;
71 import java.io.InputStream;
72 import java.io.InputStreamReader;
73 import java.io.IOException;
74 import java.io.OutputStreamWriter;
75 import java.io.PrintWriter;
76 import java.io.StringWriter;
77
78 import java.net.MalformedURLException;
79
80 import java.nio.charset.Charset;
81
82 import java.text.DateFormat;
83 import java.text.MessageFormat;
84
85 import java.util.Arrays;
86 import java.util.Calendar;
87 import java.util.Collection;
88 import java.util.Date;
89 import java.util.HashMap;
90 import java.util.Iterator;
91 import java.util.LinkedHashSet;
92 import java.util.LinkedList;
93 import java.util.List;
94 import java.util.ListIterator;
95 import java.util.Locale;
96 import java.util.Map;
97 import java.util.Properties;
98 import java.util.Set;
99 import java.util.SortedSet;
100 import java.util.TimeZone;
101 import java.util.TreeSet;
102
103 public class HtmlDoclet
104    extends AbstractDoclet
105    implements InlineTagRenderer
106 {
107    private static String filenameExtension = ".html";
108
109    /**
110     *  Contains ExternalDocSet.
111     */
112    private List<ExternalDocSet> externalDocSets = new LinkedList<ExternalDocSet>();
113
114    /**
115     *  Contains String->ExternalDocSet.
116     */
117    private Map<String,ExternalDocSet> packageNameToDocSet = new HashMap<String, ExternalDocSet>();
118
119    /**
120     *  Cache for version string from resource /version.properties
121     */
122    private String docletVersion;
123
124    /**
125     *  For now, do not output a help page.
126     */
127    private static final boolean outputHelpPage = false;
128
129    /**
130     *  Stores the output encoding (either the one specified using
131     *  -charset, or the platform default encoding).
132     */
133    private String outputCharset;
134
135    private void printNavBar(HtmlPage output, String currentPage, ClassDoc currentClass)
136    {
137          output.beginDiv(CssClass.NAVBAR_TOP);
138
139          boolean overviewLevel
140             = ("overview".equals(currentPage)
141                || "full-tree".equals(currentPage)
142                || "index".equals(currentPage)
143                || "split-index".equals(currentPage)
144                || "serialized".equals(currentPage)
145                || "deprecated".equals(currentPage)
146                || "about".equals(currentPage)
147                );
148
149          if (!isSinglePackage()) {
150             if ("overview".equals(currentPage)) {
151                output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
152                output.print("Overview");
153                output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
154             }
155             else {
156                output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
157                output.beginAnchor(output.getPathToRoot() + "/overview-summary" + filenameExtension);
158                output.print("Overview");
159                output.endAnchor();
160                output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
161             }
162
163             output.print(" ");
164          }
165
166          if (!overviewLevel || isSinglePackage()) {
167             if ("package".equals(currentPage)) {
168                output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
169                output.print("Package");
170                output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
171             }
172             else {
173                output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
174                String packageHref;
175                if (isSinglePackage()) {
176                   packageHref = output.getPathToRoot() + "/" + getPackageURL(getSinglePackage()) + "package-summary" + filenameExtension;
177                }
178                else {
179                   packageHref = "package-summary" + filenameExtension;
180                }
181                output.beginAnchor(packageHref);
182                output.print("Package");
183                output.endAnchor();
184                output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
185             }
186          }
187          else {
188             output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
189             output.print("Package");
190             output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
191          }
192
193          if (optionUse.getValue() || optionLinkSource.getValue()) {
194             output.print(" ");
195
196             if (null != currentClass) {
197                if ("class".equals(currentPage)) {
198                   output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
199                   output.print("Class");
200                   output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
201                }
202                else {
203                   output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
204                   output.beginAnchor(currentClass.name() + filenameExtension);
205                   output.print("Class");
206                   output.endAnchor();
207                   output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
208                }
209             }
210             else {
211                output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
212                output.print("Class");
213                output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
214             }
215
216             if (optionUse.getValue()) {
217                output.print(" ");
218
219                if (null != currentClass) {
220                   if ("uses".equals(currentPage)) {
221                      output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
222                      output.print("Use");
223                      output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
224                   }
225                   else {
226                      output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
227                      output.beginAnchor(currentClass.name() + "-uses" + filenameExtension);
228                      output.print("Use");
229                      output.endAnchor();
230                      output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
231                   }
232                }
233                else {
234                   output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
235                   output.print("Use");
236                   output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
237                }
238             }
239
240             if (optionLinkSource.getValue()) {
241                output.print(" ");
242
243
244                if ("source".equals(currentPage)) {
245                   output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
246                   output.print("Source");
247                   output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
248                }
249                else {
250
251                   if (null != currentClass) {
252
253                      output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
254                      String targetClassName = currentClass.name();
255                      String targetAnchor = "";
256                      if (null != currentClass.containingClass()) {
257                         targetClassName = getOuterClassDoc(currentClass).name();
258                         targetAnchor = "#line." + currentClass.position().line();
259                      }
260                      output.beginAnchor(targetClassName + "-source" + filenameExtension + targetAnchor);
261                      output.print("Source");
262                      output.endAnchor();
263                      output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
264                   }
265                   else {
266                      output.beginSpan(CssClass.NAVBAR_ITEM_DISABLED);
267                      output.print("Source");
268                      output.endSpan(CssClass.NAVBAR_ITEM_DISABLED);
269                   }
270                }
271             }
272          }
273
274
275          if (!optionNoTree.getValue()) {
276             output.print(" ");
277
278             if ("full-tree".equals(currentPage)
279                 || "package-tree".equals(currentPage)) {
280                output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
281                output.print("Tree");
282                output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
283             }
284             else {
285                output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
286                String treeHref;
287                if (isSinglePackage() && overviewLevel) {
288                   treeHref = getPackageURL(getSinglePackage()) + "tree" + filenameExtension;
289                }
290                else {
291                   treeHref = "tree" + filenameExtension;
292                }
293
294                output.beginAnchor(treeHref);
295                output.print("Tree");
296                output.endAnchor();
297                output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
298             }
299          }
300
301          output.print(" ");
302
303          String indexName;
304          if (optionSplitIndex.getValue()) {
305             indexName = "alphaindex-1";
306          }
307          else {
308             indexName = "alphaindex";
309          }
310
311          if ("index".equals(currentPage) || "split-index".equals(currentPage)) {
312             output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
313             output.print("Index");
314             output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
315          }
316          else {
317             output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
318             output.beginAnchor(output.getPathToRoot() + "/" + indexName + filenameExtension);
319             output.print("Index");
320             output.endAnchor();
321             output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
322          }
323
324          if (!optionNoDeprecatedList.getValue()) {
325             output.print(" ");
326
327             if ("deprecated".equals(currentPage)) {
328                output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
329                output.print("Deprecated");
330                output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
331             }
332             else {
333                output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
334                output.beginAnchor(output.getPathToRoot() + "/deprecated" + filenameExtension);
335                output.print("Deprecated");
336                output.endAnchor();
337                output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
338             }
339          }
340
341          if (outputHelpPage) {
342             if (!optionNoHelp.getValue()) {
343                output.print(" ");
344
345                if ("help".equals(currentPage)) {
346                   output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
347                   output.print("Help");
348                   output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
349                }
350                else {
351                   output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
352                   output.beginAnchor(output.getPathToRoot() + "/help" + filenameExtension);
353                   output.print("Help");
354                   output.endAnchor();
355                   output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
356                }
357             }
358          }
359
360          output.print(" ");
361
362          if ("about".equals(currentPage)) {
363             output.beginSpan(CssClass.NAVBAR_ITEM_ACTIVE);
364             output.print("About");
365             output.endSpan(CssClass.NAVBAR_ITEM_ACTIVE);
366          }
367          else {
368             output.beginSpan(CssClass.NAVBAR_ITEM_ENABLED);
369             output.beginAnchor(output.getPathToRoot() + "/about" + filenameExtension);
370             output.print("About");
371             output.endAnchor();
372             output.endSpan(CssClass.NAVBAR_ITEM_ENABLED);
373          }
374
375          output.endDiv(CssClass.NAVBAR_TOP);
376    }
377
378    private void printNavBarTopRow(HtmlPage output, String currentPage, ClassDoc currentClass)
379    {
380       output.beginRow();
381       output.beginCell(CssClass.NAVBAR_TOP);
382       printNavBar(output, currentPage, currentClass);
383       output.endCell();
384       if (null != optionHeader.getValue()) {
385          output.beginCell(CssClass.NAVBAR_TOP_HEADER);
386          output.print(replaceDocRoot(output, optionHeader.getValue()));
387          output.endCell();
388       }
389       output.endRow();
390    }
391
392    private void printNavBarTopNaviCell(HtmlPage output)
393    {
394       output.beginCell(CssClass.NAVBAR_TOP_NAVI);
395       output.beginAnchor(output.getPathToRoot() + "/index" + filenameExtension, "Show in a frameset", "_top");
396       output.print("Frames");
397       output.endAnchor();
398       output.print(" | ");
399
400       output.beginAnchor(output.getFile().getName(), "Show without frames", "_top");
401       output.print("No Frames");
402       output.endAnchor();
403       output.print(" ");
404
405       output.endCell();
406    }
407
408    private void printNavBarTop(HtmlPage output, String currentPage)
409    {
410       printNavBarTop(output, currentPage, null, null, null);
411    }
412
413    private void printNavBarTop(HtmlPage output, String currentPage,
414                                ClassDoc currentClass, Object prev, Object next)
415    {
416       if (!optionNoNavBar.getValue()) {
417          output.beginTable(CssClass.NAVBAR_TOP);
418          printNavBarTopRow(output, currentPage, currentClass);
419          output.beginRow();
420          if ("class".equals(currentPage)) {
421             output.beginCell(CssClass.NAVBAR_TOP_NAVI);
422             ClassDoc prevClass = (ClassDoc)prev;
423             ClassDoc nextClass = (ClassDoc)next;
424             if (null != prevClass) {
425                output.anchor(getClassDocURL(output, prevClass), "Prev Class");
426             }
427             else {
428                output.print("Prev Class");
429             }
430             output.print(" | ");
431             if (null != nextClass) {
432                output.anchor(getClassDocURL(output, nextClass), "Next Class");
433             }
434             else {
435                output.print("Next Class");
436             }
437             output.endCell();
438          }
439          else if ("split-index".equals(currentPage)) {
440             output.beginCell(CssClass.NAVBAR_TOP_NAVI);
441             Integer prevLetter = (Integer)prev;
442             Integer nextLetter = (Integer)next;
443             if (null != prevLetter) {
444                output.anchor("alphaindex-" + prevLetter + filenameExtension, "Prev Letter");
445             }
446             else {
447                output.print("Prev Letter");
448             }
449             output.print(" | ");
450             if (null != nextLetter) {
451                output.anchor("alphaindex-" + nextLetter + filenameExtension, "Next Letter");
452             }
453             else {
454                output.print("Next Letter");
455             }
456             output.endCell();
457          }
458          else {
459             output.beginCell(CssClass.NAVBAR_TOP_NAVI);
460             output.endCell();
461          }
462
463          printNavBarTopNaviCell(output);
464          output.endRow();
465
466          if ("class".equals(currentPage)) {
467             output.beginRow();
468
469             output.beginCell(CssClass.NAVBAR_TOP_NAVI);
470             output.print("Summary: ");
471
472             if (currentClass.innerClasses().length > 0) {
473                output.anchor("#summary-inner", "Nested");
474             }
475             else {
476                output.print("Nested");
477             }
478
479             output.print(" | ");
480
481             if (currentClass.fields().length > 0) {
482                output.anchor("#summary-fields", "Field");
483             }
484             else {
485                output.print("Field");
486             }
487
488             output.print(" | ");
489
490             if (currentClass.methods().length > 0) {
491                output.anchor("#summary-methods", "Method");
492             }
493             else {
494                output.print("Method");
495             }
496
497             output.print(" | ");
498
499             if (currentClass.constructors().length > 0) {
500                output.anchor("#summary-constructors", "Constr");
501             }
502             else {
503                output.print("Constr");
504             }
505
506             output.endCell();
507
508             output.beginCell(CssClass.NAVBAR_TOP_NAVI);
509             output.print("Detail: ");
510
511             if (currentClass.innerClasses().length > 0) {
512                output.anchor("#detail-inner", "Nested");
513             }
514             else {
515                output.print("Nested");
516             }
517
518             output.print(" | ");
519
520             if (currentClass.fields().length > 0) {
521                output.anchor("#detail-fields", "Field");
522             }
523             else {
524                output.print("Field");
525             }
526
527             output.print(" | ");
528
529             if (currentClass.methods().length > 0) {
530                output.anchor("#detail-methods", "Method");
531             }
532             else {
533                output.print("Method");
534             }
535
536             output.print(" | ");
537
538             if (currentClass.constructors().length > 0) {
539                output.anchor("#detail-constructors", "Constr");
540             }
541             else {
542                output.print("Constr");
543             }
544
545             output.endCell();
546             output.endRow();
547          }
548          output.endTable();
549       }
550    }
551
552    private void printNavBarTopPackage(HtmlPage output, String currentPage,
553                                       PackageDoc prevPackage, PackageDoc nextPackage)
554    {
555       if (!optionNoNavBar.getValue()) {
556          output.beginTable(CssClass.NAVBAR_TOP);
557          printNavBarTopRow(output, currentPage, null);
558
559          output.beginRow();
560          output.beginCell(CssClass.NAVBAR_TOP_NAVI);
561          if (null != prevPackage) {
562             output.anchor(output.getPathToRoot() + "/" + getPackageURL(prevPackage) + "package-summary" + filenameExtension, "Prev Package");
563          }
564          else {
565             output.print("Prev Package");
566          }
567          output.print(" | ");
568          if (null != nextPackage) {
569             output.anchor(output.getPathToRoot() + "/" + getPackageURL(nextPackage) + "package-summary" + filenameExtension, "Next Package");
570          }
571          else {
572             output.print("Next Package");
573          }
574          output.endCell();
575
576          printNavBarTopNaviCell(output);
577          output.endRow();
578
579          output.endTable();
580       }
581    }
582
583    private void printNavBarBottom(HtmlPage output, String currentPage)
584    {
585       printNavBarBottom(output, currentPage, null);
586    }
587
588    private void printNavBarBottom(HtmlPage output, String currentPage, ClassDoc currentClass)
589    {
590       if ("class".equals(currentPage)) {
591          String boilerplate = null;
592          Tag[] boilerplateTags = getOuterClassDoc(currentClass).tags("@boilerplate");
593          if (boilerplateTags.length > 0) {
594             boilerplate = boilerplateTags[0].text();
595          }
596          if (null != boilerplate) {
597             output.hr();
598             output.beginDiv(CssClass.CLASS_BOILERPLATE);
599             output.print(boilerplate);
600             output.endDiv(CssClass.CLASS_BOILERPLATE);
601             output.hr();
602          }
603       }
604
605       if (!optionNoNavBar.getValue()) {
606          output.beginDiv(CssClass.NAVBAR_BOTTOM_SPACER);
607          output.print(" ");
608          output.endDiv(CssClass.NAVBAR_BOTTOM_SPACER);
609          output.beginTable(CssClass.NAVBAR_BOTTOM);
610          output.beginRow();
611          output.beginCell();
612          printNavBar(output, currentPage, currentClass);
613          output.endCell();
614          if (null != optionFooter.getValue()) {
615             output.beginCell();
616             output.print(replaceDocRoot(output, optionFooter.getValue()));
617             output.endCell();
618          }
619          output.endRow();
620          output.endTable();
621       }
622
623       if (null != optionBottom.getValue()) {
624          output.hr();
625          output.print(replaceDocRoot(output, optionBottom.getValue()));
626       }
627    }
628
629    private void printPackagePageClasses(HtmlPage output, ClassDoc[] classDocs, String header)
630    {
631       if (classDocs.length > 0) {
632          output.beginDiv(CssClass.TABLE_CONTAINER);
633          output.beginTable(CssClass.PACKAGE_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
634          output.rowDiv(CssClass.TABLE_HEADER, header);
635
636          for (int i=0; i<classDocs.length; ++i) {
637             ClassDoc classDoc = classDocs[i];
638             if (classDoc.isIncluded()) {
639                output.beginRow();
640
641                output.beginCell(CssClass.PACKAGE_SUMMARY_LEFT);
642                printType(output, classDoc);
643                output.endCell();
644
645                output.beginCell(CssClass.PACKAGE_SUMMARY_RIGHT);
646                printTags(output, classDoc, classDoc.firstSentenceTags(), true);
647                output.endCell();
648                output.endRow();
649             }
650          }
651          output.endTable();
652          output.endDiv(CssClass.TABLE_CONTAINER);
653          output.print("\n");
654       }
655    }
656
657    private void printPackagesListFile()
658       throws IOException
659    {
660       PrintWriter out
661          = new PrintWriter(new OutputStreamWriter(new FileOutputStream(new File(getTargetDirectory(),
662                                                                                 "package-list")),
663                                                   "UTF-8"));
664
665       PackageDoc[] packages = getRootDoc().specifiedPackages();
666       for (int i=0; i<packages.length; ++i) {
667          String packageName = packages[i].name();
668          if (packageName.length() > 0) {
669             out.println(packageName);
670          }
671       }
672
673       out.close();
674    }
675
676    private void printPackagePage(File packageDir, String pathToRoot,
677                                  PackageDoc packageDoc,
678                                  PackageDoc prevPackageDoc,
679                                  PackageDoc nextPackageDoc)
680       throws IOException
681    {
682       HtmlPage output = newHtmlPage(new File(packageDir, "package-summary" + filenameExtension),
683                                     pathToRoot);
684
685       Set<String> keywords = new LinkedHashSet<String>();
686       keywords.add(packageDoc.name() + " packages");
687
688       output.beginPage(getPageTitle(packageDoc.name()), getOutputCharset(),
689                        keywords, getStylesheets());
690       output.beginBody(CssClass.BODY_CONTENT_PACKAGE);
691       printNavBarTopPackage(output, "package", prevPackageDoc, nextPackageDoc);
692
693       output.beginDiv(CssClass.PACKAGE_TITLE);
694       output.print("Package ");
695       if (packageDoc.name().length() > 0) {
696          output.print(packageDoc.name());
697       }
698       else {
699          output.print("&lt;Unnamed&gt;");
700       }
701       output.endDiv(CssClass.PACKAGE_TITLE);
702
703       output.beginDiv(CssClass.PACKAGE_DESCRIPTION_TOP);
704       printTags(output, packageDoc, packageDoc.firstSentenceTags(), true);
705       output.endDiv(CssClass.PACKAGE_DESCRIPTION_TOP);
706
707       printPackagePageClasses(output, packageDoc.interfaces(),
708                               "Interface Summary");
709       printPackagePageClasses(output, packageDoc.ordinaryClasses(),
710                               "Class Summary");
711       printPackagePageClasses(output, packageDoc.exceptions(),
712                               "Exception Summary");
713       printPackagePageClasses(output, packageDoc.errors(),
714                               "Error Summary");
715
716       output.anchorName("description");
717       output.beginDiv(CssClass.PACKAGE_DESCRIPTION_FULL);
718       printTags(output, packageDoc, packageDoc.inlineTags(), false);
719       output.endDiv(CssClass.PACKAGE_DESCRIPTION_FULL);
720
721       printNavBarBottom(output, "package");
722       output.endBody();
723       output.endPage();
724       output.close();
725    }
726
727    static class TreeNode
728       implements Comparable<TreeNode>
729    {
730       ClassDoc classDoc;
731       SortedSet<TreeNode> children = new TreeSet<TreeNode>();
732
733       TreeNode(ClassDoc classDoc) {
734          TreeNode.this.classDoc = classDoc;
735       }
736
737       public boolean equals(Object other)
738       {
739          return classDoc.equals(((TreeNode)other).classDoc);
740       }
741
742       public int compareTo(TreeNode other)
743       {
744          return classDoc.compareTo(other.classDoc);
745       }
746
747       public int hashCode()
748       {
749          return classDoc.hashCode();
750       }
751    }
752
753    private TreeNode addClassTreeNode(Map<String,TreeNode> treeMap, ClassDoc classDoc)
754    {
755       TreeNode node = treeMap.get(classDoc.qualifiedName());
756       if (null == node) {
757          node = new TreeNode(classDoc);
758          treeMap.put(classDoc.qualifiedName(), node);
759
760          ClassDoc superClassDoc = (ClassDoc)classDoc.superclass();
761          if (null != superClassDoc) {
762             TreeNode parentNode = addClassTreeNode(treeMap, superClassDoc);
763             parentNode.children.add(node);
764          }
765       }
766       return node;
767    }
768
769    private TreeNode addInterfaceTreeNode(Map<String,TreeNode> treeMap, ClassDoc classDoc)
770    {
771       TreeNode node = treeMap.get(classDoc.qualifiedName());
772       if (null == node) {
773          node = new TreeNode(classDoc);
774          treeMap.put(classDoc.qualifiedName(), node);
775
776          ClassDoc[] superInterfaces = classDoc.interfaces();
777          if (null != superInterfaces && superInterfaces.length > 0) {
778             for (int i=0; i<superInterfaces.length; ++i) {
779                TreeNode parentNode = addInterfaceTreeNode(treeMap, superInterfaces[i]);
780                parentNode.children.add(node);
781             }
782          }
783          else {
784             TreeNode rootNode = treeMap.get("<root>");
785             if (null == rootNode) {
786                rootNode = new TreeNode(null);
787                treeMap.put("<root>", rootNode);
788             }
789             rootNode.children.add(node);
790          }
791       }
792       return node;
793    }
794
795    private void printPackageTreeRec(HtmlPage output, TreeNode node, TreeNode parentNode)
796    {
797       output.beginElement("li", "class", "node");
798       output.beginElement("div");
799       if (node.classDoc.isIncluded()) {
800          String packageName = node.classDoc.containingPackage().name();
801          if (packageName.length() > 0) {
802             output.print(packageName);
803             output.print(".");
804          }
805          output.beginSpan(CssClass.TREE_LINK);
806          printType(output, node.classDoc);
807          output.endSpan(CssClass.TREE_LINK);
808       }
809       else {
810          output.print(possiblyQualifiedName(node.classDoc));
811       }
812       ClassDoc[] interfaces = node.classDoc.interfaces();
813       ClassDoc parentClassDoc = null;
814       if (null != parentNode) {
815          parentClassDoc = parentNode.classDoc;
816       }
817       if (interfaces.length > 0
818           && !(interfaces.length == 1 && interfaces[0].equals(parentClassDoc))) {
819          if (node.classDoc.isInterface()) {
820             output.print(" (also implements ");
821          }
822          else {
823             output.print(" (implements ");
824          }
825
826          boolean firstItem = true;
827          for (int i=0; i<interfaces.length; ++i) {
828             ClassDoc implemented = interfaces[i];
829             if (!implemented.equals(parentClassDoc)) {
830                if (!firstItem) {
831                   output.print(", ");
832                }
833                firstItem = false;
834                if (implemented.isIncluded()) {
835                   output.print(implemented.containingPackage().name());
836                   output.print(".");
837                   printType(output, implemented);
838                }
839                else {
840                   output.print(possiblyQualifiedName(implemented));
841                }
842             }
843          }
844          output.print(")");
845       }
846
847       output.endElement("div");
848       output.endElement("li");
849       if (!node.children.isEmpty()) {
850          output.beginElement("li", "class", "level");
851          output.beginElement("ul");
852          Iterator<TreeNode> it = node.children.iterator();
853          while (it.hasNext()) {
854             printPackageTreeRec(output, it.next(), node);
855          }
856          output.endElement("ul");
857          output.endElement("li");
858       }
859    }
860
861    private void printClassTree(HtmlPage output, ClassDoc[] classDocs)
862    {
863      Map<String,TreeNode> classTreeMap = new HashMap<String,TreeNode>();
864
865       for (int i=0; i<classDocs.length; ++i) {
866          ClassDoc classDoc = classDocs[i];
867          if (!classDoc.isInterface()) {
868             addClassTreeNode(classTreeMap, classDoc);
869          }
870       }
871
872       TreeNode root = classTreeMap.get("java.lang.Object");
873       if (null != root) {
874          output.div(CssClass.PACKAGE_TREE_SECTION_TITLE, "Class Hierarchy");
875          output.beginDiv(CssClass.PACKAGE_TREE);
876          printPackageTreeRec(output, root, null);
877          output.endDiv(CssClass.PACKAGE_TREE);
878       }
879    }
880
881    private void printInterfaceTree(HtmlPage output, ClassDoc[] classDocs)
882    {
883       Map<String,TreeNode> interfaceTreeMap = new HashMap<String,TreeNode>();
884
885       for (int i=0; i<classDocs.length; ++i) {
886          ClassDoc classDoc = classDocs[i];
887          if (classDoc.isInterface()) {
888             addInterfaceTreeNode(interfaceTreeMap, classDoc);
889          }
890       }
891
892       TreeNode interfaceRoot = interfaceTreeMap.get("<root>");
893       if (null != interfaceRoot) {
894          Iterator<TreeNode> it = interfaceRoot.children.iterator();
895          if (it.hasNext()) {
896             output.div(CssClass.PACKAGE_TREE_SECTION_TITLE, "Interface Hierarchy");
897             output.beginDiv(CssClass.PACKAGE_TREE);
898             while (it.hasNext()) {
899                TreeNode node = it.next();
900                printPackageTreeRec(output, node, null);
901             }
902             output.endDiv(CssClass.PACKAGE_TREE);
903          }
904       }
905
906    }
907
908    private void printPackageTreePage(File packageDir, String pathToRoot, PackageDoc packageDoc)
909       throws IOException
910    {
911       HtmlPage output = newHtmlPage(new File(packageDir,
912                                              "tree" + filenameExtension),
913                                     pathToRoot);
914       output.beginPage(getPageTitle(packageDoc.name() + " Hierarchy"),
915                        getOutputCharset(),
916                        getStylesheets());
917       output.beginBody(CssClass.BODY_CONTENT_PACKAGE_TREE);
918       printNavBarTop(output, "package-tree");
919
920       output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy for Package " + packageDoc.name());
921
922       ClassDoc[] classDocs = packageDoc.allClasses();
923       printClassTree(output, classDocs);
924       printInterfaceTree(output, classDocs);
925
926       printNavBarBottom(output, "package-tree");
927       output.endBody();
928       output.endPage();
929       output.close();
930    }
931
932    private void printFullTreePage()
933       throws IOException
934    {
935       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
936                                              "tree" + filenameExtension),
937                                     ".");
938       output.beginPage(getPageTitle("Hierarchy"),
939                        getOutputCharset(),
940                        getStylesheets());
941       output.beginBody(CssClass.BODY_CONTENT_FULL_TREE);
942       printNavBarTop(output, "full-tree");
943
944       output.div(CssClass.PACKAGE_TREE_TITLE, "Hierarchy for All Packages");
945
946       output.beginDiv(CssClass.FULL_TREE_PACKAGELIST);
947       output.div(CssClass.FULL_TREE_PACKAGELIST_HEADER, "Package Hierarchies:");
948       output.beginDiv(CssClass.FULL_TREE_PACKAGELIST_ITEM);
949       Set<PackageDoc> allPackages = getAllPackages();
950       Iterator<PackageDoc> it = allPackages.iterator();
951       while (it.hasNext()) {
952          PackageDoc packageDoc = it.next();
953          output.beginAnchor(getPackageURL(packageDoc) + "tree" + filenameExtension);
954          output.print(packageDoc.name());
955          output.endAnchor();
956          if (it.hasNext()) {
957             output.print(", ");
958          }
959       }
960       output.endDiv(CssClass.FULL_TREE_PACKAGELIST_ITEM);
961       output.endDiv(CssClass.FULL_TREE_PACKAGELIST);
962
963       ClassDoc[] classDocs = getRootDoc().classes();
964       printClassTree(output, classDocs);
965       printInterfaceTree(output, classDocs);
966
967       printNavBarBottom(output, "full-tree");
968       output.endBody();
969       output.endPage();
970       output.close();
971    }
972
973    private void printIndexEntry(HtmlPage output, Doc entry)
974    {
975       output.beginDiv(CssClass.INDEX_ENTRY);
976       output.beginDiv(CssClass.INDEX_ENTRY_KEY);
977       if (entry instanceof PackageDoc) {
978          output.beginAnchor(getPackageURL((PackageDoc)entry) + "package-summary" + filenameExtension);
979          output.print(entry.name());
980          output.endAnchor();
981          output.print(" - package");
982       }
983       else if (entry instanceof ClassDoc) {
984          ClassDoc classDoc = (ClassDoc)entry;
985          output.beginAnchor(getClassURL(classDoc));
986          output.print(entry.name() + getTypeParameters(classDoc));
987          output.endAnchor();
988          output.print(" - ");
989          if (entry.isInterface()) {
990             output.print("interface ");
991          }
992          else if (entry.isException()) {
993             output.print("exception ");
994          }
995          else if (entry.isError()) {
996             output.print("error ");
997          }
998          else {
999             output.print("class ");
1000          }
1001          String packageName = classDoc.containingPackage().name();
1002          if (packageName.length() > 0) {
1003             output.print(packageName);
1004             output.print(".");
1005          }
1006          printType(output, classDoc);
1007       }
1008       else {
1009          ProgramElementDoc memberDoc = (ProgramElementDoc)entry;
1010          output.beginAnchor(getMemberDocURL(output, memberDoc));
1011          output.print(entry.name());
1012          if (memberDoc instanceof ExecutableMemberDoc) {
1013             output.print(((ExecutableMemberDoc)memberDoc).signature());
1014          }
1015          output.endAnchor();
1016          output.print(" - ");
1017
1018          if (memberDoc.isStatic()) {
1019             output.print("static ");
1020          }
1021
1022          if (entry.isConstructor()) {
1023             output.print("constructor for class ");
1024          }
1025          else if (entry.isMethod()) {
1026             output.print("method in class ");
1027          }
1028          else if (entry.isField()) {
1029             output.print("field in class ");
1030          }
1031          ClassDoc containingClass = memberDoc.containingClass();
1032          String packageName = containingClass.containingPackage().name();
1033          if (packageName.length() > 0) {
1034             output.print(packageName);
1035             output.print(".");
1036          }
1037          printType(output, containingClass);
1038       }
1039       output.endDiv(CssClass.INDEX_ENTRY_KEY);
1040       output.beginDiv(CssClass.INDEX_ENTRY_DESCRIPTION);
1041       printTags(output, entry, entry.firstSentenceTags(), true);
1042       output.endDiv(CssClass.INDEX_ENTRY_DESCRIPTION);
1043       output.endDiv(CssClass.INDEX_ENTRY);
1044    }
1045
1046    private void printFrameSetPage()
1047       throws IOException
1048    {
1049       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1050                                              "index" + filenameExtension),
1051                                     ".",
1052                                     HtmlPage.DOCTYPE_FRAMESET);
1053
1054       String title = getWindowTitle();
1055       output.beginPage(title, getOutputCharset(), getStylesheets());
1056       output.beginElement("frameset", "cols", "20%,80%");
1057
1058       String contentURL;
1059       if (isSinglePackage()) {
1060          output.atomicElement("frame",
1061                               new String[] { "src", "name" },
1062                               new String[] { getPackageURL(getSinglePackage()) + "classes" + filenameExtension, "classes" });
1063          contentURL = getPackageURL(getSinglePackage()) + "package-summary.html";
1064       }
1065       else {
1066          output.beginElement("frameset", "rows", "25%,75%");
1067          output.atomicElement("frame",
1068                               new String[] { "src", "name" },
1069                               new String[] { "all-packages" + filenameExtension, "packages" });
1070          output.atomicElement("frame",
1071                               new String[] { "src", "name" },
1072                               new String[] { "all-classes" + filenameExtension, "classes" });
1073          output.endElement("frameset");
1074          contentURL = "overview-summary" + filenameExtension;
1075       }
1076       output.atomicElement("frame",
1077                            new String[] { "src", "name" },
1078                            new String[] { contentURL, "content" });
1079       output.endElement("frameset");
1080       output.endPage();
1081       output.close();
1082    }
1083
1084    private void printPackagesMenuPage()
1085       throws IOException
1086    {
1087       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1088                                              "all-packages" + filenameExtension),
1089                                     ".");
1090       output.beginPage(getPageTitle("Package Menu"), getOutputCharset(), getStylesheets());
1091       output.beginBody(CssClass.BODY_MENU_PACKAGES, false);
1092
1093       output.beginSpan(CssClass.PACKAGE_MENU_ENTRY);
1094       output.beginAnchor("all-classes" + filenameExtension,
1095                          null,
1096                          "classes");
1097       output.print("All Classes");
1098       output.endAnchor();
1099       output.endSpan(CssClass.PACKAGE_MENU_ENTRY);
1100
1101       output.div(CssClass.PACKAGE_MENU_TITLE, "Packages");
1102
1103       output.beginDiv(CssClass.PACKAGE_MENU_LIST);
1104
1105       Set<PackageDoc> packageDocs = getAllPackages();
1106       Iterator<PackageDoc> it = packageDocs.iterator();
1107       while (it.hasNext()) {
1108          PackageDoc packageDoc = it.next();
1109          output.beginSpan(CssClass.PACKAGE_MENU_ENTRY);
1110          output.beginAnchor(getPackageURL(packageDoc) + "classes" + filenameExtension,
1111                             null,
1112                             "classes");
1113          if (packageDoc.name().length() > 0) {
1114             output.print(packageDoc.name());
1115          }
1116          else {
1117             output.print("&lt;unnamed package&gt;");
1118          }
1119          output.endAnchor();
1120          output.endSpan(CssClass.PACKAGE_MENU_ENTRY);
1121          output.br();
1122       }
1123
1124       output.endDiv(CssClass.PACKAGE_MENU_LIST);
1125       output.endBody();
1126       output.endPage();
1127       output.close();
1128    }
1129
1130    private void printClassMenuEntry(HtmlPage output, ClassDoc classDoc)
1131    {
1132       CssClass entryClass;
1133       if (classDoc.isInterface()) {
1134          entryClass = CssClass.CLASS_MENU_ENTRY_INTERFACE;
1135       }
1136       else {
1137          entryClass = CssClass.CLASS_MENU_ENTRY_CLASS;
1138       }
1139       output.beginSpan(entryClass);
1140       output.beginAnchor(getClassDocURL(output, classDoc),
1141                          classDoc.qualifiedTypeName(),
1142                          "content");
1143       output.print(classDoc.name());
1144       output.endAnchor();
1145       output.endSpan(entryClass);
1146       output.br();
1147    }
1148
1149    private void printClassMenuSection(HtmlPage output, Collection classDocs, String header)
1150    {
1151       if (!classDocs.isEmpty()) {
1152          output.div(CssClass.CLASS_MENU_SUBTITLE, header);
1153          Iterator<ClassDoc> it = classDocs.iterator();
1154          while (it.hasNext()) {
1155             ClassDoc classDoc = it.next();
1156             printClassMenuEntry(output, classDoc);
1157          }
1158       }
1159    }
1160
1161    private void printClassMenuList(HtmlPage output, ClassDoc[] classDocs, boolean categorized)
1162    {
1163       output.beginDiv(CssClass.CLASS_MENU_LIST);
1164
1165       if (categorized) {
1166          Set<ClassDoc> classes = new TreeSet<ClassDoc>();
1167          Set<ClassDoc> interfaces = new TreeSet<ClassDoc>();
1168          Set<ClassDoc> exceptions = new TreeSet<ClassDoc>();
1169          Set<ClassDoc> errors = new TreeSet<ClassDoc>();
1170
1171          for (int i=0; i<classDocs.length; ++i) {
1172             ClassDoc classDoc = classDocs[i];
1173             if (classDoc.isInterface()) {
1174                interfaces.add(classDoc);
1175             }
1176             else if (classDoc.isException()) {
1177                exceptions.add(classDoc);
1178             }
1179             else if (classDoc.isError()) {
1180                errors.add(classDoc);
1181             }
1182             else {
1183                classes.add(classDoc);
1184             }
1185          }
1186          printClassMenuSection(output, interfaces, "Interfaces");
1187          printClassMenuSection(output, classes, "Classes");
1188          printClassMenuSection(output, exceptions, "Exceptions");
1189          printClassMenuSection(output, errors, "Errors");
1190       }
1191       else {
1192          for (int i=0; i<classDocs.length; ++i) {
1193             ClassDoc classDoc = classDocs[i];
1194             if (classDoc.isIncluded()) {
1195                printClassMenuEntry(output, classDoc);
1196             }
1197          }
1198       }
1199
1200       output.endDiv(CssClass.CLASS_MENU_LIST);
1201    }
1202
1203    private void printAllClassesMenuPage()
1204       throws IOException
1205    {
1206       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1207                                              "all-classes" + filenameExtension),
1208                                     ".");
1209       output.beginPage(getPageTitle("Class Menu"), getOutputCharset(), getStylesheets());
1210       output.beginBody(CssClass.BODY_MENU_CLASSES, false);
1211
1212       output.div(CssClass.CLASS_MENU_TITLE, "All Classes");
1213
1214       printClassMenuList(output, getRootDoc().classes(), false);
1215
1216       output.endBody();
1217       output.endPage();
1218       output.close();
1219    }
1220
1221    private void printPackageClassesMenuPage(File packageDir, String pathToRoot, PackageDoc packageDoc)
1222       throws IOException
1223    {
1224       HtmlPage output = newHtmlPage(new File(packageDir,
1225                                              "classes" + filenameExtension),
1226                                     pathToRoot);
1227
1228       output.beginPage(getPageTitle(packageDoc.name() + " Class Menu"),
1229                        getOutputCharset(), getStylesheets());
1230       output.beginBody(CssClass.BODY_MENU_CLASSES, false);
1231
1232       output.beginDiv(CssClass.CLASS_MENU_TITLE);
1233       output.beginAnchor("package-summary" + filenameExtension, "", "content");
1234       if (packageDoc.name().length() > 0) {
1235          output.print(packageDoc.name());
1236       }
1237       else {
1238          output.print("&lt;Unnamed&gt;");
1239       }
1240       output.endAnchor();
1241       output.endDiv(CssClass.CLASS_MENU_TITLE);
1242
1243       printClassMenuList(output, packageDoc.allClasses(), true);
1244
1245       output.endBody();
1246       output.endPage();
1247       output.close();
1248    }
1249
1250    private void printSplitIndex()
1251       throws IOException
1252    {
1253       Map<Character,List<Doc>> categorizedIndex = getCategorizedIndex();
1254       Iterator<Character> it = categorizedIndex.keySet().iterator();
1255       int n = 1;
1256       int count = categorizedIndex.size();
1257       while (it.hasNext()) {
1258          Character c = it.next();
1259          List<Doc> classList = categorizedIndex.get(c);
1260          printIndexPage(n++, count, c, classList);
1261       }
1262    }
1263
1264    private void printIndexPage()
1265       throws IOException
1266    {
1267       printIndexPage(0, 0, null, null);
1268    }
1269
1270    private void printIndexPage(int index, int maxIndex, Character letter, List<Doc> classList)
1271       throws IOException
1272    {
1273       String pageName = "alphaindex";
1274       if (null != letter) {
1275          pageName += "-" + index;
1276       }
1277       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1278                                              pageName + filenameExtension),
1279                                     ".");
1280       output.beginPage(getPageTitle("Alphabetical Index"),
1281                        getOutputCharset(),
1282                        getStylesheets());
1283       output.beginBody(CssClass.BODY_CONTENT_INDEX);
1284       if (null == letter) {
1285          printNavBarTop(output, "index");
1286       }
1287       else {
1288          printNavBarTop(output, "split-index", null,
1289                         (index > 1) ? new Integer(index - 1) : null,
1290                         (index < maxIndex) ? new Integer(index + 1) : null);
1291       }
1292
1293       {
1294          String title;
1295          if (null == letter) {
1296             title = "Alphabetical Index";
1297          }
1298          else {
1299             title = "Alphabetical Index: " + letter;
1300          }
1301          output.div(CssClass.INDEX_TITLE, title);
1302
1303          if (null != letter || getCategorizedIndex().keySet().size() > 1) {
1304             output.beginDiv(CssClass.INDEX_LETTERS);
1305
1306             Iterator it = getCategorizedIndex().keySet().iterator();
1307             int n = 1;
1308             while (it.hasNext()) {
1309                Character c = (Character)it.next();
1310                output.beginSpan(CssClass.INDEX_LETTER);
1311                if (letter != null) {
1312                   output.beginAnchor("alphaindex-" + n + filenameExtension);
1313                }
1314                else {
1315                   output.beginAnchor("#" + c);
1316                }
1317                output.print(c.toString());
1318                output.endAnchor();
1319                output.endSpan(CssClass.INDEX_LETTER);
1320                output.beginSpan(CssClass.INDEX_LETTER_SPACER);
1321                output.print(" ");
1322                output.endSpan(CssClass.INDEX_LETTER_SPACER);
1323                ++n;
1324             }
1325          }
1326
1327          output.endDiv(CssClass.INDEX_LETTERS);
1328       }
1329
1330       if (null != letter) {
1331          printIndexCategory(output, letter, classList);
1332       }
1333       else {
1334          Map<Character,List<Doc>> categorizedIndex = getCategorizedIndex();
1335          Iterator<Character> categoryIt = categorizedIndex.keySet().iterator();
1336
1337          while (categoryIt.hasNext()) {
1338             letter = categoryIt.next();
1339             classList = categorizedIndex.get(letter);
1340             output.anchorName(letter.toString());
1341             printIndexCategory(output, letter, classList);
1342          }
1343       }
1344
1345       printNavBarBottom(output, "index");
1346       output.endBody();
1347       output.endPage();
1348       output.close();
1349    }
1350
1351    private void printIndexCategory(HtmlPage output, Character letter, List classList)
1352    {
1353       Iterator it = classList.iterator();
1354
1355       output.div(CssClass.INDEX_CATEGORY_HEADER, letter.toString());
1356       output.beginDiv(CssClass.INDEX_CATEGORY);
1357       while (it.hasNext()) {
1358          Doc entry = (Doc)it.next();
1359          printIndexEntry(output, entry);
1360       }
1361       output.endDiv(CssClass.INDEX_CATEGORY);
1362    }
1363
1364    private void printDeprecationSummary(HtmlPage output, List docs, String header)
1365    {
1366       if (!docs.isEmpty()) {
1367          output.beginDiv(CssClass.TABLE_CONTAINER);
1368          output.beginTable(CssClass.DEPRECATION_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
1369          output.rowDiv(CssClass.TABLE_HEADER, header);
1370
1371          Iterator it = docs.iterator();
1372          while (it.hasNext()) {
1373             Doc doc = (Doc)it.next();
1374             output.beginRow();
1375
1376             output.beginCell(CssClass.DEPRECATION_SUMMARY_LEFT);
1377             if (doc instanceof Type) {
1378                printType(output, (Type)doc);
1379             }
1380             else {
1381                ProgramElementDoc memberDoc = (ProgramElementDoc)doc;
1382                output.beginAnchor(getMemberDocURL(output, memberDoc));
1383                output.print(memberDoc.containingClass().qualifiedName());
1384                output.print(".");
1385                output.print(memberDoc.name());
1386                if (memberDoc instanceof ExecutableMemberDoc) {
1387                   output.print(((ExecutableMemberDoc)memberDoc).flatSignature());
1388                }
1389                output.endAnchor();
1390             }
1391             output.beginDiv(CssClass.DEPRECATION_SUMMARY_DESCRIPTION);
1392             printTags(output, doc, doc.tags("deprecated")[0].firstSentenceTags(), true);
1393             output.endDiv(CssClass.DEPRECATION_SUMMARY_DESCRIPTION);
1394
1395             output.endCell();
1396
1397             output.endRow();
1398          }
1399          output.endTable();
1400          output.endDiv(CssClass.TABLE_CONTAINER);
1401          output.print("\n");
1402       }
1403    }
1404
1405
1406    private void printSerializationPage()
1407       throws IOException
1408    {
1409       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1410                                              "serialized-form" + filenameExtension),
1411                                     ".");
1412       output.beginPage(getPageTitle("Serialized Form"),
1413                        getOutputCharset(),
1414                        getStylesheets());
1415       output.beginBody(CssClass.BODY_CONTENT_DEPRECATED);
1416       printNavBarTop(output, "serialized");
1417
1418       output.div(CssClass.SERIALIZED_TITLE, "Serialized Form");
1419
1420       Iterator<PackageDoc> it = getAllPackages().iterator();
1421
1422       while (it.hasNext()) {
1423
1424          PackageDoc packageDoc = it.next();
1425
1426          List<ClassDoc> serializableClasses = new LinkedList<ClassDoc>();
1427          ClassDoc[] classes = packageDoc.allClasses();
1428          for (int i=0; i<classes.length; ++i) {
1429             ClassDoc classDoc = classes[i];
1430             if (classDoc.isSerializable() || classDoc.isExternalizable()) {
1431                serializableClasses.add(classDoc);
1432             }
1433          }
1434
1435          if (!serializableClasses.isEmpty()) {
1436             output.div(CssClass.SERIALIZED_PACKAGE_HEADER, "Package " + packageDoc.name());
1437
1438             Iterator<ClassDoc> cit = serializableClasses.iterator();
1439             while (cit.hasNext()) {
1440                ClassDoc classDoc = cit.next();
1441
1442                output.anchorName(classDoc.qualifiedTypeName());
1443
1444                output.beginDiv(CssClass.SERIALIZED_CLASS_HEADER);
1445                output.print("Class ");
1446                printType(output, classDoc, true);
1447                output.print(" extends ");
1448                printType(output, classDoc.superclass());
1449                output.print(" implements Serializable");
1450                output.endDiv(CssClass.SERIALIZED_CLASS_HEADER);
1451
1452                FieldDoc serialVersionUidField = findField(classDoc, "serialVersionUID");
1453                if (null != serialVersionUidField
1454                    && serialVersionUidField.isFinal()
1455                    && serialVersionUidField.isStatic()
1456                    && serialVersionUidField.type().typeName().equals("long")) {
1457
1458                   String fieldValue = serialVersionUidField.constantValueExpression();
1459                   if (null != fieldValue) {
1460                      output.beginDiv(CssClass.SERIALIZED_SVUID_OUTER);
1461                      output.span(CssClass.SERIALIZED_SVUID_HEADER, "serialVersionUID: ");
1462                      output.span(CssClass.SERIALIZED_SVUID_VALUE, fieldValue);
1463                      output.endDiv(CssClass.SERIALIZED_SVUID_OUTER);
1464                   }
1465                }
1466                printMemberDetails(output,
1467                                   classDoc.serializationMethods(),
1468                                   "Serialization Methods",
1469                                   true, null);
1470                printMemberDetails(output,
1471                                   classDoc.serializableFields(),
1472                                   "Serialized Fields",
1473                                   true, null);
1474             }
1475          }
1476       }
1477
1478       printNavBarBottom(output, "serialized");
1479
1480       output.endBody();
1481       output.endPage();
1482       output.close();
1483    }
1484
1485
1486    private void printDeprecationPage()
1487       throws IOException
1488    {
1489       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1490                                              "deprecated" + filenameExtension),
1491                                     ".");
1492       output.beginPage(getPageTitle("Deprecated API"),
1493                        getOutputCharset(),
1494                        getStylesheets());
1495       output.beginBody(CssClass.BODY_CONTENT_DEPRECATED);
1496       printNavBarTop(output, "deprecated");
1497
1498       output.div(CssClass.DEPRECATION_TITLE, "Deprecated API");
1499
1500       List<ClassDoc> deprecatedInterfaces = new LinkedList<ClassDoc>();
1501       List<ClassDoc> deprecatedExceptions = new LinkedList<ClassDoc>();
1502       List<ClassDoc> deprecatedErrors = new LinkedList<ClassDoc>();
1503       List<ClassDoc> deprecatedClasses = new LinkedList<ClassDoc>();
1504       List<FieldDoc> deprecatedFields = new LinkedList<FieldDoc>();
1505       List<MethodDoc> deprecatedMethods = new LinkedList<MethodDoc>();
1506       List<ConstructorDoc> deprecatedConstructors = new LinkedList<ConstructorDoc>();
1507
1508       ClassDoc[] classDocs = getRootDoc().classes();
1509       for (int i=0; i<classDocs.length; ++i) {
1510          ClassDoc classDoc = classDocs[i];
1511          {
1512             Tag[] deprecatedTags = classDoc.tags("deprecated");
1513             if (null != deprecatedTags && deprecatedTags.length > 0) {
1514                if (classDoc.isInterface()) {
1515                   deprecatedInterfaces.add(classDoc);
1516                }
1517                else if (classDoc.isException()) {
1518                   deprecatedExceptions.add(classDoc);
1519                }
1520                else if (classDoc.isError()) {
1521                   deprecatedErrors.add(classDoc);
1522                }
1523                else {
1524                   deprecatedClasses.add(classDoc);
1525                }
1526             }
1527          }
1528          ConstructorDoc[] constructors = classDoc.constructors();
1529          for (int j=0; j<constructors.length; ++j) {
1530             Tag[] deprecatedTags = constructors[j].tags("deprecated");
1531             if (null != deprecatedTags && deprecatedTags.length > 0) {
1532                deprecatedConstructors.add(constructors[j]);
1533             }
1534          }
1535          MethodDoc[] methods = classDoc.methods();
1536          for (int j=0; j<methods.length; ++j) {
1537             Tag[] deprecatedTags = methods[j].tags("deprecated");
1538             if (null != deprecatedTags && deprecatedTags.length > 0) {
1539                deprecatedMethods.add(methods[j]);
1540             }
1541          }
1542          FieldDoc[] fields = classDoc.fields();
1543          for (int j=0; j<fields.length; ++j) {
1544             Tag[] deprecatedTags = fields[j].tags("deprecated");
1545             if (null != deprecatedTags && deprecatedTags.length > 0) {
1546                deprecatedFields.add(fields[j]);
1547             }
1548          }
1549       }
1550
1551       if (!deprecatedInterfaces.isEmpty()
1552           || !deprecatedClasses.isEmpty()
1553           || !deprecatedExceptions.isEmpty()
1554           || !deprecatedErrors.isEmpty()
1555           || !deprecatedFields.isEmpty()
1556           || !deprecatedMethods.isEmpty()
1557           || !deprecatedConstructors.isEmpty()) {
1558
1559          output.beginDiv(CssClass.DEPRECATION_TOC);
1560          output.div(CssClass.DEPRECATION_TOC_HEADER, "Contents");
1561          output.beginDiv(CssClass.DEPRECATION_TOC_LIST);
1562          if (!deprecatedInterfaces.isEmpty()) {
1563             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1564             output.anchor("#interfaces", "Deprecated Interfaces");
1565             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1566          }
1567          if (!deprecatedClasses.isEmpty()) {
1568             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1569             output.anchor("#classes", "Deprecated Classes");
1570             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1571          }
1572          if (!deprecatedExceptions.isEmpty()) {
1573             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1574             output.anchor("#exceptions", "Deprecated Exceptions");
1575             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1576          }
1577          if (!deprecatedErrors.isEmpty()) {
1578             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1579             output.anchor("#errors", "Deprecated Errors");
1580             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1581          }
1582          if (!deprecatedFields.isEmpty()) {
1583             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1584             output.anchor("#fields", "Deprecated Fields");
1585             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1586          }
1587          if (!deprecatedMethods.isEmpty()) {
1588             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1589             output.anchor("#methods", "Deprecated Methods");
1590             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1591          }
1592          if (!deprecatedConstructors.isEmpty()) {
1593             output.beginDiv(CssClass.DEPRECATION_TOC_ENTRY);
1594             output.anchor("#constructors", "Deprecated Constructors");
1595             output.endDiv(CssClass.DEPRECATION_TOC_ENTRY);
1596          }
1597          output.endDiv(CssClass.DEPRECATION_TOC_LIST);
1598          output.endDiv(CssClass.DEPRECATION_TOC);
1599          output.beginDiv(CssClass.DEPRECATION_LIST);
1600
1601          output.anchorName("interfaces");
1602          printDeprecationSummary(output, deprecatedInterfaces, "Deprecated Interfaces");
1603
1604          output.anchorName("classes");
1605          printDeprecationSummary(output, deprecatedClasses, "Deprecated Classes");
1606
1607          output.anchorName("exceptions");
1608          printDeprecationSummary(output, deprecatedExceptions, "Deprecated Exceptions");
1609
1610          output.anchorName("errors");
1611          printDeprecationSummary(output, deprecatedErrors, "Deprecated Errors");
1612
1613          output.anchorName("fields");
1614          printDeprecationSummary(output, deprecatedFields, "Deprecated Fields");
1615
1616          output.anchorName("methods");
1617          printDeprecationSummary(output, deprecatedMethods, "Deprecated Methods");
1618
1619          output.anchorName("constructors");
1620          printDeprecationSummary(output, deprecatedConstructors, "Deprecated Constructors");
1621
1622          output.endDiv(CssClass.DEPRECATION_LIST);
1623       }
1624       else {
1625          output.beginDiv(CssClass.DEPRECATION_EMPTY);
1626          output.print("No deprecated classes or class members in this API.");
1627          output.endDiv(CssClass.DEPRECATION_EMPTY);
1628
1629       }
1630
1631       printNavBarBottom(output, "deprecated");
1632       output.endBody();
1633       output.endPage();
1634       output.close();
1635    }
1636
1637    private void printAboutPage()
1638       throws IOException
1639    {
1640       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1641                                              "about" + filenameExtension),
1642                                     ".");
1643       output.beginPage(getPageTitle("About"),
1644                        getOutputCharset(),
1645                        getStylesheets());
1646       output.beginBody(CssClass.BODY_CONTENT_ABOUT);
1647
1648       printNavBarTop(output, "about");
1649
1650       output.div(CssClass.ABOUT_TITLE, "About");
1651
1652       output.beginDiv(CssClass.ABOUT_GENERATOR);
1653       output.print("Generated by ");
1654       output.print("Gjdoc");
1655       output.print(" HtmlDoclet ");
1656       output.print(getDocletVersion());
1657       output.print(", part of ");
1658       output.beginAnchor("http://www.gnu.org/software/classpath/cp-tools/", "", "_top");
1659       output.print("GNU Classpath Tools");
1660       output.endAnchor();
1661       output.print(", on ");
1662       DateFormat format = DateFormat.getDateTimeInstance(DateFormat.LONG,
1663                                                          DateFormat.LONG,
1664                                                          Locale.US);
1665       Calendar cal = Calendar.getInstance(TimeZone.getTimeZone("UTC"),
1666                                           Locale.US);
1667       format.setCalendar(cal);
1668       output.print(format.format(new Date()));
1669       output.print(".");
1670       output.endDiv(CssClass.ABOUT_GENERATOR);
1671
1672       printNavBarBottom(output, "about");
1673
1674       output.endBody();
1675       output.endPage();
1676       output.close();
1677    }
1678
1679    private void printSourcePage(File packageDir, ClassDoc classDoc, String sourceXhtml)
1680       throws IOException
1681    {
1682       HtmlPage output = newHtmlPage(new File(packageDir,
1683                                              classDoc.name() + "-source" + filenameExtension),
1684                                     getPathToRoot(packageDir, getTargetDirectory()));
1685       output.beginPage(getPageTitle("Source for " + classDoc.qualifiedTypeName()),
1686                        getOutputCharset(),
1687                        getStylesheets());
1688
1689       output.beginBody(CssClass.BODY_CONTENT_SOURCE);
1690
1691       printNavBarTop(output, "source", classDoc, null, null);
1692
1693       output.div(CssClass.SOURCE_TITLE, "Source for " + classDoc.qualifiedTypeName());
1694       output.beginDiv(CssClass.SOURCE);
1695       output.print(sourceXhtml);
1696       output.endDiv(CssClass.SOURCE);
1697
1698       printNavBarBottom(output, "source", classDoc);
1699
1700       output.endBody();
1701       output.endPage();
1702
1703       output.close();
1704    }
1705
1706    private void printHelpPage()
1707       throws IOException
1708    {
1709       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1710                                              "help" + filenameExtension),
1711                                     ".");
1712       output.beginPage(getPageTitle("Help"),
1713                        getOutputCharset(),
1714                        getStylesheets());
1715       output.beginBody(CssClass.BODY_CONTENT_HELP);
1716
1717       printNavBarTop(output, "help");
1718
1719       InputStream helpIn;
1720       if (null != optionHelpFile.getValue()){
1721          helpIn = new FileInputStream(optionHelpFile.getValue());
1722       }
1723       else {
1724          helpIn = getClass().getResourceAsStream("/htmldoclet/help.xhtml");
1725       }
1726       output.insert(new InputStreamReader(helpIn, "utf-8"));
1727       helpIn.close();
1728
1729       printNavBarBottom(output, "help");
1730
1731       output.endBody();
1732       output.endPage();
1733       output.close();
1734    }
1735
1736    private void printOverviewPage()
1737       throws IOException
1738    {
1739       HtmlPage output = newHtmlPage(new File(getTargetDirectory(),
1740                                              "overview-summary" + filenameExtension),
1741                                     ".");
1742       output.beginPage(getWindowTitle(),
1743                        getOutputCharset(),
1744                        getStylesheets());
1745       output.beginBody(CssClass.BODY_CONTENT_OVERVIEW);
1746
1747       printNavBarTop(output, "overview");
1748
1749       String overviewHeader;
1750       if (null != optionDocTitle.getValue()) {
1751          overviewHeader = optionDocTitle.getValue();
1752       }
1753       else if (null != optionTitle.getValue()) {
1754          overviewHeader = optionTitle.getValue();
1755       }
1756       else {
1757          overviewHeader = null;
1758       }
1759
1760       if (null != overviewHeader) {
1761          output.div(CssClass.OVERVIEW_TITLE, overviewHeader);
1762       }
1763
1764       output.beginDiv(CssClass.OVERVIEW_DESCRIPTION_TOP);
1765       printTags(output, getRootDoc(), getRootDoc().firstSentenceTags(), true);
1766       output.endDiv(CssClass.OVERVIEW_DESCRIPTION_TOP);
1767
1768       List packageGroups = getPackageGroups();
1769
1770       if (packageGroups.isEmpty()) {
1771
1772          printOverviewPackages(output, getAllPackages(),
1773                                "All Packages");
1774       }
1775       else {
1776          Set otherPackages = new LinkedHashSet();
1777          otherPackages.addAll(getAllPackages());
1778
1779          Iterator it = packageGroups.iterator();
1780          while (it.hasNext()) {
1781             PackageGroup packageGroup = (PackageGroup)it.next();
1782             printOverviewPackages(output,
1783                                   packageGroup.getPackages(),
1784                                   packageGroup.getName());
1785             otherPackages.removeAll(packageGroup.getPackages());
1786          }
1787
1788          if (!otherPackages.isEmpty()) {
1789             printOverviewPackages(output,
1790                                   otherPackages,
1791                                   "Other Packages");
1792          }
1793       }
1794
1795       output.anchorName("description");
1796       output.beginDiv(CssClass.OVERVIEW_DESCRIPTION_FULL);
1797       printTags(output, getRootDoc(), getRootDoc().inlineTags(), false);
1798       output.endDiv(CssClass.OVERVIEW_DESCRIPTION_FULL);
1799
1800       printNavBarBottom(output, "overview");
1801       output.endBody();
1802       output.endPage();
1803       output.close();
1804    }
1805
1806    private void printOverviewPackages(HtmlPage output, Collection packageDocs, String header)
1807    {
1808       output.beginDiv(CssClass.TABLE_CONTAINER);
1809       output.beginTable(CssClass.OVERVIEW_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
1810       output.rowDiv(CssClass.TABLE_HEADER, header);
1811
1812       Iterator it = packageDocs.iterator();
1813       while (it.hasNext()) {
1814          PackageDoc packageDoc = (PackageDoc)it.next();
1815          output.beginRow();
1816
1817          output.beginCell(CssClass.OVERVIEW_SUMMARY_LEFT);
1818          output.beginAnchor(getPackageURL(packageDoc) + "package-summary" + filenameExtension);
1819          output.print(packageDoc.name());
1820          output.endAnchor();
1821          output.endCell();
1822
1823          output.beginCell(CssClass.OVERVIEW_SUMMARY_RIGHT);
1824          printTags(output, packageDoc, packageDoc.firstSentenceTags(), true);
1825          output.endCell();
1826          output.endRow();
1827       }
1828       output.endTable();
1829       output.endDiv(CssClass.TABLE_CONTAINER);
1830    }
1831
1832    private void printClassUsagePage(File packageDir, String pathToRoot, ClassDoc classDoc)
1833       throws IOException
1834    {
1835       HtmlPage output = newHtmlPage(new File(packageDir,
1836                                              classDoc.name() + "-uses" + filenameExtension),
1837                                     pathToRoot);
1838       output.beginPage(getPageTitle(classDoc.name()), getOutputCharset(), getStylesheets());
1839       output.beginBody(CssClass.BODY_CONTENT_USES);
1840       printNavBarTop(output, "uses", classDoc, null, null);
1841
1842       output.div(CssClass.USAGE_TITLE,
1843                  "Uses of " + getClassTypeName(classDoc)
1844                  + " " + classDoc.qualifiedName());
1845
1846       Map packageToUsageTypeMap = getUsageOfClass(classDoc);
1847       if (null != packageToUsageTypeMap && !packageToUsageTypeMap.isEmpty()) {
1848
1849          Iterator packagesIterator = packageToUsageTypeMap.keySet().iterator();
1850          while (packagesIterator.hasNext()) {
1851             PackageDoc packageDoc = (PackageDoc)packagesIterator.next();
1852
1853             output.div(CssClass.USAGE_PACKAGE_TITLE, "Uses in package " + packageDoc.name());
1854
1855             Map usageTypeToUsersMap = (Map)packageToUsageTypeMap.get(packageDoc);
1856             Iterator usageTypeIterator = usageTypeToUsersMap.keySet().iterator();
1857             while (usageTypeIterator.hasNext()) {
1858                UsageType usageType = (UsageType)usageTypeIterator.next();
1859
1860                output.beginTable(CssClass.USAGE_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
1861                output.rowDiv(CssClass.USAGE_TABLE_HEADER, format("usagetype." + usageType.getId(),
1862                                                                  classDoc.qualifiedName()));
1863
1864                Set users = (Set)usageTypeToUsersMap.get(usageType);
1865                Iterator userIterator = users.iterator();
1866                while (userIterator.hasNext()) {
1867                   Doc user = (Doc)userIterator.next();
1868
1869                   output.beginRow();
1870
1871                   if (user instanceof ClassDoc) {
1872                      output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
1873                      output.print("class");
1874                      output.endCell();
1875
1876                      output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
1877                      output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1878                      printType(output, ((ClassDoc)user));
1879                      output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1880                      output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1881                      printTags(output, ((ClassDoc)user), ((ClassDoc)user).firstSentenceTags(), true);
1882                      output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1883                      output.endCell();
1884                   }
1885                   else if (user instanceof FieldDoc) {
1886                      FieldDoc fieldDoc = (FieldDoc)user;
1887
1888                      output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
1889                      printType(output, ((FieldDoc)user).type());
1890                      output.endCell();
1891
1892                      output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
1893                      output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1894                      printType(output, ((FieldDoc)user).containingClass());
1895                      output.print(".");
1896                      output.beginAnchor(getMemberDocURL(output, (FieldDoc)user));
1897                      output.print(((FieldDoc)user).name());
1898                      output.endAnchor();
1899                      output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1900                      output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1901                      printTags(output, ((FieldDoc)user), ((FieldDoc)user).firstSentenceTags(), true);
1902                      output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1903                      output.endCell();
1904                   }
1905                   else if (user instanceof MethodDoc) {
1906                      MethodDoc methodDoc = (MethodDoc)user;
1907
1908                      output.beginCell(CssClass.USAGE_SUMMARY_LEFT);
1909                      printType(output, ((MethodDoc)user).returnType());
1910                      output.endCell();
1911
1912                      output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
1913                      output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1914                      printType(output, ((MethodDoc)user).containingClass());
1915                      output.print(".");
1916                      output.beginAnchor(getMemberDocURL(output, (MethodDoc)user));
1917                      output.print(((MethodDoc)user).name());
1918                      output.endAnchor();
1919                      printParameters(output, (ExecutableMemberDoc)user);
1920                      output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1921                      output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1922                      printTags(output, ((MethodDoc)user), ((MethodDoc)user).firstSentenceTags(), true);
1923                      output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1924                      output.endCell();
1925                   }
1926                   else if (user instanceof ConstructorDoc) {
1927                      ConstructorDoc constructorDoc = (ConstructorDoc)user;
1928
1929                      output.beginCell(CssClass.USAGE_SUMMARY_RIGHT);
1930                      output.beginDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1931                      printType(output, ((ConstructorDoc)user).containingClass());
1932                      output.print(".");
1933                      output.beginAnchor(getMemberDocURL(output, (ConstructorDoc)user));
1934                      output.print(((ConstructorDoc)user).name());
1935                      output.endAnchor();
1936                      printParameters(output, (ExecutableMemberDoc)user);
1937                      output.endDiv(CssClass.USAGE_SUMMARY_SYNOPSIS);
1938                      output.beginDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1939                      printTags(output, ((ConstructorDoc)user),
1940                                ((ConstructorDoc)user).firstSentenceTags(), true);
1941                      output.endDiv(CssClass.USAGE_SUMMARY_DESCRIPTION);
1942                      output.endCell();
1943                   }
1944
1945                   output.endRow();
1946                }
1947                output.endTable();
1948             }
1949          }
1950       }
1951       else {
1952          output.div(CssClass.USAGE_EMPTY,
1953                     getClassTypeName(classDoc)
1954                     + " " + classDoc.qualifiedName() + " is not used by any class in this documentation set.");
1955       }
1956       printNavBarBottom(output, "uses", classDoc);
1957       output.endBody();
1958       output.endPage();
1959       output.close();
1960    }
1961
1962    private void printSuperTreeRec(HtmlPage output, ListIterator it, int level)
1963    {
1964       if (it.hasPrevious()) {
1965          ClassDoc cd = (ClassDoc)it.previous();
1966          output.beginElement("li", new String[] { "class" }, new String[] { "inheritance " + level });
1967          output.beginElement("code");
1968          if (it.hasPrevious()) {
1969             printType(output, cd, true);
1970          }
1971          else {
1972             output.print(cd.qualifiedName() + getTypeParameters(cd));
1973          }
1974          output.endElement("code");
1975          output.endElement("li");
1976
1977          output.beginElement("li");
1978
1979          if (it.hasPrevious()) {
1980             output.beginElement("ul", new String[] { "class" }, new String[] { "inheritance " + (level + 1) });
1981             printSuperTreeRec(output, it, level + 1);
1982             output.endElement("ul");
1983          }
1984
1985          output.endElement("li");
1986       }
1987    }
1988
1989    private static boolean isSubInterface(ClassDoc classDoc, ClassDoc otherClassDoc)
1990    {
1991       ClassDoc[] interfaces = otherClassDoc.interfaces();
1992       for (int i=0; i<interfaces.length; ++i) {
1993          if (classDoc == interfaces[i]) {
1994             return true;
1995          }
1996          else if (isSubInterface(classDoc, interfaces[i])) {
1997             return true;
1998          }
1999       }
2000       return false;
2001    }
2002
2003    private void printCommaSeparatedTypes(HtmlPage output,
2004                                          Collection list,
2005                                          String header,
2006                                          CssClass cssClass)
2007    {
2008       if (!list.isEmpty()) {
2009          output.beginDiv(cssClass);
2010          output.div(CssClass.CLASS_KNOWNIMPLEMENTING_HEADER, header);
2011          output.beginDiv(CssClass.CLASS_KNOWNIMPLEMENTING_ITEM);
2012          Iterator it = list.iterator();
2013          while (it.hasNext()) {
2014             Type type = (Type)it.next();
2015             printType(output, type);
2016             if (it.hasNext()) {
2017                output.print(", ");
2018             }
2019          }
2020          output.endDiv(CssClass.CLASS_KNOWNIMPLEMENTING_ITEM);
2021          output.endDiv(cssClass);
2022       }
2023    }
2024
2025    private void printClassPage(File packageDir, String pathToRoot,
2026                                ClassDoc classDoc, ClassDoc prevClassDoc, ClassDoc nextClassDoc)
2027       throws IOException
2028    {
2029       HtmlPage output = newHtmlPage(new File(packageDir,
2030                                              classDoc.name() + filenameExtension),
2031                                     pathToRoot);
2032       Set keywords = new LinkedHashSet();
2033       {
2034          keywords.add(classDoc.qualifiedName() + " class");
2035          FieldDoc[] fieldDocs = classDoc.fields();
2036          for (int i=0; i<fieldDocs.length; ++i) {
2037             FieldDoc fieldDoc = fieldDocs[i];
2038             keywords.add(fieldDoc.name());
2039          }
2040
2041          MethodDoc[] methodDocs = classDoc.methods();
2042          for (int i=0; i<methodDocs.length; ++i) {
2043             MethodDoc methodDoc = methodDocs[i];
2044             keywords.add(methodDoc.name() + "()");
2045          }
2046       }
2047       String parameters = getTypeParameters(classDoc);
2048
2049       output.beginPage(getPageTitle(classDoc.name()), getOutputCharset(),
2050                        keywords, getStylesheets());
2051       output.beginBody(CssClass.BODY_CONTENT_CLASS);
2052       printNavBarTop(output, "class", classDoc, prevClassDoc, nextClassDoc);
2053
2054       output.beginDiv(CssClass.CLASS_TITLE);
2055       output.div(CssClass.CLASS_TITLE_PACKAGE,
2056                  classDoc.containingPackage().name());
2057       output.div(CssClass.CLASS_TITLE_CLASS,
2058                  getClassTypeName(classDoc)
2059                  + " " + classDoc.name()
2060                  + parameters);
2061       output.endDiv(CssClass.CLASS_TITLE);
2062
2063       boolean needSep = false;
2064
2065       if (classDoc.isInterface()) {
2066
2067          InterfaceRelation relation
2068             = (InterfaceRelation)getInterfaceRelations().get(classDoc);
2069
2070          printCommaSeparatedTypes(output,
2071                                   relation.superInterfaces,
2072                                   "All Superinterfaces:",
2073                                   CssClass.CLASS_KNOWNIMPLEMENTING);
2074
2075          printCommaSeparatedTypes(output,
2076                                   relation.subInterfaces,
2077                                   "Known Subinterfaces:",
2078                                   CssClass.CLASS_KNOWNIMPLEMENTING);
2079
2080          printCommaSeparatedTypes(output,
2081                                   relation.implementingClasses,
2082                                   "Known Implementing Classes:",
2083                                   CssClass.CLASS_KNOWNIMPLEMENTING);
2084
2085          needSep = !relation.superInterfaces.isEmpty()
2086             || !relation.subInterfaces.isEmpty()
2087             || !relation.implementingClasses.isEmpty();
2088       }
2089       else {
2090          needSep = true;
2091
2092          if (!"java.lang.Object".equals(classDoc.qualifiedName())) {
2093             LinkedList superClasses = new LinkedList();
2094             for (ClassDoc cd = classDoc; cd != null; cd = cd.superclass()) {
2095                superClasses.add(cd);
2096             }
2097             output.beginDiv(CssClass.CLASS_INHERITANCETREE);
2098             output.beginElement("ul", new String[] { "class" }, new String[] { "inheritance 0" });
2099             printSuperTreeRec(output, superClasses.listIterator(superClasses.size()), 0);
2100             output.endElement("ul");
2101             output.endDiv(CssClass.CLASS_INHERITANCETREE);
2102
2103             if (null != classDoc.containingClass()) {
2104                output.beginDiv(CssClass.CLASS_ENCLOSINGCLASS);
2105                output.div(CssClass.CLASS_ENCLOSINGCLASS_HEADER, "Enclosing Class:");
2106                output.beginDiv(CssClass.CLASS_ENCLOSINGCLASS_ITEM);
2107                printType(output, classDoc.containingClass());
2108                output.endDiv(CssClass.CLASS_ENCLOSINGCLASS_ITEM);
2109                output.endDiv(CssClass.CLASS_ENCLOSINGCLASS);
2110             }
2111
2112             Set implementedInterfaces = getImplementedInterfaces(classDoc);
2113
2114             printCommaSeparatedTypes(output,
2115                                      implementedInterfaces,
2116                                      "Implemented Interfaces:",
2117                                      CssClass.CLASS_KNOWNIMPLEMENTING);
2118
2119             List knownDirectSubclasses = getKnownDirectSubclasses(classDoc);
2120             if (!knownDirectSubclasses.isEmpty()) {
2121                output.beginDiv(CssClass.CLASS_SUBCLASSES);
2122                output.div(CssClass.CLASS_SUBCLASSES_HEADER, "Known Direct Subclasses:");
2123                output.beginDiv(CssClass.CLASS_SUBCLASSES_ITEM);
2124                Iterator it = knownDirectSubclasses.iterator();
2125                while (it.hasNext()) {
2126                   printType(output, (ClassDoc)it.next());
2127                   if (it.hasNext()) {
2128                      output.print(", ");
2129                   }
2130                }
2131
2132                output.endDiv(CssClass.CLASS_SUBCLASSES_ITEM);
2133                output.endDiv(CssClass.CLASS_SUBCLASSES_HEADER);
2134                output.endDiv(CssClass.CLASS_SUBCLASSES);
2135             }
2136          }
2137       }
2138
2139       if (needSep) {
2140          output.hr();
2141       }
2142
2143       output.beginDiv(CssClass.CLASS_SYNOPSIS);
2144       output.beginDiv(CssClass.CLASS_SYNOPSIS_DECLARATION);
2145       output.print(getFullModifiers(classDoc) + ' ' + getClassTypeKeyword(classDoc)
2146                    + ' ');
2147       output.beginSpan(CssClass.CLASS_SYNOPSIS_NAME);
2148       if (optionLinkSource.getValue() && null != classDoc.position()) {
2149          output.beginAnchor(getOuterClassDoc(classDoc).name() + "-source" + filenameExtension + "#line." + classDoc.position());
2150          output.print(classDoc.name() + parameters);
2151          output.endAnchor();
2152       }
2153       else {
2154          output.print(classDoc.name() + parameters);
2155       }
2156       output.endSpan(CssClass.CLASS_SYNOPSIS_NAME);
2157       output.endDiv(CssClass.CLASS_SYNOPSIS_DECLARATION);
2158
2159       if (!classDoc.isInterface()) {
2160          if (null != classDoc.superclass()) {
2161             output.beginDiv(CssClass.CLASS_SYNOPSIS_SUPERCLASS);
2162             output.print("extends ");
2163             printType(output, classDoc.superclass());
2164             output.endDiv(CssClass.CLASS_SYNOPSIS_SUPERCLASS);
2165          }
2166       }
2167
2168       ClassDoc[] interfaces = classDoc.interfaces();
2169       if (interfaces.length > 0) {
2170          output.beginDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS);
2171          if (!classDoc.isInterface()) {
2172             output.print("implements ");
2173          }
2174          else {
2175             output.print("extends ");
2176          }
2177          for (int i=0; i<interfaces.length; ++i) {
2178             if (i>0) {
2179                output.print(", ");
2180             }
2181             printType(output, interfaces[i]);
2182          }
2183          output.endDiv(CssClass.CLASS_SYNOPSIS_IMPLEMENTS);
2184       }
2185       output.endDiv(CssClass.CLASS_SYNOPSIS);
2186
2187       output.hr();
2188
2189       if (!optionNoComment.getValue()) {
2190          output.beginDiv(CssClass.CLASS_DESCRIPTION);
2191          printTags(output, classDoc, classDoc.inlineTags(), false);
2192          output.endDiv(CssClass.CLASS_DESCRIPTION);
2193
2194          printTaglets(output, classDoc.tags(), new HtmlTagletContext(classDoc, output, false));
2195       }
2196
2197
2198       Set implementedInterfaces = getImplementedInterfaces(classDoc);
2199
2200       boolean haveInheritedFields = false;
2201       boolean haveInheritedMethods = false;
2202       boolean haveInheritedClasses = false;
2203       {
2204          if (!classDoc.isInterface()) {
2205             ClassDoc superClassDoc = classDoc.superclass();
2206             while (null != superClassDoc
2207                    && (!haveInheritedFields
2208                        || !haveInheritedMethods
2209                        || !haveInheritedClasses)) {
2210                if (superClassDoc.fields().length > 0) {
2211                   haveInheritedFields = true;
2212                }
2213                if (superClassDoc.methods().length > 0) {
2214                   haveInheritedMethods = true;
2215                }
2216                if (superClassDoc.innerClasses().length > 0) {
2217                   haveInheritedClasses = true;
2218                }
2219                superClassDoc = superClassDoc.superclass();
2220             }
2221          }
2222       }
2223
2224       printProgramElementDocs(output, getSortedInnerClasses(classDoc),
2225                               "Nested Class Summary", haveInheritedClasses,
2226                               "summary-inner");
2227
2228       {
2229          ClassDoc superClassDoc = classDoc.superclass();
2230          while (null != superClassDoc) {
2231             printInheritedMembers(output, getSortedInnerClasses(superClassDoc),
2232                                   "Nested classes/interfaces inherited from class {0}",
2233                                   superClassDoc);
2234             superClassDoc = superClassDoc.superclass();
2235          }
2236       }
2237
2238       printProgramElementDocs(output, getSortedFields(classDoc),
2239                               "Field Summary", haveInheritedFields,
2240                               "summary-fields");
2241
2242       {
2243          ClassDoc superClassDoc = classDoc.superclass();
2244          while (null != superClassDoc) {
2245             printInheritedMembers(output, getSortedFields(superClassDoc),
2246                                   "Fields inherited from class {0}",
2247                                   superClassDoc);
2248             superClassDoc = superClassDoc.superclass();
2249          }
2250       }
2251
2252       {
2253          Iterator it = implementedInterfaces.iterator();
2254          while (it.hasNext()) {
2255             ClassDoc implementedInterface
2256                = (ClassDoc)it.next();
2257             if (!"java.io.Serializable".equals(implementedInterface.qualifiedName())
2258                 && !"java.io.Externalizable".equals(implementedInterface.qualifiedName())) {
2259                printInheritedMembers(output, getSortedFields(implementedInterface),
2260                                      "Fields inherited from interface {0}",
2261                                      implementedInterface);
2262             }
2263          }
2264       }
2265
2266       printProgramElementDocs(output, getSortedConstructors(classDoc),
2267                               "Constructor Summary", false,
2268                               "summary-constructors");
2269       printProgramElementDocs(output, getSortedMethods(classDoc),
2270                               "Method Summary", haveInheritedMethods,
2271                               "summary-methods");
2272
2273       if (classDoc.isInterface()) {
2274          InterfaceRelation relation
2275             = (InterfaceRelation)getInterfaceRelations().get(classDoc);
2276          Iterator it = relation.superInterfaces.iterator();
2277          while (it.hasNext()) {
2278             ClassDoc superClassDoc = (ClassDoc)it.next();
2279             printInheritedMembers(output, getSortedMethods(superClassDoc),
2280                                   "Methods inherited from interface {0}",
2281                                   superClassDoc);
2282          }
2283       }
2284       else {
2285          ClassDoc superClassDoc = classDoc.superclass();
2286          while (null != superClassDoc) {
2287             printInheritedMembers(output, getSortedMethods(superClassDoc),
2288                                   "Methods inherited from class {0}",
2289                                   superClassDoc);
2290             superClassDoc = superClassDoc.superclass();
2291          }
2292       }
2293
2294       printMemberDetails(output, getSortedFields(classDoc),
2295                          "Field Details", false, "detail-fields");
2296       printMemberDetails(output, getSortedConstructors(classDoc),
2297                          "Constructor Details", false, "detail-constructors");
2298       printMemberDetails(output, getSortedMethods(classDoc),
2299                          "Method Details", false, "detail-methods");
2300
2301       printNavBarBottom(output, "class", classDoc);
2302
2303       output.endBody();
2304       output.endPage();
2305       output.close();
2306    }
2307
2308    private void printInheritedMembers(HtmlPage output,
2309                                       ProgramElementDoc[] memberDocs,
2310                                       String headerFormat,
2311                                       ClassDoc superclass)
2312    {
2313       if (memberDocs.length > 0) {
2314
2315          output.beginDiv(CssClass.TABLE_CONTAINER);
2316          output.beginTable(CssClass.CLASS_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
2317          String superclassLink;
2318          if (superclass.isIncluded()) {
2319             superclassLink = superclass.containingPackage().name()
2320                + "." + createTypeHref(output, superclass, false);
2321          }
2322          else {
2323             superclassLink = createTypeHref(output, superclass, true);
2324          }
2325          output.rowDiv(CssClass.TABLE_SUB_HEADER,
2326                        new MessageFormat(headerFormat).format(new Object[] {
2327                           superclassLink
2328                        }));
2329
2330          output.beginRow();
2331          output.beginCell(CssClass.CLASS_SUMMARY_INHERITED);
2332          for (int i=0; i<memberDocs.length; ++i) {
2333             ProgramElementDoc memberDoc = memberDocs[i];
2334             if (i > 0) {
2335                output.print(", ");
2336             }
2337             String title = null;
2338             if (memberDoc.isMethod()) {
2339                title = memberDoc.name() + ((MethodDoc)memberDoc).flatSignature();
2340             }
2341             else if (memberDoc.isInterface()) {
2342                title = "interface " + ((ClassDoc)memberDoc).qualifiedName();
2343             }
2344             else if (memberDoc.isClass()) {
2345                title = "class " + ((ClassDoc)memberDoc).qualifiedName();
2346             }
2347             output.beginAnchor(getMemberDocURL(output, memberDoc), title);
2348             output.beginSpan(CssClass.CLASS_SUMMARY_INHERITED_MEMBER);
2349             output.print(memberDoc.name());
2350             output.endSpan(CssClass.CLASS_SUMMARY_INHERITED_MEMBER);
2351             output.endAnchor();
2352          }
2353          output.endCell();
2354          output.endRow();
2355          output.endTable();
2356          output.endDiv(CssClass.TABLE_CONTAINER);
2357       }
2358    }
2359
2360    private void collectSpecifiedByRecursive(Set specifyingInterfaces,
2361                                             ClassDoc classDoc,
2362                                             MethodDoc methodDoc)
2363    {
2364       ClassDoc[] interfaces = classDoc.interfaces();
2365       for (int i=0; i<interfaces.length; ++i) {
2366          MethodDoc[] methods = interfaces[i].methods();
2367          for (int j=0; j<methods.length; ++j) {
2368             if (methods[j].name().equals(methodDoc.name())
2369                 && methods[j].signature().equals(methodDoc.signature())) {
2370                specifyingInterfaces.add(methods[j]);
2371                break;
2372             }
2373          }
2374          collectSpecifiedByRecursive(specifyingInterfaces,
2375                                      interfaces[i],
2376                                      methodDoc);
2377       }
2378    }
2379
2380    private void printMemberDetails(HtmlPage output,
2381                                    ProgramElementDoc[] memberDocs, String header,
2382                                    boolean isOnSerializedPage,
2383                                    String anchor)
2384    {
2385       if (memberDocs.length > 0) {
2386
2387          if (null != anchor) {
2388             output.anchorName(anchor);
2389          }
2390
2391          CssClass sectionClass;
2392          CssClass headerClass;
2393          if (isOnSerializedPage) {
2394             sectionClass = CssClass.SERIALIZED_SECTION;
2395             headerClass = CssClass.SERIALIZED_SECTION_HEADER;
2396          }
2397          else {
2398             sectionClass = CssClass.SECTION;
2399             headerClass = CssClass.SECTION_HEADER;
2400          }
2401          output.div(headerClass, header);
2402          output.beginDiv(sectionClass);
2403
2404          for (int i=0; i<memberDocs.length; ++i) {
2405             if (i>0) {
2406                output.hr();
2407             }
2408
2409             ProgramElementDoc memberDoc = memberDocs[i];
2410
2411             output.anchorName(getMemberAnchor(memberDoc));
2412
2413             output.beginDiv(CssClass.MEMBER_DETAIL);
2414             output.div(CssClass.MEMBER_DETAIL_NAME, memberDoc.name());
2415
2416             StringBuffer synopsis = new StringBuffer();
2417             int synopsisLength = 0;
2418
2419             if (!isOnSerializedPage || !memberDoc.isField()) {
2420                String fullModifiers = getFullModifiers(memberDoc);
2421                synopsis.append(fullModifiers);
2422                synopsisLength += fullModifiers.length();
2423
2424             }
2425             if (memberDoc.isMethod() || memberDoc.isField()) {
2426                Type type;
2427                if (memberDoc.isMethod()) {
2428                   type = ((MethodDoc)memberDoc).returnType();
2429                }
2430                else {
2431                   type = ((FieldDoc)memberDoc).type();
2432                }
2433
2434                synopsis.append(" ");
2435                synopsisLength ++;
2436                synopsis.append(createTypeHref(output, type, false));
2437                if (null != type.asClassDoc() && type.asClassDoc().isIncluded()) {
2438                   synopsisLength += type.asClassDoc().name().length();
2439                }
2440                else {
2441                   synopsisLength += type.qualifiedTypeName().length();
2442                }
2443                synopsisLength += type.dimension().length();
2444             }
2445
2446             synopsis.append(" ");
2447             synopsisLength ++;
2448
2449             if (optionLinkSource.getValue() && null != memberDoc.position()) {
2450                ClassDoc containingClass = memberDoc.containingClass();
2451                while (null != containingClass.containingClass()) {
2452                   containingClass = containingClass.containingClass();
2453                }
2454                String href = containingClass.name() + "-source" + filenameExtension + "#line." + memberDoc.position().line();
2455                synopsis.append(output.createHrefString(href, memberDoc.name()));
2456             }
2457             else {
2458                synopsis.append(memberDoc.name());
2459             }
2460             synopsisLength += memberDoc.name().length();
2461
2462             if (memberDoc.isConstructor() || memberDoc.isMethod()) {
2463                //printParameters(output, (ExecutableMemberDoc)memberDoc);
2464                synopsis.append("(");
2465                ++ synopsisLength;
2466                StringBuffer paddingLeft = new StringBuffer();
2467                for (int j=0; j<synopsisLength; ++j) {
2468                   paddingLeft.append(' ');
2469                }
2470                Parameter[] parameters = ((ExecutableMemberDoc)memberDoc).parameters();
2471                for (int j=0; j<parameters.length; ++j) {
2472                   Parameter parameter = parameters[j];
2473                   synopsis.append(createTypeHref(output, parameter.type(), false));
2474                   synopsis.append(" ");
2475                   synopsis.append(parameter.name());
2476                   if (j < parameters.length - 1) {
2477                      synopsis.append(",\n");
2478                      synopsis.append(paddingLeft);
2479                   }
2480                }
2481                synopsis.append(")");
2482                ClassDoc[] exceptions = ((ExecutableMemberDoc)memberDoc).thrownExceptions();
2483                if (exceptions.length > 0) {
2484                   synopsis.append("\n            throws ");
2485                   for (int j=0; j<exceptions.length; ++j) {
2486                      ClassDoc exception = exceptions[j];
2487                      synopsis.append(createTypeHref(output, exception, false));
2488                      if (j < exceptions.length - 1) {
2489                         synopsis.append(",\n                   ");
2490                      }
2491                   }
2492                }
2493             }
2494
2495             output.beginDiv(CssClass.MEMBER_DETAIL_SYNOPSIS);
2496             output.print(synopsis.toString());
2497             output.endDiv(CssClass.MEMBER_DETAIL_SYNOPSIS);
2498
2499             output.beginDiv(CssClass.MEMBER_DETAIL_BODY);
2500
2501             Tag[] deprecatedTags = memberDoc.tags("deprecated");
2502             if (deprecatedTags.length > 0) {
2503                output.beginDiv(CssClass.DEPRECATED_INLINE);
2504                output.beginSpan(CssClass.DEPRECATED_HEADER);
2505                output.print("Deprecated. ");
2506                output.endSpan(CssClass.DEPRECATED_HEADER);
2507                output.beginSpan(CssClass.DEPRECATED_BODY);
2508             }
2509             for (int j=0; j<deprecatedTags.length; ++j) {
2510                printTags(output, memberDoc, deprecatedTags[j].inlineTags(), true);
2511             }
2512             if (deprecatedTags.length > 0) {
2513                output.endSpan(CssClass.DEPRECATED_BODY);
2514                output.beginDiv(CssClass.DEPRECATED_INLINE);
2515             }
2516
2517             output.beginDiv(CssClass.MEMBER_DETAIL_DESCRIPTION);
2518             printTags(output, memberDoc, memberDoc.inlineTags(), false);
2519             output.endDiv(CssClass.MEMBER_DETAIL_DESCRIPTION);
2520
2521             if (memberDoc.isConstructor() || memberDoc.isMethod()) {
2522
2523                if (memberDoc.isMethod()) {
2524                   Set specifyingInterfaces = new LinkedHashSet();
2525                   if (memberDoc.containingClass().isInterface()) {
2526                      collectSpecifiedByRecursive(specifyingInterfaces,
2527                                                  memberDoc.containingClass(),
2528                                                  (MethodDoc)memberDoc);
2529                   }
2530                   else {
2531                      for (ClassDoc cd = memberDoc.containingClass();
2532                           null != cd; cd = cd.superclass()) {
2533                         collectSpecifiedByRecursive(specifyingInterfaces,
2534                                                     cd,
2535                                                     (MethodDoc)memberDoc);
2536                      }
2537                   }
2538
2539                   if (!specifyingInterfaces.isEmpty()
2540                       && !isOnSerializedPage) {
2541                      output.beginDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_LIST);
2542                      output.div(CssClass.MEMBER_DETAIL_SPECIFIED_BY_HEADER, "Specified by:");
2543                      Iterator it = specifyingInterfaces.iterator();
2544                      while (it.hasNext()) {
2545                         MethodDoc specifyingInterfaceMethod = (MethodDoc)it.next();
2546                         output.beginDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_ITEM);
2547                         output.beginAnchor(getMemberDocURL(output,
2548                                                            specifyingInterfaceMethod));
2549                         output.print(memberDoc.name());
2550                         output.endAnchor();
2551                         output.print(" in interface ");
2552                         printType(output, specifyingInterfaceMethod.containingClass());
2553                         output.endDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_ITEM);
2554                      }
2555                      output.endDiv(CssClass.MEMBER_DETAIL_SPECIFIED_BY_LIST);
2556                   }
2557
2558                   ClassDoc overriddenClassDoc = null;
2559                   MemberDoc specifyingSuperMethod = null;
2560
2561                   for (ClassDoc superclassDoc = memberDoc.containingClass().superclass();
2562                        null != superclassDoc && null == overriddenClassDoc;
2563                        superclassDoc = superclassDoc.superclass()) {
2564
2565                      MethodDoc[] methods = superclassDoc.methods();
2566                      for (int j=0; j<methods.length; ++j) {
2567                         if (methods[j].name().equals(memberDoc.name())
2568                             && methods[j].signature().equals(((MethodDoc)memberDoc).signature())) {
2569                            overriddenClassDoc = superclassDoc;
2570                            specifyingSuperMethod = methods[j];
2571                            break;
2572                         }
2573                      }
2574                   }
2575
2576                   if (null != overriddenClassDoc) {
2577                      output.beginDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_LIST);
2578                      output.div(CssClass.MEMBER_DETAIL_OVERRIDDEN_HEADER, "Overrides:");
2579                      output.beginDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_ITEM);
2580
2581                      output.beginAnchor(getMemberDocURL(output,
2582                                                         specifyingSuperMethod));
2583                      output.print(memberDoc.name());
2584                      output.endAnchor();
2585                      output.print(" in interface ");
2586                      printType(output, overriddenClassDoc);
2587
2588                      output.endDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_ITEM);
2589                      output.endDiv(CssClass.MEMBER_DETAIL_OVERRIDDEN_LIST);
2590                   }
2591                }
2592
2593                if (!optionNoComment.getValue()) {
2594
2595                   ExecutableMemberDoc execMemberDoc
2596                      = (ExecutableMemberDoc)memberDoc;
2597
2598                   if (execMemberDoc.paramTags().length > 0) {
2599                      output.beginDiv(CssClass.MEMBER_DETAIL_PARAMETER_LIST);
2600                      output.div(CssClass.MEMBER_DETAIL_PARAMETER_HEADER, "Parameters:");
2601                      Parameter[] parameters = execMemberDoc.parameters();
2602                      for (int j=0; j<parameters.length; ++j) {
2603                         Parameter parameter = parameters[j];
2604                         ParamTag[] paramTags = execMemberDoc.paramTags();
2605                         ParamTag paramTag = null;
2606                         for (int k=0; k<paramTags.length; ++k) {
2607                            if (paramTags[k].parameterName().equals(parameter.name())) {
2608                               paramTag = paramTags[k];
2609                               break;
2610                            }
2611                         }
2612
2613                         if (null != paramTag) {
2614                            output.beginDiv(CssClass.MEMBER_DETAIL_PARAMETER_ITEM);
2615                            output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_NAME);
2616                            output.print(parameter.name());
2617                            output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_NAME);
2618                            output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_SEPARATOR);
2619                            output.print(" - ");
2620                            output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_SEPARATOR);
2621                            output.beginSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_DESCRIPTION);
2622                            printTags(output, execMemberDoc, paramTag.inlineTags(), false);
2623                            output.endSpan(CssClass.MEMBER_DETAIL_PARAMETER_ITEM_DESCRIPTION);
2624                            output.endDiv(CssClass.MEMBER_DETAIL_PARAMETER_ITEM);
2625                         }
2626                      }
2627                      output.endDiv(CssClass.MEMBER_DETAIL_PARAMETER_LIST);
2628                   }
2629
2630                   if (execMemberDoc.isMethod()
2631                       && !"void".equals(((MethodDoc)execMemberDoc).returnType().typeName())) {
2632
2633                      Tag[] returnTags = execMemberDoc.tags("return");
2634                      if (returnTags.length > 0) {
2635                         Tag returnTag = returnTags[0];
2636
2637                         output.beginDiv(CssClass.MEMBER_DETAIL_RETURN_LIST);
2638                         output.div(CssClass.MEMBER_DETAIL_RETURN_HEADER, "Returns:");
2639                         output.beginDiv(CssClass.MEMBER_DETAIL_RETURN_ITEM);
2640
2641                         printTags(output, execMemberDoc, returnTag.inlineTags(), false);
2642
2643                         output.endDiv(CssClass.MEMBER_DETAIL_RETURN_ITEM);
2644                         output.endDiv(CssClass.MEMBER_DETAIL_RETURN_LIST);
2645                      }
2646                   }
2647
2648                   Set thrownExceptions = getThrownExceptions(execMemberDoc);
2649                   boolean haveThrowsInfo = false;
2650                   ThrowsTag[] throwsTags = execMemberDoc.throwsTags();
2651                   for (int k=0; k<throwsTags.length; ++k) {
2652                      ThrowsTag throwsTag = throwsTags[k];
2653                      if (null != throwsTags[k].exception()
2654                          && (isUncheckedException(throwsTags[k].exception())
2655                              || thrownExceptions.contains(throwsTag.exception()))) {
2656                         haveThrowsInfo = true;
2657                         break;
2658                      }
2659                   }
2660
2661                   if (haveThrowsInfo) {
2662                      output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
2663                      output.div(CssClass.MEMBER_DETAIL_THROWN_HEADER, "Throws:");
2664
2665                      for (int k=0; k<throwsTags.length; ++k) {
2666                         ThrowsTag throwsTag = throwsTags[k];
2667                         if (null != throwsTag.exception()
2668                             && (isUncheckedException(throwsTag.exception())
2669                                 || thrownExceptions.contains(throwsTag.exception()))) {
2670                            output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_ITEM);
2671                            output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_NAME);
2672                            printType(output, throwsTags[k].exception());
2673                            output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_NAME);
2674                            if (null != throwsTag) {
2675                               output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_SEPARATOR);
2676                               output.print(" - ");
2677                               output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_SEPARATOR);
2678                               output.beginSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_DESCRIPTION);
2679                               printTags(output, execMemberDoc, throwsTag.inlineTags(), false);
2680                               output.endSpan(CssClass.MEMBER_DETAIL_THROWN_ITEM_DESCRIPTION);
2681                            }
2682                            output.endDiv(CssClass.MEMBER_DETAIL_THROWN_ITEM);
2683                         }
2684                      }
2685                      output.endDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
2686                   }
2687                }
2688             }
2689
2690             if (!optionNoComment.getValue()) {
2691
2692                if (memberDoc.isField()) {
2693                   FieldDoc fieldDoc = ((FieldDoc)memberDoc);
2694                   if (null != fieldDoc.constantValue()) {
2695                      output.beginDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
2696                      output.div(CssClass.MEMBER_DETAIL_THROWN_HEADER, "Field Value:");
2697                      output.div(CssClass.MEMBER_DETAIL_THROWN_ITEM,
2698                                 fieldDoc.constantValueExpression().toString());
2699                      output.endDiv(CssClass.MEMBER_DETAIL_THROWN_LIST);
2700                   }
2701                }
2702
2703                TagletContext context = new HtmlTagletContext(memberDoc, output, isOnSerializedPage);
2704                printTaglets(output, memberDoc.tags(), context);
2705             }
2706
2707             output.endDiv(CssClass.MEMBER_DETAIL_BODY);
2708             output.endDiv(CssClass.MEMBER_DETAIL);
2709          }
2710          output.endDiv(sectionClass);
2711       }
2712    }
2713
2714
2715    private void printParameters(HtmlPage output, ExecutableMemberDoc memberDoc)
2716    {
2717       Parameter[] parameters = memberDoc.parameters();
2718       output.print("(");
2719       for (int j=0; j<parameters.length; ++j) {
2720          if (j > 0) {
2721             output.print(", ");
2722          }
2723          printType(output, parameters[j].type());
2724          output.print("&nbsp;");
2725          output.print(parameters[j].name());
2726       }
2727       output.print(")");
2728    }
2729
2730    private void printProgramElementDocs(HtmlPage output,
2731                                         ProgramElementDoc[] memberDocs,
2732                                         String header,
2733                                         boolean forceOutputHeader,
2734                                         String anchor)
2735    {
2736       if (memberDocs.length > 0 || forceOutputHeader) {
2737          output.anchorName(anchor);
2738          output.beginDiv(CssClass.TABLE_CONTAINER);
2739          output.beginTable(CssClass.CLASS_SUMMARY, new String[] { "border", "width" }, new String[] { "1", "100%" });
2740          output.rowDiv(CssClass.TABLE_HEADER, header);
2741
2742          for (int i=0; i<memberDocs.length; ++i) {
2743             ProgramElementDoc memberDoc = memberDocs[i];
2744             output.beginRow();
2745
2746             if (!memberDoc.isConstructor()) {
2747                output.beginCell(CssClass.CLASS_SUMMARY_LEFT);
2748                output.beginDiv(CssClass.CLASS_SUMMARY_LEFT_SYNOPSIS);
2749                output.print(getSummaryModifiers(memberDoc) + " ");
2750                if (memberDoc.isMethod()) {
2751                   printType(output, ((MethodDoc)memberDoc).returnType());
2752                }
2753                else if (memberDoc.isField()) {
2754                   printType(output, ((FieldDoc)memberDoc).type());
2755                }
2756                else if (memberDoc.isInterface()) {
2757                   output.print(" interface");
2758                }
2759                else if (memberDoc.isClass()) {
2760                   output.print(" class");
2761                }
2762                output.endDiv(CssClass.CLASS_SUMMARY_LEFT_SYNOPSIS);
2763                output.endCell();
2764             }
2765
2766             output.beginCell(CssClass.CLASS_SUMMARY_RIGHT);
2767             output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_LIST);
2768             output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_SYNOPSIS);
2769             if (memberDoc.isClass() || memberDoc.isInterface()) {
2770                output.beginAnchor(getClassDocURL(output, (ClassDoc)memberDoc));
2771             }
2772             else {
2773                output.beginAnchor("#" + getMemberAnchor(memberDoc));
2774             }
2775             output.print(memberDoc.name());
2776             output.endAnchor();
2777             if (memberDoc.isConstructor() || memberDoc.isMethod()) {
2778                printParameters(output, (ExecutableMemberDoc)memberDoc);
2779             }
2780             output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_SYNOPSIS);
2781             Tag[] firstSentenceTags;
2782             Tag[] deprecatedTags = memberDoc.tags("deprecated");
2783             if (deprecatedTags.length > 0) {
2784                firstSentenceTags = deprecatedTags[0].firstSentenceTags();
2785             }
2786             else {
2787                firstSentenceTags = memberDoc.firstSentenceTags();
2788             }
2789
2790             if (null != firstSentenceTags && firstSentenceTags.length > 0) {
2791                output.beginDiv(CssClass.CLASS_SUMMARY_RIGHT_DESCRIPTION);
2792                if (deprecatedTags.length > 0) {
2793                   output.beginDiv(CssClass.DEPRECATED);
2794                   output.beginSpan(CssClass.DEPRECATED_HEADER);
2795                   output.print("Deprecated. ");
2796                   output.endSpan(CssClass.DEPRECATED_HEADER);
2797                   output.beginSpan(CssClass.DEPRECATED_BODY);
2798                }
2799                printTags(output, memberDoc, firstSentenceTags, true);
2800                if (deprecatedTags.length > 0) {
2801                   output.endSpan(CssClass.DEPRECATED_BODY);
2802                   output.beginDiv(CssClass.DEPRECATED);
2803                }
2804                output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_DESCRIPTION);
2805             }
2806             output.endDiv(CssClass.CLASS_SUMMARY_RIGHT_LIST);
2807             output.endCell();
2808             output.endRow();
2809          }
2810          output.endTable();
2811          output.endDiv(CssClass.TABLE_CONTAINER);
2812       }
2813    }
2814
2815    private void printTag(final HtmlPage output,
2816                          HtmlRepairer repairer,
2817                          Tag tag, boolean firstSentence,
2818                          boolean inline,
2819                          Doc contextDoc)
2820    {
2821       TagletContext context = new HtmlTagletContext(contextDoc, output, false);
2822       if (firstSentence) {
2823          output.print(renderInlineTags(tag.firstSentenceTags(), context));
2824       }
2825       else {
2826          output.print(renderInlineTags(tag.inlineTags(), context));
2827       }
2828    }
2829
2830    private void printTags(HtmlPage output, Doc contextDoc, Tag[] tags, boolean firstSentence)
2831    {
2832       printTags(output, contextDoc, tags, firstSentence, false);
2833    }
2834
2835    private void printTags(HtmlPage output, Doc contextDoc, Tag[] tags, boolean firstSentence, boolean inline)
2836    {
2837       if (!optionNoComment.getValue()) {
2838          output.print(renderInlineTags(tags, new HtmlTagletContext(contextDoc, output, false)));
2839       }
2840
2841       /*
2842       if (!optionNoComment.getValue()) {
2843          output.print(renderInlineTags(tag.firstSentenceTags(), output));
2844          HtmlRepairer repairer = new HtmlRepairer(getRootDoc(),
2845                                                   true, false,
2846                                                   null, null,
2847                                                   true);
2848          for (int i=0; i<tags.length; ++i) {
2849             printTag(output, repairer, tags[i], firstSentence, inline);
2850          }
2851          output.print(repairer.terminateText());
2852       }
2853       */
2854    }
2855
2856    private String getClassDocURL(HtmlPage output, ClassDoc classDoc)
2857    {
2858       return output.getPathToRoot()
2859          + "/"
2860          + getPackageURL(classDoc.containingPackage())
2861          + classDoc.name() + filenameExtension;
2862    }
2863
2864    private String getMemberDocURL(HtmlPage output, ProgramElementDoc memberDoc)
2865    {
2866       ClassDoc classDoc = memberDoc.containingClass();
2867       PackageDoc packageDoc = classDoc.containingPackage();
2868       ExternalDocSet externalDocSet = null;
2869       if (classDoc.containingPackage().name().length() > 0) {
2870          externalDocSet = packageNameToDocSet.get(packageDoc.name());
2871       }
2872       StringBuffer result = new StringBuffer();
2873       result.append(getClassDocURL(output, classDoc));
2874       result.append('#');
2875       if (null == externalDocSet) {
2876          result.append(getMemberAnchor(memberDoc));
2877       }
2878       else {
2879          result.append(getMemberAnchor(memberDoc, externalDocSet.isJavadocCompatible()));
2880       }
2881       return result.toString();
2882    }
2883
2884    private void printType(HtmlPage output, Type type)
2885    {
2886       printType(output, type, false);
2887    }
2888
2889    private void printType(HtmlPage output, Type type, boolean fullyQualified)
2890    {
2891       output.print(createTypeHref(output, type, fullyQualified));
2892    }
2893
2894    private String createTypeHref(HtmlPage output, Type type, boolean fullyQualified)
2895    {
2896       ClassDoc asClassDoc = type.asClassDoc();
2897       String url = null;
2898       if (null != asClassDoc && asClassDoc.isIncluded()) {
2899          url = getClassDocURL(output, asClassDoc);
2900      }
2901       else if (!type.isPrimitive()) {
2902          if (type.qualifiedTypeName().length() > type.typeName().length()) {
2903             String packageName = type.qualifiedTypeName();
2904             packageName = packageName.substring(0, packageName.length() - type.typeName().length() - 1);
2905
2906             ExternalDocSet externalDocSet = packageNameToDocSet.get(packageName);
2907             if (null != externalDocSet) {
2908                url = externalDocSet.getClassDocURL(packageName, type.typeName());
2909             }
2910          }
2911       }
2912
2913       StringBuffer result = new StringBuffer();
2914
2915       if (null != url && null != asClassDoc) {
2916         String parameters = getTypeParameters(asClassDoc);
2917          if (fullyQualified) {
2918             result.append(output.createHrefString(url,possiblyQualifiedName(asClassDoc) + parameters));
2919          }
2920          else {
2921             StringBuffer title = new StringBuffer();
2922             title.append(getClassTypeName(asClassDoc));
2923             title.append(" in ");
2924             title.append(asClassDoc.containingPackage().name());
2925             result.append(output.createHrefString(url, asClassDoc.name() + parameters, title.toString()));
2926          }
2927       }
2928       else {
2929          result.append(possiblyQualifiedName(type));
2930       }
2931       result.append(type.dimension());
2932       return result.toString();
2933    }
2934
2935    private void printTaglets(final HtmlPage output, Tag[] tags, TagletContext context)
2936    {
2937       super.printMainTaglets(tags, context, new TagletPrinter() {
2938             public void printTagletString(String tagletString) {
2939                output.beginDiv(CssClass.TAGLET);
2940                output.print(tagletString);
2941                output.endDiv(CssClass.TAGLET);
2942             }
2943          });
2944    }
2945
2946    private String getPackageURL(PackageDoc packageDoc)
2947    {
2948       if (packageDoc.name().length() > 0) {
2949          ExternalDocSet externalDocSet = packageNameToDocSet.get(packageDoc.name());
2950          String url;
2951          if (null != externalDocSet) {
2952             url = externalDocSet.getPackageDocURL(packageDoc.name());
2953          }
2954          else {
2955             url = packageDoc.name().replace('.', '/');
2956          }
2957          if (!url.endsWith("/")) {
2958             return url + '/';
2959          }
2960          else {
2961             return url;
2962          }
2963      }
2964       else {
2965          return "";
2966       }
2967    }
2968
2969    private String getClassURL(ClassDoc classDoc)
2970    {
2971       ExternalDocSet externalDocSet = null;
2972       if (classDoc.containingPackage().name().length() > 0) {
2973          externalDocSet = packageNameToDocSet.get(classDoc.containingPackage().name());
2974       }
2975       if (null != externalDocSet) {
2976          return externalDocSet.getClassDocURL(classDoc.containingPackage().name(),
2977                                               classDoc.name());
2978       }
2979       else {
2980          return getPackageURL(classDoc.containingPackage()) + classDoc.name() + filenameExtension;
2981       }
2982    }
2983
2984    protected void run()
2985       throws DocletConfigurationException, IOException
2986    {
2987       if (optionSerialWarn.getValue()) {
2988          printWarning("Option -serialwarn is currently ignored.");
2989       }
2990
2991       if (null != optionTitle.getValue()) {
2992          printWarning("Option -title is deprecated.");
2993       }
2994
2995       if (!optionValidHtml.getValue()) {
2996          printWarning("Option -validhtml hasn't been specified. Generated HTML will not validate.");
2997       }
2998
2999
3000       {
3001          boolean warningEmitted = false;
3002          Iterator it = externalDocSets.iterator();
3003          while (it.hasNext()) {
3004             ExternalDocSet externalDocSet = (ExternalDocSet)it.next();
3005             printNotice("Fetching package list for external documentation set.");
3006             try {
3007                externalDocSet.load(getTargetDirectory());
3008                if (!isJavadocCompatibleNames() && externalDocSet.isJavadocCompatible()
3009                    && !warningEmitted) {
3010                   printWarning("Linking to javadoc-compatible documentation. Generated HTML will not validate ");
3011                   warningEmitted = true;
3012                }
3013             }
3014             catch (FileNotFoundException e) {
3015                printWarning("Cannot fetch package list from " + externalDocSet.getPackageListDir());
3016             }
3017             Iterator pit = externalDocSet.getPackageNames().iterator();
3018             while (pit.hasNext()) {
3019                String packageName = (String)pit.next();
3020                packageNameToDocSet.put(packageName, externalDocSet);
3021             }
3022          }
3023       }
3024       printNotice("Building cross-reference information...");
3025       getInterfaceRelations();
3026       getAllSubClasses();
3027
3028       printNotice("Writing overview files...");
3029       printFrameSetPage();
3030       if (!isSinglePackage()) {
3031          printPackagesMenuPage();
3032          printAllClassesMenuPage();
3033          printOverviewPage();
3034          if (!optionNoTree.getValue()) {
3035             printNotice("Writing full tree...");
3036             printFullTreePage();
3037          }
3038       }
3039       printPackagesListFile();
3040       printAboutPage();
3041       if (!optionNoIndex.getValue()) {
3042          printNotice("Writing index...");
3043          if (!optionSplitIndex.getValue()) {
3044             printIndexPage();
3045          }
3046          else {
3047             printSplitIndex();
3048          }
3049       }
3050       if (outputHelpPage && !optionNoHelp.getValue()) {
3051          printHelpPage();
3052       }
3053
3054       // Copy resources
3055
3056       File resourcesDir = new File(getTargetDirectory(),
3057                                    "resources");
3058
3059       if ((resourcesDir.exists() && !resourcesDir.isDirectory())
3060           || (!resourcesDir.exists() && !resourcesDir.mkdirs())) {
3061          throw new IOException("Cannot create directory " + resourcesDir);
3062       }
3063
3064       // Copy resources
3065
3066       String[] resourceNames = {
3067          "gjdoc.js",
3068          "gjdochtml-clean-layout.css",
3069          "gjdochtml-clean-color1.css",
3070          "inherit.png",
3071          "xhtml11-target10.dtd",
3072       };
3073
3074       for (int i=0; i<resourceNames.length; ++i) {
3075          String resourceName = resourceNames[i];
3076          File targetFile = new File(resourcesDir,
3077                                     resourceName);
3078          InputStream in = getClass().getResourceAsStream("/htmldoclet/" + resourceName);
3079          if (in == null) {
3080                 in = new FileInputStream("src/resources/htmldoclet/" + resourceName);
3081          }
3082          FileOutputStream out = new FileOutputStream(targetFile);
3083          IOToolkit.copyStream(in, out);
3084          in.close();
3085          out.close();
3086       }
3087
3088       // Copy stylesheets
3089
3090       if (null != optionAddStylesheet.getValue()) {
3091          File addStylesheetTargetFile = new File(resourcesDir,
3092                                                  "user.css");
3093
3094          IOToolkit.copyFile(optionAddStylesheet.getValue(),
3095                             addStylesheetTargetFile);
3096       }
3097
3098       if (null != optionStylesheetFile.getValue()) {
3099          File stylesheetTargetFile = new File(resourcesDir,
3100                                               "user.css");
3101
3102          IOToolkit.copyFile(optionStylesheetFile.getValue(),
3103                             stylesheetTargetFile);
3104       }
3105
3106       // Write gjdoc.properties
3107
3108       File gjdocPropertiesTargetFile = new File(getTargetDirectory(),
3109                                                 "gjdoc.properties");
3110       writeGjdocProperties(gjdocPropertiesTargetFile);
3111
3112       /*
3113       else {
3114          InputStream cssIn = getClass().getResourceAsStream("/htmldoclet/gjdochtml-vanilla.css");
3115          FileOutputStream cssOut = new FileOutputStream(stylesheetTargetFile);
3116          IOToolkit.copyStream(cssIn, cssOut);
3117          cssIn.close();
3118          cssOut.close();
3119       }
3120       */
3121
3122       if (!optionNoDeprecatedList.getValue()) {
3123          printDeprecationPage();
3124       }
3125
3126       printSerializationPage();
3127
3128       Collection packageDocsCollection = getAllPackages();
3129       PackageDoc[] packageDocs
3130          = (PackageDoc[])packageDocsCollection.toArray(new PackageDoc[0]);
3131
3132       for (int i=0; i<packageDocs.length; ++i) {
3133          PackageDoc packageDoc = packageDocs[i];
3134          File packageDir = new File(getTargetDirectory(),
3135                                     packageDoc.name().replace('.', File.separatorChar));
3136          if (!packageDir.exists() && !packageDir.mkdirs()) {
3137             throw new IOException("Couldn't create directory " + packageDir);
3138          }
3139          try {
3140             List packageSourceDirs = getPackageSourceDirs(packageDoc);
3141             Iterator pdIt = packageSourceDirs.iterator();
3142             while (pdIt.hasNext()) {
3143                File sourcePackageDir = (File)pdIt.next();
3144                copyDocFiles(sourcePackageDir, packageDir);
3145             }
3146          }
3147          catch (IOException ignore) {
3148          }
3149          String pathToRoot = getPathToRoot(packageDir, getTargetDirectory());
3150          String packageName = packageDoc.name();
3151          if (0 == packageName.length()) {
3152             packageName = "<unnamed>";
3153          }
3154          printNotice("Writing HTML files for package " + packageName);
3155          printPackagePage(packageDir, pathToRoot, packageDoc,
3156                           (i > 0) ? packageDocs[i - 1] : null,
3157                           (i < packageDocs.length - 1) ? packageDocs[i + 1] : null);
3158          if (!optionNoTree.getValue()) {
3159             printPackageTreePage(packageDir, pathToRoot, packageDoc);
3160          }
3161          printPackageClassesMenuPage(packageDir, pathToRoot, packageDoc);
3162          ClassDoc[] classDocs = packageDoc.allClasses();
3163          for (int j=0; j<classDocs.length; ++j) {
3164             ClassDoc classDoc = classDocs[j];
3165             if (classDoc.isIncluded()) {
3166                printClassPage(packageDir, pathToRoot,
3167                               classDocs[j],
3168                               (j > 0) ? classDocs[j - 1] : null,
3169                               (j < classDocs.length - 1) ? classDocs[j + 1] : null
3170                               );
3171                if (optionUse.getValue()) {
3172                   printClassUsagePage(packageDir, pathToRoot, classDocs[j]);
3173                }
3174                if (optionLinkSource.getValue() && null == classDoc.containingClass()) {
3175                   try {
3176                      File sourceFile = getSourceFile(classDoc);
3177
3178                      Java2xhtml java2xhtml = new Java2xhtml();
3179                      Properties properties = new Properties();
3180                      properties.setProperty("isCodeSnippet", "true");
3181                      properties.setProperty("hasLineNumbers", "true");
3182                      java2xhtml.setProperties(properties);
3183
3184                      StringWriter sourceBuffer = new StringWriter();
3185                      FileReader sourceReader = new FileReader(sourceFile);
3186                      IOToolkit.copyStream(sourceReader, sourceBuffer);
3187                      sourceReader.close();
3188                      String result = java2xhtml.makeHTML(sourceBuffer.getBuffer(), sourceFile.getName());
3189
3190                      printSourcePage(packageDir,
3191                                      classDoc,
3192                                      result);
3193                   }
3194                   catch (IOException e) {
3195                      printWarning("Cannot locate source file for class " + classDoc.qualifiedTypeName());
3196                   }
3197                }
3198             }
3199          }
3200       }
3201    }
3202
3203    private String getPathToRoot(File subDir, File rootDir)
3204    {
3205       StringBuffer result = new StringBuffer();
3206       while (!subDir.equals(rootDir)) {
3207          if (result.length() > 0) {
3208             result.append("/");
3209          }
3210          subDir = subDir.getParentFile();
3211          result.append("..");
3212       }
3213       if (0 == result.length()) {
3214          result.append(".");
3215       }
3216       return result.toString();
3217    }
3218
3219    private String getClassTypeName(ClassDoc classDoc)
3220    {
3221       if (classDoc.isInterface()) {
3222          return "Interface";
3223       }
3224       else {
3225          return "Class";
3226       }
3227    }
3228
3229    private String getClassTypeKeyword(ClassDoc classDoc)
3230    {
3231       if (classDoc.isInterface()) {
3232          return "interface";
3233       }
3234       else {
3235          return "class";
3236       }
3237    }
3238
3239    private String getMemberAnchor(ProgramElementDoc memberDoc)
3240    {
3241       return getMemberAnchor(memberDoc, isJavadocCompatibleNames());
3242    }
3243
3244    private String getMemberAnchor(ProgramElementDoc memberDoc, boolean javadocCompatibility)
3245    {
3246       StringBuffer anchor = new StringBuffer();
3247       anchor.append(memberDoc.name());
3248       if (memberDoc.isConstructor() || memberDoc.isMethod()) {
3249          if (javadocCompatibility) {
3250             anchor.append(((ExecutableMemberDoc)memberDoc).signature());
3251          }
3252          else {
3253             anchor.append(':');
3254             Parameter[] parameters = ((ExecutableMemberDoc)memberDoc).parameters();
3255             for (int i=0; i<parameters.length; ++i) {
3256                anchor.append(parameters[i].type().typeName());
3257                for (int j=0; j<parameters[i].type().dimension().length()/2; ++j) {
3258                   anchor.append('-');
3259                }
3260                if (i < parameters.length - 1) {
3261                   anchor.append(':');
3262                }
3263             }
3264          }
3265       }
3266       return anchor.toString();
3267    }
3268
3269    private String getFullModifiers(ProgramElementDoc memberDoc)
3270    {
3271       StringBuffer result = new StringBuffer();
3272       if (memberDoc.isPackagePrivate()) {
3273          result.append("(package private) ");
3274       }
3275       result.append(memberDoc.modifiers());
3276       if ((memberDoc.isClass() && ((ClassDoc)memberDoc).isAbstract())
3277           || (memberDoc.isMethod() && ((MethodDoc)memberDoc).isAbstract())) {
3278          result.append(" abstract");
3279       }
3280       return result.toString();
3281    }
3282
3283    private String getSummaryModifiers(ProgramElementDoc memberDoc)
3284    {
3285       StringBuffer result = new StringBuffer();
3286       if (memberDoc.isPackagePrivate()) {
3287          result.append("(package private) ");
3288       }
3289       else if (memberDoc.isPrivate()) {
3290          result.append("private ");
3291       }
3292       else if (memberDoc.isProtected()) {
3293          result.append("protected ");
3294       }
3295       if (memberDoc.isStatic()) {
3296          result.append("static");
3297       }
3298       else if ((memberDoc.isClass() && ((ClassDoc)memberDoc).isAbstract())
3299           || (memberDoc.isMethod() && ((MethodDoc)memberDoc).isAbstract())) {
3300          result.append("abstract");
3301       }
3302       return result.toString();
3303    }
3304
3305    protected DocletOption[] getOptions()
3306    {
3307       return options;
3308    }
3309
3310    private DocletOptionFlag optionNoNavBar =
3311      new DocletOptionFlag("-nonavbar");
3312
3313    private DocletOptionFlag optionNoTree =
3314      new DocletOptionFlag("-notree");
3315
3316    private DocletOptionFlag optionNoDeprecatedList =
3317      new DocletOptionFlag("-nodeprecatedlist");
3318
3319    private DocletOptionFlag optionNoIndex =
3320      new DocletOptionFlag("-noindex");
3321
3322    private DocletOptionFlag optionUse =
3323      new DocletOptionFlag("-use");
3324
3325    private DocletOptionFlag optionNoHelp =
3326      new DocletOptionFlag("-nohelp");
3327
3328    private DocletOptionFlag optionNoComment =
3329      new DocletOptionFlag("-nocomment");
3330
3331    private DocletOptionFlag optionSerialWarn =
3332      new DocletOptionFlag("-serialwarn");
3333
3334    private DocletOptionFlag optionSplitIndex =
3335      new DocletOptionFlag("-splitindex");
3336
3337    private DocletOptionString optionHeader =
3338      new DocletOptionString("-header");
3339
3340    private DocletOptionString optionFooter =
3341      new DocletOptionString("-footer");
3342
3343    private DocletOptionString optionBottom =
3344      new DocletOptionString("-bottom");
3345
3346    private DocletOptionString optionWindowTitle =
3347      new DocletOptionString("-windowtitle");
3348
3349    private DocletOptionString optionDocTitle =
3350      new DocletOptionString("-doctitle");
3351
3352    private DocletOptionString optionTitle =
3353      new DocletOptionString("-title");
3354
3355    private DocletOptionFile optionHelpFile =
3356      new DocletOptionFile("-helpfile");
3357
3358    private DocletOptionFile optionStylesheetFile =
3359      new DocletOptionFile("-stylesheetfile");
3360
3361    private DocletOptionFlag optionLinkSource =
3362      new DocletOptionFlag("-linksource");
3363
3364    private DocletOption optionLink =
3365      new DocletOption("-link") {
3366
3367         public int getLength()
3368         {
3369            return 2;
3370         }
3371
3372         public boolean set(String[] optionArr)
3373         {
3374            externalDocSets.add(new ExternalDocSet(optionArr[1], null));
3375            return true;
3376         }
3377      };
3378
3379    private DocletOption optionLinkOffline =
3380      new DocletOption("-linkoffline") {
3381
3382         public int getLength()
3383         {
3384            return 3;
3385         }
3386
3387         public boolean set(String[] optionArr)
3388         {
3389            externalDocSets.add(new ExternalDocSet(optionArr[1], optionArr[2]));
3390            return true;
3391         }
3392      };
3393
3394    private DocletOptionString optionDocEncoding =
3395      new DocletOptionString("-docencoding");
3396
3397    private DocletOptionString optionEncoding =
3398      new DocletOptionString("-encoding");
3399
3400    private DocletOptionString optionCharset =
3401      new DocletOptionString("-charset");
3402
3403    private DocletOptionFile optionAddStylesheet =
3404      new DocletOptionFile("-addstylesheet");
3405
3406    private DocletOptionFlag optionValidHtml =
3407      new DocletOptionFlag("-validhtml");
3408
3409    private DocletOptionString optionBaseUrl =
3410      new DocletOptionString("-baseurl");
3411
3412    private DocletOption[] options =
3413       {
3414          optionNoNavBar,
3415          optionNoTree,
3416          optionNoDeprecatedList,
3417          optionNoIndex,
3418          optionNoHelp,
3419          optionNoComment,
3420          optionUse,
3421          optionSplitIndex,
3422          optionHeader,
3423          optionFooter,
3424          optionBottom,
3425          optionHelpFile,
3426          optionStylesheetFile,
3427          optionWindowTitle,
3428          optionDocTitle,
3429          optionTitle,
3430          optionLinkSource,
3431          optionLink,
3432          optionLinkOffline,
3433          optionDocEncoding,
3434          optionEncoding,
3435          optionCharset,
3436          optionAddStylesheet,
3437          optionValidHtml,
3438          optionBaseUrl,
3439       };
3440
3441    static {
3442       setInstance(new HtmlDoclet());
3443    }
3444
3445    private static String replaceDocRoot(HtmlPage output, String str)
3446    {
3447       return StringToolkit.replace(str, "{@docRoot}", output.getPathToRoot());
3448    }
3449
3450    private String getOutputDocEncoding()
3451    {
3452       String encoding = optionDocEncoding.getValue();
3453
3454       if (null == encoding) {
3455          encoding = optionEncoding.getValue();
3456       }
3457
3458       return encoding;
3459    }
3460
3461    private String getOutputCharset()
3462    {
3463       if (null == outputCharset) {
3464
3465          if (null != optionCharset.getValue()) {
3466             outputCharset = optionCharset.getValue();
3467          }
3468          else {
3469             String fileEncoding = System.getProperty("file.encoding");
3470             if (null != fileEncoding) {
3471                try {
3472                   outputCharset = Charset.forName(fileEncoding).name();
3473                }
3474                catch (Exception ignore) {
3475                }
3476             }
3477
3478             if (null == outputCharset) {
3479                printWarning("Cannot determine platform default charset, falling back to ISO-8859-1.");
3480                outputCharset = "ISO-8859-1";
3481             }
3482          }
3483       }
3484       return outputCharset;
3485    }
3486
3487    public InlineTagRenderer getInlineTagRenderer()
3488    {
3489       return this;
3490    }
3491
3492    public String renderInlineTags(Tag[] tags, TagletContext context)
3493    {
3494       StringBuffer result = new StringBuffer();
3495
3496       HtmlRepairer repairer = new HtmlRepairer(getRootDoc(),
3497                                                true, false,
3498                                                null, null,
3499                                                true);
3500
3501       for (int i=0; i<tags.length; ++i) {
3502
3503          Tag tag = tags[i];
3504
3505          if ("Text".equals(tag.name())) {
3506             result.append(repairer.getWellformedHTML(tag.text()));
3507          }
3508          else if ("@link".equals(tag.name())) {
3509             result.append(renderSeeTag((SeeTag)tag, context, false));
3510          }
3511          else if ("@linkplain".equals(tag.name())) {
3512             result.append(renderSeeTag((SeeTag)tag, context, true));
3513          }
3514          else if ("@docRoot".equals(tag.name())) {
3515             result.append(((HtmlTagletContext)context).getOutput().getPathToRoot());
3516          }
3517          else {
3518             //TagletContext context = TagletContext.OVERVIEW; // FIXME
3519             Taglet taglet = (Taglet)tagletMap.get(tag.name().substring(1));
3520             if (null != taglet) {
3521                if (taglet instanceof GnuExtendedTaglet) {
3522                   result.append(((GnuExtendedTaglet)taglet).toString(tag, context));
3523                }
3524                else {
3525                   result.append(taglet.toString(tag));
3526                }
3527             }
3528          }
3529       }
3530       result.append(repairer.terminateText());
3531       return result.toString();
3532    }
3533
3534    public String renderSeeTag(SeeTag seeTag, TagletContext context, boolean plainFont)
3535    {
3536       StringBuffer result = new StringBuffer();
3537
3538       String href = null;
3539       String label = null;
3540       MemberDoc referencedMember = seeTag.referencedMember();
3541       if (null != seeTag.referencedClass()) {
3542
3543          href = getClassDocURL(((HtmlTagletContext)context).getOutput(), seeTag.referencedClass());
3544
3545          Doc doc = context.getDoc();
3546          ClassDoc classDoc = null;
3547          if (doc.isClass() || doc.isInterface()) {
3548             classDoc = (ClassDoc)doc;
3549          }
3550          else if (doc.isField() || doc.isMethod() || doc.isConstructor()) {
3551             classDoc = ((MemberDoc)doc).containingClass();
3552          }
3553
3554          if (null == referencedMember
3555              || seeTag.referencedClass() != classDoc
3556              || ((HtmlTagletContext)context).isOnSerializedPage()) {
3557
3558             if (!seeTag.referencedClass().isIncluded()) {
3559                label = possiblyQualifiedName(seeTag.referencedClass());
3560             }
3561             else {
3562                label = seeTag.referencedClass().typeName();
3563             }
3564             if (null != referencedMember) {
3565                label += '.';
3566             }
3567          }
3568          else {
3569             label = "";
3570          }
3571
3572          if (null != referencedMember) {
3573             label += referencedMember.name();
3574             if (referencedMember.isMethod() || referencedMember.isConstructor()) {
3575                label += ((ExecutableMemberDoc)referencedMember).flatSignature();
3576             }
3577             href  += '#' + getMemberAnchor(referencedMember);
3578          }
3579          else if (null != seeTag.referencedMemberName()) {
3580             href = null;
3581          }
3582       }
3583       else {
3584          String referencedClassName = seeTag.referencedClassName();
3585
3586          if (null != referencedClassName) {
3587
3588             String referencedPackageName = null;
3589
3590             Iterator it = packageNameToDocSet.keySet().iterator();
3591             while (it.hasNext()) {
3592                String packageName = (String)it.next();
3593                if ((null == referencedPackageName
3594                     || packageName.length() > referencedPackageName.length())
3595                    && referencedClassName.startsWith(packageName + '.')) {
3596                   referencedPackageName = packageName;
3597                }
3598             }
3599
3600             if (null != referencedPackageName) {
3601                ExternalDocSet externalDocSet
3602                   = (ExternalDocSet)packageNameToDocSet.get(referencedPackageName);
3603
3604                String className = referencedClassName.substring(referencedPackageName.length() + 1);
3605                href = externalDocSet.getClassDocURL(referencedPackageName,
3606                                                     className);
3607                label = className;
3608
3609                String referencedMemberName = seeTag.referencedMemberName();
3610
3611                if (null != referencedMemberName) {
3612                   label += '.';
3613                   label += referencedMemberName;
3614                   href  += '#' + transformReferencedMemberName(referencedMemberName,
3615                                                                externalDocSet.isJavadocCompatible());
3616                }
3617                else if (null != seeTag.referencedMemberName()) {
3618                   href = null;
3619                }
3620             }
3621          }
3622       }
3623
3624       if (null != seeTag.label()
3625           && seeTag.label().length() > 0) {
3626          label = seeTag.label();
3627       }
3628
3629       if (null == label) {
3630          label = seeTag.text();
3631          if (label.startsWith("#")) {
3632             label = label.substring(1);
3633          }
3634          else {
3635             label = label.replace('#', '.');
3636          }
3637          label.trim();
3638       }
3639
3640       if (null != href) {
3641          result.append("<a href=\"");
3642          result.append(href);
3643          result.append("\">");
3644          if (!plainFont) {
3645             result.append("<code>");
3646          }
3647          result.append(label);
3648          if (!plainFont) {
3649             result.append("</code>");
3650          }
3651          result.append("</a>");
3652       }
3653       else {
3654          if (!plainFont) {
3655             result.append("<code>");
3656          }
3657          result.append(label);
3658          if (!plainFont) {
3659             result.append("</code>");
3660          }
3661       }
3662
3663       return result.toString();
3664    }
3665
3666    protected String renderTag(String tagName, Tag[] tags, TagletContext context)
3667    {
3668       Doc doc = context.getDoc();
3669
3670       if ("see".equals(tagName)
3671           && ((tags.length > 0)
3672               || (doc.isClass()
3673                   && (((ClassDoc)doc).isSerializable()
3674                       || ((ClassDoc)doc).isExternalizable())))) {
3675
3676          StringBuffer result = new StringBuffer();
3677          result.append("<dl class=\"tag list\">");
3678          result.append("<dt class=\"tag section header\"><b>");
3679          result.append("See Also:");
3680          result.append("</b></dt>");
3681
3682          boolean oneLine = true;
3683
3684          if (oneLine) {
3685             result.append("<dd>");
3686          }
3687
3688          for (int i = 0; i < tags.length; ++i) {
3689             if (oneLine) {
3690                if (i > 0) {
3691                   result.append(", ");
3692                }
3693             }
3694             else {
3695                result.append("<dd>");
3696             }
3697             result.append(renderSeeTag((SeeTag)tags[i], context, false));
3698             if (!oneLine) {
3699                result.append("</dd>");
3700             }
3701          }
3702
3703          if ((doc instanceof ClassDoc)
3704              && (((ClassDoc)doc).isSerializable() || ((ClassDoc)doc).isExternalizable())) {
3705             if (tags.length > 0) {
3706                result.append(", ");
3707             }
3708             HtmlPage output = ((HtmlTagletContext)context).getOutput();
3709             result.append("<a href=\"" + output.getPathToRoot() + "/serialized-form" + filenameExtension + "#" + ((ClassDoc)doc).qualifiedName() + "\">Serialized Form</a>");
3710          }
3711
3712          if (oneLine) {
3713             result.append("</dd>");
3714          }
3715          result.append("</dl>");
3716          return result.toString();
3717       }
3718       else if (tags.length > 0
3719                && "serial".equals(tagName)
3720                && ((HtmlTagletContext)context).isOnSerializedPage()) {
3721
3722          return renderInlineTags(tags[0].inlineTags(), context);
3723       }
3724       else {
3725          return "";
3726       }
3727    }
3728
3729    private String getWindowTitle()
3730    {
3731       if (null == optionWindowTitle.getValue()) {
3732          return "Generated API Documentation";
3733       }
3734       else {
3735          return optionWindowTitle.getValue();
3736       }
3737    }
3738
3739    private String getPageTitle(String title)
3740    {
3741       if (null == optionWindowTitle.getValue()) {
3742          return title;
3743       }
3744       else {
3745          return title + " (" + optionWindowTitle.getValue() + ")";
3746       }
3747    }
3748
3749    protected String getDocletVersion()
3750    {
3751       if (null == docletVersion) {
3752          docletVersion = gnu.classpath.Configuration.CLASSPATH_VERSION;
3753       }
3754       return docletVersion;
3755    }
3756
3757    private Map getStylesheets()
3758    {
3759       Map sheets = new HashMap();
3760       if (null != optionStylesheetFile.getValue()) {
3761          sheets.put("User-specified", new String[] {
3762             "resources/user.css"
3763          });
3764       }
3765       else {
3766          List cleanSheets = new LinkedList();
3767          cleanSheets.add("resources/gjdochtml-clean-layout.css");
3768          cleanSheets.add("resources/gjdochtml-clean-color1.css");
3769          if (null != optionAddStylesheet.getValue()) {
3770             cleanSheets.add("resources/user.css");
3771          }
3772          sheets.put("GNU Clean", cleanSheets.toArray(new String[0]));
3773       }
3774       return sheets;
3775    }
3776
3777    protected boolean isSinglePackage()
3778    {
3779       if (getRootDoc().firstSentenceTags().length > 0) {
3780          return false;
3781       }
3782       else if (null != optionDocTitle.getValue()
3783                || null != optionTitle.getValue()) {
3784          return false;
3785       }
3786       else {
3787          return super.isSinglePackage();
3788       }
3789    }
3790
3791   private String getTypeParameters(ClassDoc classDoc)
3792   {
3793     String parameters = "";
3794     TypeVariable[] params = classDoc.typeParameters();
3795     if (params != null && params.length > 0)
3796       {
3797         parameters = "&lt;";
3798         for (int a = 0; a < params.length; ++a)
3799           {
3800             parameters += params[a].typeName();
3801             Type[] bounds = params[a].bounds();
3802             if (bounds != null)
3803               {
3804                 parameters += " extends ";
3805                 for (int b = 0; a < bounds.length; ++b)
3806                   {
3807                     parameters += bounds[a];
3808                     if (b != bounds.length - 1)
3809                       parameters += " & ";
3810                   }
3811               }
3812             if (a != params.length - 1)
3813               parameters += ",";
3814           }
3815         parameters += "&gt;";
3816       }
3817     return parameters;
3818   }
3819
3820    private String transformReferencedMemberName(String referencedMemberName,
3821                                                 boolean javadocCompatibility)
3822    {
3823       if (!javadocCompatibility) {
3824          StringBuffer result = new StringBuffer();
3825          for (int i=0; i<referencedMemberName.length(); ++i) {
3826             char c = referencedMemberName.charAt(i);
3827             switch (c) {
3828             case '(': result.append(':'); break;
3829             case ')': break;
3830             case ',': result.append(':'); break;
3831             case '[': result.append('-'); break;
3832             case ']': break;
3833             default:  result.append(c); break;
3834             }
3835          }
3836          return result.toString();
3837       }
3838       else {
3839          return referencedMemberName;
3840       }
3841    }
3842
3843    public void writeGjdocProperties(File outputFile)
3844       throws IOException
3845    {
3846       Properties properties = new Properties();
3847       properties.setProperty("gjdoc.version", getDocletVersion());
3848       properties.setProperty("gjdoc.compat", Boolean.toString(isJavadocCompatibleNames()));
3849
3850       FileOutputStream out = new FileOutputStream(outputFile);
3851       properties.store(out, "GNU Gjdoc API Documentation Set Descriptor");
3852       out.close();
3853    }
3854
3855    public boolean isJavadocCompatibleNames()
3856    {
3857       return !optionValidHtml.getValue();
3858    }
3859
3860    private HtmlPage newHtmlPage(File file,
3861                                 String pathToRoot)
3862       throws IOException
3863    {
3864       return new HtmlPage(file,
3865                           pathToRoot,
3866                           getOutputDocEncoding(),
3867                           optionBaseUrl.getValue(),
3868                           getTargetDirectory());
3869    }
3870
3871    private HtmlPage newHtmlPage(File file,
3872                                 String pathToRoot,
3873                                 String docType)
3874       throws IOException
3875    {
3876       return new HtmlPage(file,
3877                           pathToRoot,
3878                           getOutputDocEncoding(),
3879                           optionBaseUrl.getValue(),
3880                           getTargetDirectory(),
3881                           docType);
3882    }
3883 }