001/* 002 * Copyright (c) 1998, 2022, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package org.jdrupes.mdoclet.internal.doclets.formats.html; 027 028import java.util.List; 029import javax.lang.model.element.Element; 030 031import org.jdrupes.mdoclet.internal.doclets.formats.html.Navigation.PageMode; 032import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.BodyContents; 033import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.ContentBuilder; 034import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlId; 035import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlStyle; 036import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.HtmlTree; 037import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.TagName; 038import org.jdrupes.mdoclet.internal.doclets.formats.html.markup.Text; 039import org.jdrupes.mdoclet.internal.doclets.toolkit.Content; 040import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocFileIOException; 041import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocLink; 042import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPath; 043import org.jdrupes.mdoclet.internal.doclets.toolkit.util.DocPaths; 044 045/** 046 * Generate the Help File for the generated API documentation. The help file 047 * contents are helpful for browsing the generated documentation. 048 */ 049public class HelpWriter extends HtmlDocletWriter { 050 051 private final String[][] SEARCH_EXAMPLES = { 052 { "\"j.l.obj\"", "\"java.lang.Object\"" }, 053 { "\"InpStr\"", "\"java.io.InputStream\"" }, 054 { "\"math exact long\"", "\"java.lang.Math.absExact(long)\"" } 055 }; 056 057 Content overviewLink; 058 Content indexLink; 059 Content allClassesLink; 060 Content allPackagesLink; 061 062 /** 063 * Constructor to construct HelpWriter object. 064 * @param configuration the configuration 065 * @param filename File to be generated. 066 */ 067 public HelpWriter(HtmlConfiguration configuration, 068 DocPath filename) { 069 super(configuration, filename); 070 071 // yes, INDEX is correct in the following line 072 overviewLink = links.createLink(DocPaths.INDEX, 073 resources.getText("doclet.Overview")); 074 allPackagesLink = links.createLink(DocPaths.ALLPACKAGES_INDEX, 075 resources.getText("doclet.All_Packages")); 076 allClassesLink = links.createLink(DocPaths.ALLCLASSES_INDEX, 077 resources.getText("doclet.All_Classes_And_Interfaces")); 078 DocPath dp = options.splitIndex() 079 ? DocPaths.INDEX_FILES.resolve(DocPaths.indexN(1)) 080 : DocPaths.INDEX_ALL; 081 indexLink = links.createLink(dp, resources.getText("doclet.Index")); 082 } 083 084 /** 085 * Construct the HelpWriter object and then use it to generate the help 086 * file. The name of the generated file is "help-doc.html". The help file 087 * will get generated if and only if "-helpfile" and "-nohelp" is not used 088 * on the command line. 089 * 090 * @param configuration the configuration 091 * @throws DocFileIOException if there is a problem while generating the documentation 092 */ 093 public static void generate(HtmlConfiguration configuration) 094 throws DocFileIOException { 095 DocPath filename = DocPaths.HELP_DOC; 096 HelpWriter helpgen = new HelpWriter(configuration, filename); 097 helpgen.generateHelpFile(); 098 } 099 100 /** 101 * Generate the help file contents. 102 * 103 * @throws DocFileIOException if there is a problem while generating the documentation 104 */ 105 protected void generateHelpFile() throws DocFileIOException { 106 String title = resources.getText("doclet.Window_Help_title"); 107 HtmlTree body = getBody(getWindowTitle(title)); 108 ContentBuilder helpFileContent = new ContentBuilder(); 109 addHelpFileContents(helpFileContent); 110 body.add(new BodyContents() 111 .setHeader(getHeader(PageMode.HELP)) 112 .addMainContent(helpFileContent) 113 .setFooter(getFooter())); 114 printHtmlDocument(null, "help", body); 115 } 116 117 /** 118 * Adds the help file contents from the resource file to the content. 119 * While adding the help file contents it also keeps track of user options. 120 * 121 * The general organization is: 122 * <ul> 123 * <li>Heading, and TOC 124 * <li>Navigation help 125 * <li>Page-specific help 126 * </ul> 127 */ 128 protected void addHelpFileContents(Content content) { 129 var mainTOC = HtmlTree.UL(HtmlStyle.helpTOC); 130 131 content 132 .add(HtmlTree.HEADING(Headings.PAGE_TITLE_HEADING, HtmlStyle.title, 133 getContent("doclet.help.main_heading"))) 134 .add(mainTOC) 135 .add(new HtmlTree(TagName.HR)) 136 .add(getNavigationSection(mainTOC)) 137 .add(new HtmlTree(TagName.HR)) 138 .add(getPageKindSection(mainTOC)) 139 .add(new HtmlTree(TagName.HR)) 140 .add(HtmlTree.SPAN(HtmlStyle.helpFootnote, 141 getContent("doclet.help.footnote"))); 142 } 143 144 @Override 145 protected Navigation getNavBar(PageMode pageMode, Element element) { 146 return super.getNavBar(pageMode, element) 147 .setSubNavLinks(() -> List.of( 148 links.createLink(HtmlIds.HELP_NAVIGATION, 149 contents.navHelpNavigation), 150 links.createLink(HtmlIds.HELP_PAGES, contents.navHelpPages))); 151 } 152 153 /** 154 * Creates the navigation help, adding an entry into the main table-of-contents. 155 * 156 * The general organization is: 157 * <ul> 158 * <li>General notes 159 * <li>Search 160 * </ul> 161 * 162 * @param mainTOC the main table-of-contents 163 * 164 * @return the content containing the help 165 */ 166 private Content getNavigationSection(HtmlTree mainTOC) { 167 Content content = new ContentBuilder(); 168 169 Content navHeading = contents.getContent("doclet.help.navigation.head"); 170 var navSection = HtmlTree.DIV(HtmlStyle.subTitle) 171 .add(HtmlTree.HEADING(Headings.CONTENT_HEADING, navHeading) 172 .setId(HtmlIds.HELP_NAVIGATION)) 173 .add(contents.getContent("doclet.help.navigation.intro", 174 overviewLink)); 175 if (options.createIndex()) { 176 Content links = new ContentBuilder(); 177 if (!configuration.packages.isEmpty()) { 178 links.add(allPackagesLink); 179 links.add(", "); 180 } 181 links.add(allClassesLink); 182 navSection.add(" ") 183 .add(contents.getContent("doclet.help.navigation.index", 184 indexLink, links)); 185 } 186 content.add(navSection); 187 188 var subTOC = HtmlTree.UL(HtmlStyle.helpSubTOC); 189 190 HtmlTree section; 191 192 // Search 193 if (options.createIndex()) { 194 section = newHelpSection(getContent("doclet.help.search.head"), 195 PageMode.SEARCH, subTOC); 196 var searchIntro 197 = HtmlTree.P(getContent("doclet.help.search.intro")); 198 var searchExamples = HtmlTree.UL(HtmlStyle.helpSectionList); 199 for (String[] example : SEARCH_EXAMPLES) { 200 searchExamples.add(HtmlTree.LI( 201 getContent("doclet.help.search.example", 202 HtmlTree.CODE(Text.of(example[0])), example[1]))); 203 } 204 var searchSpecLink = HtmlTree.A( 205 resources.getText("doclet.help.search.spec.url", 206 configuration.getDocletVersion().feature()), 207 getContent("doclet.help.search.spec.title")); 208 var searchRefer = HtmlTree 209 .P(getContent("doclet.help.search.refer", searchSpecLink)); 210 section.add(searchIntro) 211 .add(searchExamples) 212 .add(searchRefer); 213 navSection.add(section); 214 } 215 216 mainTOC.add(HtmlTree.LI(new ContentBuilder( 217 links.createLink(DocLink.fragment(HtmlIds.HELP_NAVIGATION.name()), 218 navHeading), 219 Text.of(": "), subTOC))); 220 221 return content; 222 } 223 224 /** 225 * Creates the page-specific help, adding an entry into the main table-of-contents. 226 * 227 * The general organization is: 228 * <ul> 229 * <li>Overview 230 * <li>Declaration pages: module, package, classes 231 * <li>Derived info for declarations: use and tree 232 * <li>General summary info: deprecated, preview 233 * <li>Detailed summary info: constant values, serialized form, system properties 234 * <li>Index info: all packages, all classes, full index 235 * </ul> 236 * 237 * @param mainTOC the main table-of-contents 238 * 239 * @return the content containing the help 240 */ 241 private Content getPageKindSection(HtmlTree mainTOC) { 242 Content pageKindsHeading 243 = contents.getContent("doclet.help.page_kinds.head"); 244 var pageKindsSection = HtmlTree.DIV(HtmlStyle.subTitle) 245 .add(HtmlTree.HEADING(Headings.CONTENT_HEADING, pageKindsHeading) 246 .setId(HtmlIds.HELP_PAGES)) 247 .add(contents.getContent("doclet.help.page_kinds.intro")); 248 249 var subTOC = HtmlTree.UL(HtmlStyle.helpSubTOC); 250 251 HtmlTree section; 252 253 // Overview 254 if (options.createOverview()) { 255 section = newHelpSection(contents.overviewLabel, PageMode.OVERVIEW, 256 subTOC); 257 String overviewKey = configuration.showModules 258 ? "doclet.help.overview.modules.body" 259 : "doclet.help.overview.packages.body"; 260 section.add(HtmlTree.P(getContent(overviewKey, overviewLink))); 261 pageKindsSection.add(section); 262 } 263 264 // Module 265 if (configuration.showModules) { 266 section 267 = newHelpSection(contents.moduleLabel, PageMode.MODULE, subTOC); 268 Content moduleIntro = getContent("doclet.help.module.intro"); 269 var modulePara = HtmlTree.P(moduleIntro); 270 section.add(modulePara) 271 .add(newHelpSectionList( 272 contents.packagesLabel, 273 contents.modulesLabel, 274 contents.servicesLabel)); 275 pageKindsSection.add(section); 276 } 277 278 // Package 279 section 280 = newHelpSection(contents.packageLabel, PageMode.PACKAGE, subTOC) 281 .add(HtmlTree.P(getContent("doclet.help.package.intro"))) 282 .add(newHelpSectionList( 283 contents.interfaces, 284 contents.classes, 285 contents.enums, 286 contents.exceptionClasses, 287 contents.annotationTypes)); 288 pageKindsSection.add(section); 289 290 // Class/interface 291 Content notes = new ContentBuilder( 292 HtmlTree.SPAN(HtmlStyle.helpNote, 293 getContent("doclet.help.class_interface.note")), 294 Text.of(" "), 295 getContent("doclet.help.class_interface.anno"), 296 Text.of(" "), 297 getContent("doclet.help.class_interface.enum"), 298 Text.of(" "), 299 getContent("doclet.help.class_interface.record"), 300 Text.of(" "), 301 getContent("doclet.help.class_interface.property")); 302 303 section = newHelpSection(getContent("doclet.help.class_interface.head"), 304 PageMode.CLASS, subTOC) 305 .add( 306 HtmlTree.P(getContent("doclet.help.class_interface.intro"))) 307 .add(newHelpSectionList( 308 getContent( 309 "doclet.help.class_interface.inheritance_diagram"), 310 getContent("doclet.help.class_interface.subclasses"), 311 getContent("doclet.help.class_interface.subinterfaces"), 312 getContent("doclet.help.class_interface.implementations"), 313 getContent("doclet.help.class_interface.declaration"), 314 getContent("doclet.help.class_interface.description"))) 315 .add(new HtmlTree(TagName.BR)) 316 .add(newHelpSectionList( 317 contents.nestedClassSummary, 318 contents.enumConstantSummary, 319 contents.fieldSummaryLabel, 320 contents.propertySummaryLabel, 321 contents.constructorSummaryLabel, 322 contents.methodSummary, 323 contents.annotateTypeRequiredMemberSummaryLabel, 324 contents.annotateTypeOptionalMemberSummaryLabel)) 325 .add(new HtmlTree(TagName.BR)) 326 .add(newHelpSectionList( 327 contents.enumConstantDetailLabel, 328 contents.fieldDetailsLabel, 329 contents.propertyDetailsLabel, 330 contents.constructorDetailsLabel, 331 contents.methodDetailLabel, 332 contents.annotationTypeMemberDetail)) 333 .add(HtmlTree.P(notes)) 334 .add(HtmlTree 335 .P(getContent("doclet.help.class_interface.member_order"))); 336 pageKindsSection.add(section); 337 338 section = newHelpSection(getContent("doclet.help.other_files.head"), 339 PageMode.DOC_FILE, subTOC) 340 .add(HtmlTree.P(getContent("doclet.help.other_files.body"))); 341 pageKindsSection.add(section); 342 343 // Class Use 344 if (options.classUse()) { 345 section = newHelpSection(getContent("doclet.help.use.head"), 346 PageMode.USE, subTOC) 347 .add(HtmlTree.P(getContent("doclet.help.use.body"))); 348 pageKindsSection.add(section); 349 } 350 351 // Tree 352 if (options.createTree()) { 353 section = newHelpSection(getContent("doclet.help.tree.head"), 354 PageMode.TREE, subTOC); 355 Content treeIntro = getContent("doclet.help.tree.intro", 356 links.createLink(DocPaths.OVERVIEW_TREE, 357 resources.getText("doclet.Class_Hierarchy")), 358 HtmlTree.CODE(Text.of("java.lang.Object"))); 359 section.add(HtmlTree.P(treeIntro)) 360 .add(newHelpSectionList( 361 getContent("doclet.help.tree.overview"), 362 getContent("doclet.help.tree.package"))); 363 pageKindsSection.add(section); 364 } 365 366 // Preview 367 if (configuration.conditionalPages 368 .contains(HtmlConfiguration.ConditionalPage.PREVIEW)) { 369 section 370 = newHelpSection(contents.previewAPI, PageMode.PREVIEW, subTOC); 371 Content previewBody = getContent("doclet.help.preview.body", 372 links.createLink(DocPaths.PREVIEW_LIST, contents.previewAPI)); 373 section.add(HtmlTree.P(previewBody)); 374 pageKindsSection.add(section); 375 } 376 377 // New 378 if (configuration.conditionalPages 379 .contains(HtmlConfiguration.ConditionalPage.NEW)) { 380 section = newHelpSection(contents.newAPI, PageMode.NEW, subTOC); 381 Content newBody = getContent("doclet.help.new.body", 382 links.createLink(DocPaths.NEW_LIST, contents.newAPI)); 383 section.add(HtmlTree.P(newBody)); 384 pageKindsSection.add(section); 385 } 386 387 // Deprecated 388 if (configuration.conditionalPages 389 .contains(HtmlConfiguration.ConditionalPage.DEPRECATED)) { 390 section = newHelpSection(contents.deprecatedAPI, 391 PageMode.DEPRECATED, subTOC); 392 Content deprBody = getContent("doclet.help.deprecated.body", 393 links.createLink(DocPaths.DEPRECATED_LIST, 394 resources.getText("doclet.Deprecated_API"))); 395 section.add(HtmlTree.P(deprBody)); 396 pageKindsSection.add(section); 397 } 398 399 // Constant Field Values 400 if (configuration.conditionalPages 401 .contains(HtmlConfiguration.ConditionalPage.CONSTANT_VALUES)) { 402 section = newHelpSection(contents.constantsSummaryTitle, 403 PageMode.CONSTANT_VALUES, subTOC); 404 Content constantsBody = getContent("doclet.help.constants.body", 405 links.createLink(DocPaths.CONSTANT_VALUES, 406 resources.getText("doclet.Constants_Summary"))); 407 section.add(HtmlTree.P(constantsBody)); 408 pageKindsSection.add(section); 409 } 410 411 // Serialized Form 412 if (configuration.conditionalPages 413 .contains(HtmlConfiguration.ConditionalPage.SERIALIZED_FORM)) { 414 section = newHelpSection(contents.serializedForm, 415 PageMode.SERIALIZED_FORM, subTOC) 416 .add( 417 HtmlTree.P(getContent("doclet.help.serial_form.body"))); 418 pageKindsSection.add(section); 419 } 420 421 // System Properties 422 if (configuration.conditionalPages 423 .contains(HtmlConfiguration.ConditionalPage.SYSTEM_PROPERTIES)) { 424 section = newHelpSection(contents.systemPropertiesLabel, 425 PageMode.SYSTEM_PROPERTIES, subTOC); 426 Content sysPropsBody 427 = getContent("doclet.help.systemProperties.body", 428 links.createLink(DocPaths.SYSTEM_PROPERTIES, 429 resources.getText("doclet.systemProperties"))); 430 section.add(HtmlTree.P(sysPropsBody)); 431 pageKindsSection.add(section); 432 } 433 434 // External Specification 435 if (configuration.conditionalPages 436 .contains(HtmlConfiguration.ConditionalPage.EXTERNAL_SPECS)) { 437 section = newHelpSection(contents.externalSpecifications, 438 PageMode.EXTERNAL_SPECS, subTOC); 439 Content extSpecsBody 440 = getContent("doclet.help.externalSpecifications.body", 441 links.createLink(DocPaths.EXTERNAL_SPECS, 442 resources.getText("doclet.External_Specifications"))); 443 section.add(HtmlTree.P(extSpecsBody)); 444 pageKindsSection.add(section); 445 } 446 447 // Index 448 if (options.createIndex()) { 449 if (!configuration.packages.isEmpty()) { 450 section = newHelpSection( 451 getContent("doclet.help.all_packages.head"), 452 PageMode.ALL_PACKAGES, subTOC) 453 .add(HtmlTree.P(getContent( 454 "doclet.help.all_packages.body", allPackagesLink))); 455 pageKindsSection.add(section); 456 } 457 458 section = newHelpSection(getContent("doclet.help.all_classes.head"), 459 PageMode.ALL_CLASSES, subTOC) 460 .add(HtmlTree.P(getContent("doclet.help.all_classes.body", 461 allClassesLink))); 462 pageKindsSection.add(section); 463 464 Content links = new ContentBuilder(); 465 if (!configuration.packages.isEmpty()) { 466 links.add(allPackagesLink); 467 links.add(", "); 468 } 469 links.add(allClassesLink); 470 section = newHelpSection(getContent("doclet.help.index.head"), 471 PageMode.INDEX, subTOC) 472 .add(HtmlTree.P(getContent("doclet.help.index.body", 473 indexLink, links))); 474 pageKindsSection.add(section); 475 } 476 477 mainTOC.add(HtmlTree.LI(new ContentBuilder( 478 links.createLink(DocLink.fragment(HtmlIds.HELP_PAGES.name()), 479 pageKindsHeading), 480 Text.of(": "), subTOC))); 481 482 return pageKindsSection; 483 } 484 485 private Content getContent(String key) { 486 return contents.getContent(key); 487 } 488 489 private Content getContent(String key, Object arg) { 490 return contents.getContent(key, arg); 491 } 492 493 private Content getContent(String key, Object arg1, Object arg2) { 494 return contents.getContent(key, arg1, arg2); 495 } 496 497 private HtmlTree newHelpSection(Content headingContent, HtmlTree toc, 498 HtmlId id) { 499 Content link 500 = links.createLink(DocLink.fragment(id.name()), headingContent); 501 toc.add(HtmlTree.LI(link)); 502 503 return HtmlTree.SECTION(HtmlStyle.helpSection, 504 HtmlTree.HEADING(Headings.SUB_HEADING, headingContent)) 505 .setId(id); 506 } 507 508 private HtmlTree newHelpSection(Content headingContent, 509 Navigation.PageMode pm, HtmlTree toc) { 510 return newHelpSection(headingContent, toc, htmlIds.forPage(pm)); 511 } 512 513 private HtmlTree newHelpSectionList(Content first, Content... rest) { 514 var list = HtmlTree.UL(HtmlStyle.helpSectionList, HtmlTree.LI(first)); 515 List.of(rest).forEach(i -> list.add(HtmlTree.LI(i))); 516 return list; 517 } 518}