1/*
2 * Copyright (c) 1997, 2017, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.  Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26package jdk.javadoc.internal.doclets.formats.html;
27
28import java.util.*;
29
30import javax.lang.model.element.ModuleElement;
31import javax.lang.model.element.PackageElement;
32import javax.lang.model.element.TypeElement;
33
34import jdk.javadoc.doclet.DocletEnvironment;
35import jdk.javadoc.doclet.Reporter;
36import jdk.javadoc.internal.doclets.toolkit.AbstractDoclet;
37import jdk.javadoc.internal.doclets.toolkit.DocletException;
38import jdk.javadoc.internal.doclets.toolkit.Messages;
39import jdk.javadoc.internal.doclets.toolkit.builders.AbstractBuilder;
40import jdk.javadoc.internal.doclets.toolkit.util.ClassTree;
41import jdk.javadoc.internal.doclets.toolkit.util.DocFile;
42import jdk.javadoc.internal.doclets.toolkit.util.DocFileIOException;
43import jdk.javadoc.internal.doclets.toolkit.util.DocPath;
44import jdk.javadoc.internal.doclets.toolkit.util.DocPaths;
45import jdk.javadoc.internal.doclets.toolkit.util.IndexBuilder;
46
47/**
48 * The class with "start" method, calls individual Writers.
49 *
50 *  <p><b>This is NOT part of any supported API.
51 *  If you write code that depends on this, you do so at your own risk.
52 *  This code and its internal interfaces are subject to change or
53 *  deletion without notice.</b>
54 *
55 * @author Atul M Dambalkar
56 * @author Robert Field
57 * @author Jamie Ho
58 *
59 */
60public class HtmlDoclet extends AbstractDoclet {
61
62    public HtmlDoclet() {
63        configuration = new HtmlConfiguration(this);
64    }
65
66    @Override // defined by Doclet
67    public String getName() {
68        return "Html";
69    }
70
71    /**
72     * The global configuration information for this run.
73     */
74    private final HtmlConfiguration configuration;
75
76    private Messages messages;
77
78
79    private static final DocPath DOCLET_RESOURCES = DocPath
80            .create("/jdk/javadoc/internal/doclets/formats/html/resources");
81
82    @Override // defined by Doclet
83    public void init(Locale locale, Reporter reporter) {
84        configuration.reporter = reporter;
85        configuration.locale = locale;
86        messages = configuration.getMessages();
87    }
88
89    /**
90     * Create the configuration instance.
91     * Override this method to use a different
92     * configuration.
93     *
94     * @return the configuration
95     */
96    @Override // defined by AbstractDoclet
97    public HtmlConfiguration getConfiguration() {
98        return configuration;
99    }
100
101    /**
102     * Start the generation of files. Call generate methods in the individual
103     * writers, which will in turn generate the documentation files. Call the
104     * TreeWriter generation first to ensure the Class Hierarchy is built
105     * first and then can be used in the later generation.
106     *
107     * For new format.
108     *
109     * @throws DocletException if there is a problem while writing the other files
110     * @see jdk.doclet.DocletEnvironment
111     */
112    @Override // defined by AbstractDoclet
113    protected void generateOtherFiles(DocletEnvironment docEnv, ClassTree classtree)
114            throws DocletException {
115        super.generateOtherFiles(docEnv, classtree);
116        if (configuration.linksource) {
117            SourceToHTMLConverter.convertRoot(configuration,
118                docEnv, DocPaths.SOURCE_OUTPUT);
119        }
120
121        if (configuration.topFile.isEmpty()) {
122            messages.error("doclet.No_Non_Deprecated_Classes_To_Document");
123            return;
124        }
125        boolean nodeprecated = configuration.nodeprecated;
126        performCopy(configuration.helpfile);
127        performCopy(configuration.stylesheetfile);
128        // do early to reduce memory footprint
129        if (configuration.classuse) {
130            ClassUseWriter.generate(configuration, classtree);
131        }
132        IndexBuilder indexbuilder = new IndexBuilder(configuration, nodeprecated);
133
134        if (configuration.createtree) {
135            TreeWriter.generate(configuration, classtree);
136        }
137        if (configuration.createindex) {
138            configuration.buildSearchTagIndex();
139            if (configuration.splitindex) {
140                SplitIndexWriter.generate(configuration, indexbuilder);
141            } else {
142                SingleIndexWriter.generate(configuration, indexbuilder);
143            }
144        }
145
146        if (!(configuration.nodeprecatedlist || nodeprecated)) {
147            DeprecatedListWriter.generate(configuration);
148        }
149
150        AllClassesFrameWriter.generate(configuration,
151            new IndexBuilder(configuration, nodeprecated, true));
152
153        if (configuration.frames) {
154            FrameOutputWriter.generate(configuration);
155        }
156
157        if (configuration.createoverview) {
158            if (configuration.showModules) {
159                ModuleIndexWriter.generate(configuration);
160            } else {
161                PackageIndexWriter.generate(configuration);
162            }
163        }
164
165        if (!configuration.frames && !configuration.createoverview) {
166            IndexRedirectWriter.generate(configuration);
167        }
168
169        if (configuration.helpfile.isEmpty() && !configuration.nohelp) {
170            HelpWriter.generate(configuration);
171        }
172        // If a stylesheet file is not specified, copy the default stylesheet
173        // and replace newline with platform-specific newline.
174        DocFile f;
175        if (configuration.stylesheetfile.length() == 0) {
176            f = DocFile.createFileForOutput(configuration, DocPaths.STYLESHEET);
177            f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.STYLESHEET), false, true);
178        }
179        f = DocFile.createFileForOutput(configuration, DocPaths.JAVASCRIPT);
180        f.copyResource(DocPaths.RESOURCES.resolve(DocPaths.JAVASCRIPT), true, true);
181        if (configuration.createindex) {
182            f = DocFile.createFileForOutput(configuration, DocPaths.SEARCH_JS);
183            f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.SEARCH_JS), true, true);
184
185            f = DocFile.createFileForOutput(configuration, DocPaths.RESOURCES.resolve(DocPaths.GLASS_IMG));
186            f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.GLASS_IMG), true, false);
187
188            f = DocFile.createFileForOutput(configuration, DocPaths.RESOURCES.resolve(DocPaths.X_IMG));
189            f.copyResource(DOCLET_RESOURCES.resolve(DocPaths.X_IMG), true, false);
190            copyJqueryFiles();
191        }
192    }
193
194    protected void copyJqueryFiles() throws DocletException {
195        List<String> files = Arrays.asList(
196                "jquery-1.10.2.js",
197                "jquery-ui.js",
198                "jquery-ui.css",
199                "jquery-ui.min.js",
200                "jquery-ui.min.css",
201                "jquery-ui.structure.min.css",
202                "jquery-ui.structure.css",
203                "external/jquery/jquery.js",
204                "jszip/dist/jszip.js",
205                "jszip/dist/jszip.min.js",
206                "jszip-utils/dist/jszip-utils.js",
207                "jszip-utils/dist/jszip-utils.min.js",
208                "jszip-utils/dist/jszip-utils-ie.js",
209                "jszip-utils/dist/jszip-utils-ie.min.js",
210                "images/ui-bg_flat_0_aaaaaa_40x100.png",
211                "images/ui-icons_454545_256x240.png",
212                "images/ui-bg_glass_95_fef1ec_1x400.png",
213                "images/ui-bg_glass_75_dadada_1x400.png",
214                "images/ui-bg_highlight-soft_75_cccccc_1x100.png",
215                "images/ui-icons_888888_256x240.png",
216                "images/ui-icons_2e83ff_256x240.png",
217                "images/ui-bg_glass_65_ffffff_1x400.png",
218                "images/ui-icons_cd0a0a_256x240.png",
219                "images/ui-bg_glass_55_fbf9ee_1x400.png",
220                "images/ui-icons_222222_256x240.png",
221                "images/ui-bg_glass_75_e6e6e6_1x400.png",
222                "images/ui-bg_flat_75_ffffff_40x100.png");
223        DocFile f;
224        for (String file : files) {
225            DocPath filePath = DocPaths.JQUERY_FILES.resolve(file);
226            f = DocFile.createFileForOutput(configuration, filePath);
227            f.copyResource(DOCLET_RESOURCES.resolve(filePath), true, false);
228        }
229    }
230
231    /**
232     * {@inheritDoc}
233     */
234    @Override // defined by AbstractDoclet
235    protected void generateClassFiles(SortedSet<TypeElement> arr, ClassTree classtree)
236            throws DocletException {
237        List<TypeElement> list = new ArrayList<>(arr);
238        ListIterator<TypeElement> iterator = list.listIterator();
239        TypeElement klass = null;
240        while (iterator.hasNext()) {
241            TypeElement prev = iterator.hasPrevious() ? klass : null;
242            klass = iterator.next();
243            TypeElement next = iterator.nextIndex() == list.size()
244                    ? null : list.get(iterator.nextIndex());
245
246            if (utils.isHidden(klass) ||
247                    !(configuration.isGeneratedDoc(klass) && utils.isIncluded(klass))) {
248                continue;
249            }
250
251            if (utils.isAnnotationType(klass)) {
252                AbstractBuilder annotationTypeBuilder =
253                    configuration.getBuilderFactory()
254                        .getAnnotationTypeBuilder(klass,
255                            prev == null ? null : prev.asType(),
256                            next == null ? null : next.asType());
257                annotationTypeBuilder.build();
258            } else {
259                AbstractBuilder classBuilder =
260                    configuration.getBuilderFactory().getClassBuilder(klass,
261                            prev, next, classtree);
262                classBuilder.build();
263            }
264        }
265    }
266
267    /**
268     * {@inheritDoc}
269     */
270    @Override // defined by AbstractDoclet
271    protected void generateModuleFiles() throws DocletException {
272        if (configuration.showModules) {
273            if (configuration.frames  && configuration.modules.size() > 1) {
274                ModuleIndexFrameWriter.generate(configuration);
275            }
276            ModuleElement prevModule = null, nextModule;
277            List<ModuleElement> mdles = new ArrayList<>(configuration.modulePackages.keySet());
278            int i = 0;
279            for (ModuleElement mdle : mdles) {
280                if (configuration.frames && configuration.modules.size() > 1) {
281                    ModulePackageIndexFrameWriter.generate(configuration, mdle);
282                    ModuleFrameWriter.generate(configuration, mdle);
283                }
284                nextModule = (i + 1 < mdles.size()) ? mdles.get(i + 1) : null;
285                AbstractBuilder moduleSummaryBuilder =
286                        configuration.getBuilderFactory().getModuleSummaryBuilder(
287                        mdle, prevModule, nextModule);
288                moduleSummaryBuilder.build();
289                prevModule = mdle;
290                i++;
291            }
292        }
293    }
294
295    PackageElement getNamedPackage(List<PackageElement> list, int idx) {
296        if (idx < list.size()) {
297            PackageElement pkg = list.get(idx);
298            if (pkg != null && !pkg.isUnnamed()) {
299                return pkg;
300            }
301        }
302        return null;
303    }
304
305    /**
306     * {@inheritDoc}
307     */
308    @Override // defined by AbstractDoclet
309    protected void generatePackageFiles(ClassTree classtree) throws DocletException {
310        Set<PackageElement> packages = configuration.packages;
311        if (packages.size() > 1 && configuration.frames) {
312            PackageIndexFrameWriter.generate(configuration);
313        }
314        List<PackageElement> pList = new ArrayList<>(packages);
315        PackageElement prev = null;
316        for (int i = 0 ; i < pList.size() ; i++) {
317            // if -nodeprecated option is set and the package is marked as
318            // deprecated, do not generate the package-summary.html, package-frame.html
319            // and package-tree.html pages for that package.
320            PackageElement pkg = pList.get(i);
321            if (!(configuration.nodeprecated && utils.isDeprecated(pkg))) {
322                if (configuration.frames) {
323                    PackageFrameWriter.generate(configuration, pkg);
324                }
325                int nexti = i + 1;
326                PackageElement next = null;
327                if (nexti < pList.size()) {
328                    next = pList.get(nexti);
329                    // If the next package is unnamed package, skip 2 ahead if possible
330                    if (next.isUnnamed() && ++nexti < pList.size()) {
331                       next = pList.get(nexti);
332                    }
333                }
334                AbstractBuilder packageSummaryBuilder =
335                        configuration.getBuilderFactory().getPackageSummaryBuilder(
336                        pkg, prev, next);
337                packageSummaryBuilder.build();
338                if (configuration.createtree) {
339                    PackageTreeWriter.generate(configuration, pkg, prev, next,
340                            configuration.nodeprecated);
341                }
342                prev = pkg;
343            }
344        }
345    }
346
347    @Override // defined by Doclet
348    public Set<Option> getSupportedOptions() {
349        return configuration.getSupportedOptions();
350    }
351
352    private void performCopy(String filename) throws DocFileIOException {
353        if (filename.isEmpty())
354            return;
355
356        DocFile fromfile = DocFile.createFileForInput(configuration, filename);
357        DocPath path = DocPath.create(fromfile.getName());
358        DocFile toFile = DocFile.createFileForOutput(configuration, path);
359        if (toFile.isSameFile(fromfile))
360            return;
361
362        messages.notice("doclet.Copying_File_0_To_File_1",
363                fromfile.toString(), path.getPath());
364        toFile.copyFile(fromfile);
365    }
366}
367