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