/*
* Copyright (c) 2007 BUSINESS OBJECTS SOFTWARE LIMITED
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of Business Objects nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/*
* HTMLDocumentationGenerator.java
* Creation date: Sep 27, 2005.
* By: Joseph Wong
*/
package org.openquark.cal.caldoc;
import java.text.BreakIterator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import javax.swing.text.html.CSS;
import javax.swing.text.html.HTML;
import org.openquark.cal.caldoc.CALDocToHTMLUtilities.ContentConvertibleToHTML;
import org.openquark.cal.caldoc.CALDocToHTMLUtilities.SimpleStringContent;
import org.openquark.cal.caldoc.CALDocToHTMLUtilities.SingleTextBlockContent;
import org.openquark.cal.caldoc.HTMLBuilder.AttributeList;
import org.openquark.cal.compiler.CALDocComment;
import org.openquark.cal.compiler.ClassInstance;
import org.openquark.cal.compiler.ClassInstanceIdentifier;
import org.openquark.cal.compiler.ClassMethod;
import org.openquark.cal.compiler.DataConstructor;
import org.openquark.cal.compiler.ForeignTypeInfo;
import org.openquark.cal.compiler.Function;
import org.openquark.cal.compiler.FunctionalAgent;
import org.openquark.cal.compiler.IdentifierInfo;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleTypeInfo;
import org.openquark.cal.compiler.QualifiedName;
import org.openquark.cal.compiler.Scope;
import org.openquark.cal.compiler.ScopedEntity;
import org.openquark.cal.compiler.ScopedEntityNamingPolicy;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.compiler.SourceModelTraverser;
import org.openquark.cal.compiler.TypeClass;
import org.openquark.cal.compiler.TypeConstructor;
import org.openquark.cal.compiler.TypeExpr;
import org.openquark.cal.compiler.UnableToResolveForeignEntityException;
import org.openquark.cal.internal.javamodel.JavaTypeName;
import org.openquark.cal.metadata.ArgumentMetadata;
import org.openquark.cal.metadata.CALFeatureMetadata;
import org.openquark.cal.metadata.ClassMethodMetadata;
import org.openquark.cal.metadata.FunctionMetadata;
import org.openquark.cal.metadata.FunctionalAgentMetadata;
import org.openquark.cal.metadata.InstanceMethodMetadata;
import org.openquark.cal.metadata.MetadataManager;
import org.openquark.cal.metadata.ScopedEntityMetadata;
import org.openquark.cal.module.Cal.Core.CAL_Prelude;
import org.openquark.cal.services.CALFeatureName;
import org.openquark.cal.services.CALWorkspace;
import org.openquark.cal.services.FeatureName;
import org.openquark.cal.services.LocaleUtilities;
import org.openquark.cal.services.ProgramModelManager;
import org.openquark.cal.services.WorkspaceManager;
import org.openquark.util.Pair;
/**
* This class implements the facility of converting CALDoc and metadata into HTML documentation.
* <p>
*
* Currently, the files that are generated include:
* <ul>
* <li>one CSS file for formatting for regular display
* <li>one CSS file for formatting for printing
* <li>a frameset
* <li>an overview page
* <li>a modules list
* <li>a cross-module search page
* <li>per module:
* <ul>
* <li>the module's main documentation page
* <li>a types list
* <li>a functional agents list
* <li>a type classes list
* <li>a class instances list
* </ul>
* <li>one usage indices page per type
* <li>one usage indices page per type class
* </ul>
*
* Not being public, this class is not mean to be accessed directly. To access this generator, go through the
* public interface encapsulated by CALDocTool.
* <p>
*
* A substantial portion of the high level traversal logic is encapsulated in the superclass, and as such this
* class's main focus is implementing the specific details of formatting the output in HTML. The class is organized
* in a way that is similar to a visitor in the visitor pattern, in that the implementation of the abstract methods
* are called to "visit" a particular CAL entity to generate its documentation.
* <p>
*
* The current visitation pattern is:
* <pre>
* generateDoc
* - for each module: prepareGenerationForModule
*
* beginDoc
*
* generateModuleDoc
* beginModuleDoc
*
* generateModuleHeaderSection
* generateModuleDescription
* beginImportedModulesList
* generateImportedModule
* endImportedModuleList
* beginFriendModulesList
* generateFriendModule
* endFriendModuleList
* beginDirectlyDependentModulesList
* generateDirectlyDependentModule
* endDirectlyDependentModulesList
* beginIndirectlyDependentModulesList
* generateIndirectlyDependentModule
* endIndirectlyDependentModulesList
*
* generateModuleOverviewSection
* beginModuleOverviewSection
*
* beginTypeConsOverviewSection
* generateTypeConsOverview
* generateTypeConsOverviewHeader
* beginDataConsOverviewList
* generateDataConsOverview
* endDataConsOverviewList
* generateTypeConsOverviewFooter
* endTypeConsOverviewSection
*
* beginFunctionsOverviewSection
* generateFunctionOverview
* endFunctionsOverviewSection
*
* beginTypeClassOverviewSection
* generateTypeClassOverview
* generateTypeClassOverviewHeader
* beginClassMethodOverviewList
* generateClassMethodOverview
* endClassMethodOverviewList
* generateTypeClassOverviewFooter
* endTypeClassOverviewSection
*
* beginClassInstancesOverviewSection
* generateClassInstanceOverview
* generateClassInstanceOverviewHeader
* beginInstanceMethodOverviewList
* generateInstanceMethodOverview
* endInstanceMethodOverviewList
* generateClassInstanceOverviewFooter
* endClassInstancesOverviewSection
*
* endModuleOverviewSection
*
* generateModuleDetailsSection
* generateTypeConsDocSection
* beginTypeConsDocSection
*
* generateTypeConsDoc
* generateTypeConsDocHeader
*
* beginDataConsDocList
* generateDataConsDoc
* endDataConsDocList
*
* beginKnownInstancesList
* generateKnownInstance
* endKnownInstancesList
*
* generateTypeConsDocFooter
*
* endTypeConsDocSection
*
* generateFunctionsDocSection
* beginFunctionsDocSection
*
* generateFunctionDoc
*
* endFunctionsDocSection
*
* generateTypeClassesDocSection
* beginTypeClassesDocSection
*
* generateTypeClassDoc
* generateTypeClassDocHeader
*
* beginClassMethodDocList
* generateClassMethodDoc
* endClassMethodDocList
*
* beginKnownInstancesList
* generateKnownInstance
* endKnownInstancesList
*
* generateTypeClassDocFooter
*
* endTypeClassesDocSection
*
* generateClassInstancesDocSection
* beginClassInstancesDocSection
*
* generateClassInstanceDoc
* generateClassInstanceDocHeader
*
* beginInstanceMethodDocList
* generateInstanceMethodDoc
* endInstanceMethodDocList
*
* generateClassInstanceDocFooter
*
* endClassInstancesDocSection
*
* endModuleDoc
*
* genereateUsageIndices
* beginTypeConsUsageDoc
*
* generateUsageIndiciesForTypeConsOrTypeClass
* generateUsageIndiciesForDependentModule
* beginUsageDocGroupForDependentModule
*
* beginUsageDocArgTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocArgTypeIndex
*
* beginUsageDocReturnTypeIndex
* generateUsageDocReturnTypeIndexEntry
* endUsageDocReturnTypeIndex
*
* beginUsageDocInstanceIndex
* generateUsageDocInstanceIndexEntry
* endUsageDocInstanceIndex
*
* endUsageDocGroupForDependentModule
*
* endTypeConsUsageDoc
*
* beginTypeClassUsageDoc
*
* generateUsageIndiciesForTypeConsOrTypeClass
* generateUsageIndiciesForDependentModule
* beginUsageDocGroupForDependentModule
*
* beginUsageDocArgTypeIndex
* generateUsageDocArgTypeIndexEntry
* endUsageDocArgTypeIndex
*
* beginUsageDocReturnTypeIndex
* generateUsageDocReturnTypeIndexEntry
* endUsageDocReturnTypeIndex
*
* beginUsageDocInstanceIndex
* generateUsageDocInstanceIndexEntry
* endUsageDocInstanceIndex
*
* endUsageDocGroupForDependentModule
*
* endTypeClassUsageDoc
*
* endDoc
* </pre>
*
* @see CALDocTool
*
* @author Joseph Wong
*/
final class HTMLDocumentationGenerator extends AbstractDocumentationGenerator {
/** The name of the subdirectory containing the main documentation pages for the modules. */
private static final String MODULES_SUBDIRECTORY = "modules";
/** The name of the subdirectory containing the usage pages for types. */
private static final String TYPE_CONS_USAGE_SUBDIRECTORY = "types";
/** The name of the subdirectory containing the usage pages for type classes. */
private static final String TYPE_CLASS_USAGE_SUBDIRECTORY = "typeClasses";
/** The name of the subdirectory containing instance documentation that is separated from the main documentation pages. */
private static final String SEPARATE_INSTANCE_DOC_SUBDIRECTORY = "instances";
/** The name of the subdirectory containing the intra-module navigation pages. */
private static final String NAV_SUBDIRECTORY = "nav";
/** The dot used in constructing file names */
private static final String DOT = ".";
/** The separator between the main part of a file name and the postfix, which comes before the extension. */
private static final String FILENAME_POSTFIX_SEPARATOR = "-";
/** The file name postfix for the instance index of a module. */
private static final String INSTANCE_INDEX_FILENAME_POSTFIX = "instanceIndex";
/** The file name postfix for the type class index of a module. */
private static final String TYPE_CLASS_INDEX_FILENAME_POSTFIX = "typeClassIndex";
/** The file name postfix for the functional agent index of a module. */
private static final String FUNCTIONAL_AGENT_INDEX_FILENAME_POSTFIX = "functionalAgentIndex";
/** The file name postfix for the type index of a module. */
private static final String TYPE_INDEX_FILENAME_POSTFIX = "typeIndex";
/** The file name postfix for the separate instance documentation. */
private static final String SEPARATE_INSTANCE_DOC_FILENAME_POSTFIX = "instances";
/** The file extension for HTML. */
private static final String HTML_FILE_EXTENSION = "html";
/** The name of the default CSS file. */
private static final String DEFAULT_CSS_FILENAME = "caldoc.css";
/** The name of the CSS file for printing. */
private static final String PRINTED_VERSION_CSS_FILENAME = "caldoc-print.css";
/** The name of the main documentation HTML file. */
private static final String MAIN_PAGE_FILENAME = "index.html";
/** The name of the module list HTML file. */
private static final String MODULE_LIST_FILENAME = "moduleList.html";
/** The name of the overview page HTML file. */
private static final String OVERVIEW_PAGE_FILENAME = "overview.html";
/** The name of the master scoped entity index HTML file. */
private static final String MASTER_SCOPED_ENTITY_SEARCH_PAGE_FILENAME = "search.html";
/** The name for the module list frame in its frameset. */
private static final String MODULE_LIST_FRAME_NAME = "moduleListFrame";
/** The name of the navigation frame in its frameset. */
private static final String NAV_FRAME_NAME = "navFrame";
/** The name of the main frame in its frameset. */
private static final String MAIN_FRAME_NAME = "mainFrame";
/** The name of the search frame in its frameset. */
private static final String SEARCH_FRAME_NAME = "searchFrame";
/////====================================================================================================
////
/// Fields
//
/** The configuration for this documentation generator. */
private final HTMLDocumentationGeneratorConfiguration config;
/** The CALWorkspace for metadata access. Can be null. */
private final CALWorkspace workspace;
/** Whether to globally disable all hyperlink generation. */
private final boolean disableAllHyperlinks;
/** Keeps track of the name of the current module whose documentation is being generated. */
private ModuleName currentModuleName = null;
/** The current HTML page being generated. */
private HTMLBuilder currentPage = null;
/** The main page being generated (for use to cache the {@link #currentPage} when generating separated instance doc. */
private HTMLBuilder mainPageContext = null;
/** Whether the generator is currently generating some separate instance documentation. */
private boolean inSeparateInstanceDoc = false;
/** The set of imported module names for the current module. */
private Set<ModuleName> importedModules = null;
/** The set of friend module names for the current module. */
private Set<ModuleName> friendModules = null;
/** The set of directly dependent module names for the current module. */
private Set<ModuleName> directlyDependentModules = null;
/** The set of indirectly dependent module names for the current module. */
private Set<ModuleName> indirectlyDependentModules = null;
// Some cached statistics about the current module.
private int nTypeConstructorsInModule = 0;
private int nFunctionsInModule = 0;
private int nTypeClassesInModule = 0;
private int nClassInstancesInModule = 0;
/**
* A nested map mapping:
* <p>
* lowercased module name -> module name -> disambiguated name
* <p>
* for determining how a module name should be rendered when used as part of a file name on a file system
* that is case-insensitive.
* <p>
* A disambiguation map works like this: Given a name (with mixed upper and
* lower case)
* <ol>
* <li>get the lowercase version of the name - names that conflict because
* of case-insensitivity would map to the same lowercased name.
*
* <li>using the lowercased name, get a map mapping the original names to
* disambiguated names.
*
* <li>if the map is empty, insert the pair (name, name) (the first-comer
* gets to keep its name without disambiguation).
*
* <li>if the map already has entries, the name needs to be mangled to
* create a disambiguated version. Then the pair (name, disambiguated name)
* is added to the map.
* </ol>
*
* For retrieval, simply repeat the same process as above, except instead of
* adding an entry to the inner map, the inner map is simply accessed to
* retrieve the mapping for the name.
*
*/
private final Map<String, Map<String, String>> disambiguationMapForModuleNames = new HashMap<String, Map<String, String>>();
/**
* A nested map mapping:
* <p>
* module name -> lowercased type constructor name -> type constructor name -> disambiguated name
* <p>
* for determining how a type constructor name should be rendered when used as part of a file name on a file system
* that is case-insensitive.
*/
private final Map<ModuleName, Map<String, Map<String, String>>> disambiguationMapForTypeConsNames = new HashMap<ModuleName, Map<String, Map<String, String>>>();
/**
* A nested map mapping:
* <p>
* module name -> lowercased type class name -> type class name -> disambiguated name
* <p>
* for determining how a type class name should be rendered when used as part of a file name on a file system
* that is case-insensitive.
*/
private final Map<ModuleName, Map<String, Map<String, String>>> disambiguationMapForTypeClassNames = new HashMap<ModuleName, Map<String, Map<String, String>>>();
/** The reference generator for use with the conversion of CALDoc text blocks to HTML when the current directory is the modules subdirectory. */
private final ReferenceGenerator inModulesSubdirectoryReferenceGenerator = new ReferenceGenerator();
/////====================================================================================================
////
/// Inner classes
//
/////====================================================================================================
/**
* A type-safe enumeration of the localizable user-visible strings potentially
* emitted by the documentation generator.
*
* @author Joseph Wong
*/
private static final class LocalizableUserVisibleString {
////
/// Stylesheet names
//
private static final LocalizableUserVisibleString DEFAULT = new LocalizableUserVisibleString("default");
private static final LocalizableUserVisibleString FOR_PRINTING = new LocalizableUserVisibleString("forPrinting");
////
/// Main documentation
//
private static final LocalizableUserVisibleString WINDOW_TITLE_TEMPLATE = new LocalizableUserVisibleString("windowTitleTemplate");
private static final LocalizableUserVisibleString OVERVIEW = new LocalizableUserVisibleString("overview");
private static final LocalizableUserVisibleString MODULE_SUMMARY = new LocalizableUserVisibleString("moduleSummary");
private static final LocalizableUserVisibleString TYPE_CLASSES = new LocalizableUserVisibleString("typeClasses");
private static final LocalizableUserVisibleString MODULES = new LocalizableUserVisibleString("modules");
private static final LocalizableUserVisibleString INSTANCES = new LocalizableUserVisibleString("instances");
private static final LocalizableUserVisibleString TYPES = new LocalizableUserVisibleString("types");
private static final LocalizableUserVisibleString FUNCTIONS_CLASS_METHODS_AND_DATA_CONSTRUCTORS = new LocalizableUserVisibleString("functionsClassMethodsAndDataConstructors");
private static final LocalizableUserVisibleString FUNCTIONS = new LocalizableUserVisibleString("functions");
private static final LocalizableUserVisibleString TYPE_INDEX = new LocalizableUserVisibleString("typeIndex");
private static final LocalizableUserVisibleString FUNCTIONAL_AGENT_INDEX = new LocalizableUserVisibleString("functionalAgentIndex");
private static final LocalizableUserVisibleString TYPE_CLASS_INDEX = new LocalizableUserVisibleString("typeClassIndex");
private static final LocalizableUserVisibleString INSTANCE_INDEX = new LocalizableUserVisibleString("instanceIndex");
private static final LocalizableUserVisibleString DEPRECATED_COLON = new LocalizableUserVisibleString("deprecatedColon");
private static final LocalizableUserVisibleString RETURNS_COLON = new LocalizableUserVisibleString("returnsColon");
private static final LocalizableUserVisibleString COMMA_AND_SPACE = new LocalizableUserVisibleString("commaAndSpace");
private static final LocalizableUserVisibleString AUTHOR_COLON = new LocalizableUserVisibleString("authorColon");
private static final LocalizableUserVisibleString VERSION_COLON = new LocalizableUserVisibleString("versionColon");
private static final LocalizableUserVisibleString SEE_ALSO_COLON = new LocalizableUserVisibleString("seeAlsoColon");
private static final LocalizableUserVisibleString FOREIGN_TYPE_COLON = new LocalizableUserVisibleString("foreignTypeColon");
private static final LocalizableUserVisibleString IMPLEMENTATION_VISIBILITY_COLON = new LocalizableUserVisibleString("implementationVisibilityColon");
private static final LocalizableUserVisibleString CALDOC_INDICATOR = new LocalizableUserVisibleString("caldocIndicator");
private static final LocalizableUserVisibleString METADATA_INDICATOR = new LocalizableUserVisibleString("metadataIndicator");
private static final LocalizableUserVisibleString ARGUMENTS_COLON = new LocalizableUserVisibleString("argumentsColon");
private static final LocalizableUserVisibleString RETURN_VALUE_INDICATOR = new LocalizableUserVisibleString("returnValueIndicator");
private static final LocalizableUserVisibleString COLON = new LocalizableUserVisibleString("colon");
private static final LocalizableUserVisibleString IMPORTED_MODULES_COLON = new LocalizableUserVisibleString("importedModulesColon");
private static final LocalizableUserVisibleString FRIEND_MODULES_COLON = new LocalizableUserVisibleString("friendModulesColon");
private static final LocalizableUserVisibleString DIRECTLY_DEPENDENT_MODULES_COLON = new LocalizableUserVisibleString("directlyDependentModulesColon");
private static final LocalizableUserVisibleString INDIRECTLY_DEPENDENT_MODULES_COLON = new LocalizableUserVisibleString("indirectlyDependentModulesColon");
private static final LocalizableUserVisibleString DATA_CONSTRUCTORS = new LocalizableUserVisibleString("dataConstructors");
private static final LocalizableUserVisibleString CLASS_METHODS = new LocalizableUserVisibleString("classMethods");
private static final LocalizableUserVisibleString KNOWN_INSTANCES = new LocalizableUserVisibleString("knownInstances");
private static final LocalizableUserVisibleString INSTANCE_METHODS = new LocalizableUserVisibleString("instanceMethods");
private static final LocalizableUserVisibleString NAV_BAR_ITEM_SEPARATOR = new LocalizableUserVisibleString("navBarItemSeparator");
private static final LocalizableUserVisibleString OPTIONS = new LocalizableUserVisibleString("options");
private static final LocalizableUserVisibleString SCOPE_FILTER_COLON = new LocalizableUserVisibleString("scopeFilterColon");
private static final LocalizableUserVisibleString PUBLIC_ITEMS_ONLY = new LocalizableUserVisibleString("publicItemsOnly");
private static final LocalizableUserVisibleString SHOW_ALL_ITEMS = new LocalizableUserVisibleString("showAllItems");
private static final LocalizableUserVisibleString REQUIRED_METHOD_INDICATOR = new LocalizableUserVisibleString("requiredMethodIndicator");
private static final LocalizableUserVisibleString OPTIONAL_METHOD_INDICATOR = new LocalizableUserVisibleString("optionalMethodIndicator");
////
/// Module list
//
private static final LocalizableUserVisibleString VIEW_COLON = new LocalizableUserVisibleString("viewColon");
private static final LocalizableUserVisibleString FLAT = new LocalizableUserVisibleString("flat");
private static final LocalizableUserVisibleString GROUPED = new LocalizableUserVisibleString("grouped");
private static final LocalizableUserVisibleString HIERARCHICAL = new LocalizableUserVisibleString("hierarchical");
private static final LocalizableUserVisibleString EXPAND_ALL = new LocalizableUserVisibleString("expandAll");
private static final LocalizableUserVisibleString COLLAPSE_ALL = new LocalizableUserVisibleString("collapseAll");
private static final LocalizableUserVisibleString EXPAND_BUTTON_LABEL = new LocalizableUserVisibleString("expandButtonLabel");
private static final LocalizableUserVisibleString COLLAPSE_BUTTON_LABEL = new LocalizableUserVisibleString("collapseButtonLabel");
////
/// Search page
//
private static final LocalizableUserVisibleString SEARCH = new LocalizableUserVisibleString("search");
private static final LocalizableUserVisibleString HIDE = new LocalizableUserVisibleString("hide");
private static final LocalizableUserVisibleString NO_MATCHES = new LocalizableUserVisibleString("noMatches");
private static final LocalizableUserVisibleString ENTER_SEARCH_TERM_COLON = new LocalizableUserVisibleString("enterSearchTermColon");
private static final LocalizableUserVisibleString SEARCH_RESULT_SUMMARY = new LocalizableUserVisibleString("searchResultSummary");
private static final LocalizableUserVisibleString SEARCH_RESULT_SUMMARY_PUBLIC = new LocalizableUserVisibleString("searchResultSummaryPublic");
private static final LocalizableUserVisibleString SEARCH_RESULT_SUMMARY_PROTECTED = new LocalizableUserVisibleString("searchResultSummaryProtected");
private static final LocalizableUserVisibleString SEARCH_RESULT_SUMMARY_PRIVATE = new LocalizableUserVisibleString("searchResultSummaryPrivate");
////
/// Links between main documentation and usage indices
//
private static final LocalizableUserVisibleString USAGE_INDEX_ENTRY = new LocalizableUserVisibleString("usageIndexEntry");
private static final LocalizableUserVisibleString MAIN_ENTRY = new LocalizableUserVisibleString("mainEntry");
////
/// Usage indices
//
private static final LocalizableUserVisibleString USAGE_DOC_ARGUMENT_TYPE_INDEX = new LocalizableUserVisibleString("usageDocArgumentTypeIndex");
private static final LocalizableUserVisibleString USAGE_DOC_RETURN_TYPE_INDEX = new LocalizableUserVisibleString("usageDocReturnTypeIndex");
private static final LocalizableUserVisibleString USAGE_DOC_INSTANCE_INDEX_INSTANCES_OF = new LocalizableUserVisibleString("usageDocInstanceIndexInstancesOf");
private static final LocalizableUserVisibleString USAGE_DOC_INSTANCE_INDEX_INSTANCES_FOR = new LocalizableUserVisibleString("usageDocInstanceIndexInstancesFor");
private static final LocalizableUserVisibleString DEFINING_MODULE_COLON = new LocalizableUserVisibleString("definingModuleColon");
private static final LocalizableUserVisibleString DEPENDENT_MODULE_COLON = new LocalizableUserVisibleString("dependentModuleColon");
////
/// Separate instance documentation
//
private static final LocalizableUserVisibleString INSTANCE_DOC_TITLE = new LocalizableUserVisibleString("instanceDocTitle");
////
/// CALDoc tooltips
//
private static final LocalizableUserVisibleString MODULE = new LocalizableUserVisibleString("module");
private static final LocalizableUserVisibleString FIELD_OF_DATA_CONSTRUCTORS = new LocalizableUserVisibleString("fieldOfDataConstructors");
private static final LocalizableUserVisibleString FIELD_OF_DATA_CONSTRUCTOR_AND_SPACE = new LocalizableUserVisibleString("fieldOfDataConstructorAndSpace");
private static final LocalizableUserVisibleString LOCAL_FUNCTION = new LocalizableUserVisibleString("localFunction");
private static final LocalizableUserVisibleString LOCAL_PATTERN_MATCH_VARIABLE = new LocalizableUserVisibleString("localPatternMatchVariable");
private static final LocalizableUserVisibleString CASE_PATTERN_VARIABLE = new LocalizableUserVisibleString("casePatternVariable");
private static final LocalizableUserVisibleString PARAMETER_OF_AND_SPACE = new LocalizableUserVisibleString("parameterOfAndSpace");
private static final LocalizableUserVisibleString PARAMETER_OF_LOCAL_FUNCTION_AND_SPACE = new LocalizableUserVisibleString("parameterOfLocalFunctionAndSpace");
private static final LocalizableUserVisibleString PARAMETER_OF_LAMBDA_EXPRESSION = new LocalizableUserVisibleString("parameterOfLambdaExpression");
private static final LocalizableUserVisibleString PARAMETER_OF_INSTANCE_METHOD = new LocalizableUserVisibleString("parameterOfInstanceMethod");
private static final LocalizableUserVisibleString LOCAL_VARIABLE = new LocalizableUserVisibleString("localVariable");
private static final LocalizableUserVisibleString TYPE_VARIABLE = new LocalizableUserVisibleString("typeVariable");
private static final LocalizableUserVisibleString RECORD_FIELD_NAME = new LocalizableUserVisibleString("recordFieldName");
/** The key into the caldoc.properties file. */
private final String propKey;
/** Private constructor. */
private LocalizableUserVisibleString(String propKey) {
if (propKey == null) {
throw new NullPointerException();
}
this.propKey = propKey;
}
/**
* {@inheritDoc}
*/
@Override
public String toString() {
return "!" + propKey + "!";
}
/**
* @return the localized resource string.
*/
String toResourceString() {
return CALDocMessages.getString(propKey);
}
/**
* @param arg0 the first substitution parameter.
* @return the localized resource string.
*/
String toResourceString(String arg0) {
return CALDocMessages.getString(propKey, arg0);
}
/**
* @param arg0 the first substitution parameter.
* @param arg1 the second substitution parameter.
* @return the localized resource string.
*/
String toResourceString(String arg0, String arg1) {
return CALDocMessages.getString(propKey, arg0, arg1);
}
}
/**
* A set of the CAL fragment strings employed by the documentation generator.<p>
*
* <em>These are not to be localized!</em>
*
* @author Joseph Wong
*/
private static final class CALFragments {
/** Private constructor. */
private CALFragments() {}
private static final String COMMA_AND_SPACE = ", ";
private static final String DATA = "data";
private static final String CLASS = "class";
private static final String RARROW = "->";
private static final String IMPLIES = "=>";
private static final String OPEN_PAREN = "(";
private static final String CLOSE_PAREN = ")";
private static final String UNIT_TYPE_CONS = "()";
private static final String CLOSE_BRACKET = "]";
private static final String OPEN_BRACKET = "[";
private static final String CLOSE_BRACE = "}";
private static final String OPEN_BRACE = "{";
private static final String SEPARATOR_BETWEEN_BASE_RECORD_AND_EXTENSION_FIELDS = " | ";
private static final String COLON_COLON = "::";
private static final char BACKSLASH = '\\';
private static final char DOT = '.';
/** The standard type variable name to use for display purposes. */
private static final String STANDARD_TYPE_VAR = "a";
}
/** We use <tt> for formatting code fragments. */
private static final HTML.Tag CODE_FORMATTING_TAG = HTML.Tag.TT;
/**
* A set of the HTML style class constants employed by the documentation generator.
*
* @author Joseph Wong
*/
private static final class StyleClassConstants {
/** Private constructor. */
private StyleClassConstants() {}
////
/// General style classes
//
private static final StyleClass MAJOR_SECTION = new StyleClass("major");
private static final StyleClass MINOR_SECTION = new StyleClass("minor");
private static final StyleClass MINOR_SECTION_ALTERNATE = new StyleClass(MINOR_SECTION, "alt");
private static final StyleClass NON_DISPLAYED_HEADER = new StyleClass("nonDisplayedHeader");
private static final StyleClass ABSTRACT_DEPRECATED_BLOCK = new StyleClass("deprecated");
private static final StyleClass NAME_AND_TYPE = new StyleClass("nameAndType");
private static final StyleClass CODE_BLOCK = new StyleClass("codeBlock");
private static final StyleClass PAGE_BOTTOM = new StyleClass("pageBottom");
private static final StyleClass MAIN_CONTENT = new StyleClass("mainContent");
private static final StyleClass WITH_MAIN_CONTENT = new StyleClass("withMainContent");
private static final StyleClass SIDE_BAR_TITLE = new StyleClass("sideBarTitle");
private static final StyleClass MODULE_LIST_PAGE_TITLE = new StyleClass(SIDE_BAR_TITLE, "moduleList");
private static final StyleClass MODULE_LIST_SECTION_TITLE = new StyleClass("moduleListSectionTitle");
private static final StyleClass SIDE_BAR_KHAKI_TITLE = new StyleClass(SIDE_BAR_TITLE, "khaki");
private static final StyleClass SIDE_BAR_KHAKI_SUPERTITLE = new StyleClass(SIDE_BAR_TITLE, "superkhaki");
////
/// Module list
//
private static final StyleClass TREE_DIV = new StyleClass("treeDiv");
private static final StyleClass TREE_NODE_TOGGLE = new StyleClass("treeToggle");
private static final StyleClass TREE_NODE_TOGGLE_PLACEHOLDER = new StyleClass("treeNoToggle");
////
/// Display mode toolbar
//
private static final StyleClass TOOLBAR = new StyleClass("toolbar");
private static final StyleClass SUB_TOOLBAR = new StyleClass(TOOLBAR, "sub");
private static final StyleClass BUTTON_SELECTED = new StyleClass("btnSelected");
private static final StyleClass BUTTON_NOT_SELECTED = new StyleClass("btnNotSelected");
////
/// Overview page
//
private static final StyleClass TREE_DIV_OVERVIEW_PAGE = new StyleClass(TREE_DIV, "ovw");
private static final StyleClass DL_OVERVIEW_PAGE = new StyleClass("ovwDl");
////
/// Search page
//
private static final StyleClass SEARCH_BOX_TITLE = new StyleClass(SIDE_BAR_TITLE, "searchBoxTitle");
private static final StyleClass SEARCH_BOX = new StyleClass("searchBox");
private static final StyleClass SEARCH_FIELD = new StyleClass("searchField");
////
/// Scope style classes
//
private static final StyleClass PUBLIC_SCOPE = new StyleClass("pub");
private static final StyleClass NON_PUBLIC_SCOPE = new StyleClass("nonPub");
private static final StyleClass PROTECTED_SCOPE = new StyleClass(NON_PUBLIC_SCOPE, "prot");
private static final StyleClass PRIVATE_SCOPE = new StyleClass(NON_PUBLIC_SCOPE, "priv");
////
/// Module overview style classes
//
private static final StyleClass RELATED_MODULES_LIST = new StyleClass("relatedModulesList");
private static final StyleClass OVERVIEW_TABLE = new StyleClass("ovwTbl");
private static final StyleClass OVERVIEW_TABLE_SCOPE_COLUMN = new StyleClass("ovwTblScope");
private static final StyleClass OVERVIEW_NESTED_TABLE = new StyleClass("ovwNestedTbl");
private static final StyleClass OVERVIEW_TABLE_DESCRIPTION = new StyleClass("ovwTblDesc");
private static final StyleClass OVERVIEW_TABLE_OUTER_DESCRIPTION = new StyleClass(OVERVIEW_TABLE_DESCRIPTION, "outer");
private static final StyleClass OVERVIEW_TABLE_NESTED_DESCRIPTION = new StyleClass(OVERVIEW_TABLE_DESCRIPTION, "nested");
private static final StyleClass OVERVIEW_REFERENCE = new StyleClass("ovwRef");
private static final StyleClass SHORT_DESCRIPTION_BLOCK = new StyleClass("ovwDesc");
private static final StyleClass OVERVIEW_DEPRECATED_BLOCK = new StyleClass(ABSTRACT_DEPRECATED_BLOCK, "ovw");
////
/// Details section: high-level style classes
//
private static final StyleClass DETAILS_LIST = new StyleClass("detailsList");
private static final StyleClass DATA_CONSTRUCTOR_LIST = new StyleClass(DETAILS_LIST, "dc");
private static final StyleClass CLASS_METHOD_LIST = new StyleClass(DETAILS_LIST, "cm");
private static final StyleClass KNOWN_INSTANCE_LIST = new StyleClass(DETAILS_LIST, "ki");
private static final StyleClass INSTANCE_METHOD_LIST = new StyleClass(DETAILS_LIST, "im");
private static final StyleClass DETAILS_LIST_HEADER = new StyleClass("detailsListHdr");
private static final StyleClass DATA_CONSTRUCTOR_LIST_HEADER = new StyleClass(DETAILS_LIST_HEADER, "dc");
private static final StyleClass CLASS_METHOD_LIST_HEADER = new StyleClass(DETAILS_LIST_HEADER, "cm");
private static final StyleClass KNOWN_INSTANCE_LIST_HEADER = new StyleClass(DETAILS_LIST_HEADER, "ki");
private static final StyleClass INSTANCE_METHOD_LIST_HEADER = new StyleClass(DETAILS_LIST_HEADER, "im");
////
/// Details section: low-level style classes
//
/// CALDoc/metadata indicator
//
private static final StyleClass ABSTRACT_INDICATOR = new StyleClass("ind");
private static final StyleClass METADATA_INDICATOR = new StyleClass(ABSTRACT_INDICATOR, "metadata");
private static final StyleClass CALDOC_INDICATOR = new StyleClass(ABSTRACT_INDICATOR, "caldoc");
/// Class method indicator
//
private static final StyleClass CLASS_METHOD_INDICATOR = new StyleClass("cmInd");
/// Description/attribute blocks
//
private static final StyleClass ATTRIBUTE_HEADER = new StyleClass("attrHdr");
private static final StyleClass DESCRIPTION_BLOCK = new StyleClass("desc");
private static final StyleClass AUTHOR_BLOCK = new StyleClass("author");
private static final StyleClass DEPRECATED_BLOCK = new StyleClass(ABSTRACT_DEPRECATED_BLOCK, "details");
private static final StyleClass VERSION_BLOCK = new StyleClass("version");
private static final StyleClass ARG_BLOCK = new StyleClass("arg");
private static final StyleClass RETURN_BLOCK = new StyleClass("return");
private static final StyleClass SEE_BLOCK = new StyleClass("see");
private static final StyleClass RETURN_VALUE_INDICIATOR = new StyleClass("retval");
/// Definition - header portion
//
private static final StyleClass ABSTRACT_DEFINITION_SECTION_START = new StyleClass("defSecStart");
private static final StyleClass FIRST_DEFINITION_SECTION_START = new StyleClass(ABSTRACT_DEFINITION_SECTION_START, "first");
private static final StyleClass DEFINITION_SECTION_START = new StyleClass(ABSTRACT_DEFINITION_SECTION_START, "follow");
private static final StyleClass DEFINITION_HEADER = new StyleClass("defHdr");
private static final StyleClass DEFINITION_HEADER_FIRST_LINE = new StyleClass("defHdrFirstLine");
private static final StyleClass DECLARATION = new StyleClass("decl");
private static final StyleClass SCOPE = new StyleClass("scope");
private static final StyleClass DECLARED_NAME = new StyleClass("declName");
/// Argument name formatting
//
private static final StyleClass ARG_NAME = new StyleClass("argName");
private static final StyleClass ARG_NAME_FROM_CODE = new StyleClass(ARG_NAME, "fromCode");
private static final StyleClass ARG_NAME_NOT_FROM_CODE = new StyleClass(ARG_NAME, "notFromCode");
private static final StyleClass ARG_NAME_FROM_METADATA = new StyleClass(ARG_NAME_NOT_FROM_CODE, "fromMetadata");
private static final StyleClass ARG_NAME_FROM_CALDOC = new StyleClass(ARG_NAME_NOT_FROM_CODE, "fromCALDoc");
private static final StyleClass ARG_NAME_ARTIFICIAL = new StyleClass(ARG_NAME_NOT_FROM_CODE, "artificial");
/// Type signature formatting
//
private static final StyleClass TYPE_SIGNATURE = new StyleClass("typeSig");
private static final StyleClass TYPE_CONSTRAINT = new StyleClass("typeConstraint");
private static final StyleClass CAL_SYMBOL = new StyleClass("calSymbol");
////
/// Navigation frames and bars
//
private static final StyleClass DISABLED_LINK = new StyleClass("disabledLink");
////
/// Navigation frames
//
private static final StyleClass IMPORTANT_LINK = new StyleClass("importantLink");
private static final StyleClass INDEX_NAV = new StyleClass("indexNav");
private static final StyleClass INDEX_NAV_LINK = new StyleClass("indexNavLink");
private static final StyleClass INDEX_NAV_CURRENT_LINK = new StyleClass("indexNavCurrentLink");
////
/// Options Box
//
private static final StyleClass OPTIONS_HEADER = new StyleClass("optionsHdr");
private static final StyleClass OPTIONS_BODY = new StyleClass("optionsBody");
private static final StyleClass OPTIONS_CHOICE = new StyleClass("optionsChoice");
private static final StyleClass FAKE_LINK = new StyleClass("fakeLink");
////
/// Navigation bars
//
private static final StyleClass NAV_BAR = new StyleClass("navBar");
private static final StyleClass NAV_BAR_GLOBAL_ROW = new StyleClass("navBarGlobalRow");
private static final StyleClass NAV_BAR_LOCAL_ROW = new StyleClass("navBarLocalRow");
private static final StyleClass NAV_BAR_HEADER_FOOTER = new StyleClass("navBarHeaderFooter");
private static final StyleClass MODULE_LIST_NAV_BAR = new StyleClass("moduleListNavBar");
////
/// CSS selectors for pseudo-classes
//
private static final CSSBuilder.Selector A_LINK_PSEUDOCLASS_SELECTOR = CSSBuilder.Selector.makePseudoClass(CSSBuilder.Selector.makeType(HTML.Tag.A), "link");
private static final CSSBuilder.Selector A_HOVER_PSEUDOCLASS_SELECTOR = CSSBuilder.Selector.makePseudoClass(CSSBuilder.Selector.makeType(HTML.Tag.A), "hover");
private static final CSSBuilder.Selector A_VISITED_PSEUDOCLASS_SELECTOR = CSSBuilder.Selector.makePseudoClass(CSSBuilder.Selector.makeType(HTML.Tag.A), "visited");
////
/// Tooltip fragments
//
private static final StyleClass TOOLTIP_HEADER = new StyleClass("tooltipHeader");
}
/**
* A set of the HTML element identifiers employed by the documentation generator.
*
* @author Joseph Wong
*/
private static final class ElementID {
/** Private constructor. */
private ElementID() {}
private static final String OUTER_FRAMESET = "outerFrameset";
private static final String SUMMARY_SECTION = "summarySection";
private static final String TYPES_SECTION = "typesSection";
private static final String FUNCTIONS_SECTION = "functionsSection";
private static final String TYPE_CLASSES_SECTION = "typeClassesSection";
private static final String INSTANCES_SECTION = "instancesSection";
private static final String HIDE_NONPUBLIC_STYLE = "hideNonPub";
private static final String MODULE_LIST_FLAT = "mlFlat";
private static final String MODULE_LIST_GROUPED = "mlGrouped";
private static final String MODULE_LIST_HIERARCHICAL = "mlHierarchical";
private static final String SUB_TOOLBAR_MODULE_LIST_FLAT = "tbFlat";
private static final String SUB_TOOLBAR_MODULE_LIST_GROUPED = "tbGrouped";
private static final String SUB_TOOLBAR_MODULE_LIST_HIERARCHICAL = "tbHierarchical";
private static final String DISPLAY_MODE_BUTTON_MODULE_LIST_FLAT = "dmFlat";
private static final String DISPLAY_MODE_BUTTON_MODULE_LIST_GROUPED = "dmGrouped";
private static final String DISPLAY_MODE_BUTTON_MODULE_LIST_HIERARCHICAL = "dmHierarchical";
/// Search page
//
private static final String KEY = "key";
private static final String RESULTS = "results";
/// Options box
//
private static final String HIGHLIGHT_PUBLIC_STYLE = "highlightPub";
private static final String HIGHLIGHT_NONPUBLIC_STYLE = "highlightNonPub";
private static final String OPTIONS_BOX = "optionsBox";
}
/**
* A set of the style values employed by the documentation generator.
*
* @author Joseph Wong
*/
private static final class StyleValueConstants {
/** Private constructor. */
private StyleValueConstants() {}
////
/// Font constants
//
private static final String SANS_SERIF_FONT_LIST = "Verdana, Arial, Helvetica, sans-serif";
private static final String SERIF_FONT_LIST = "palatino, 'Palatino Linotype', 'Book Antiqua', serif";
private static final String MONOSPACE_FONT_LIST = "'Lucida Console', 'Lucida Sans Typewriter', monospace";
////
/// Colour constants
//
private static final String OPENQUARK_BLUE = "#325087";
private static final String OPENQUARK_CREAM = "#ffffe2";
private static final String OPENQUARK_RED = "#f51e32";
private static final String OPENQUARK_SECONDARY_LIGHT_BLUE = "#909fc9";
private static final String OPENQUARK_SECONDARY_YELLOW = "#f9d37c";
private static final String OPENQUARK_SECONDARY_KHAKI = "#ceca8d";
private static final String OPENQUARK_WEBSITE_KHAKI = "#f2f1e1";
private static final String OPENQUARK_WEBSITE_LIGHT_BLUE_HEADER_BACKGROUND = "#e8eff7";
private static final String OPENQUARK_WEBSITE_LIGHT_BLUE_CONTENT_BACKGROUND = "#f5f9fc";
private static final String WHITE = "white";
private static final String DISABLED_LINK_COLOR = "gray";
private static final String VISITED_LINK_COLOR ="#306";
private static final String TYPE_CONSTRAINT_BACKGROUND_COLOR = "#eee";
private static final String OVERVIEW_NESTED_TABLE_BACKGROUND_COLOR = "#fcfcfc";
private static final String OVERVIEW_NESTED_TABLE_BORDER_COLOR = "#ccc";
private static final String DEPRECATED_BLOCK_CODE_BLOCK_COLOR = "#fdd";
private static final String DEPRECATED_BLOCK_BORDER_COLOR = "#fcc";
private static final String DEPRECATED_BLOCK_BACKGROUND_COLOR = "#fee";
private static final String METADATA_INDICATOR_COLOR = "green";
private static final String CALDOC_INDICATOR_COLOR = OPENQUARK_BLUE;
private static final String CODE_BLOCK_COLOR = "#574022";
private static final String CODE_BLOCK_BACKGROUND_COLOR = "#f9f8f0";
private static final String OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_COLOR = "#777";
private static final String OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR = "#dfdec6";
private static final String OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_SUPERTITLE_COLOR = OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_COLOR;
private static final String OPENQUARK_WEBSITE_KHAKI_LIGHTER = "#f9f9f0";
private static final String OPTIONS_BODY_BACKGROUND = OPENQUARK_WEBSITE_LIGHT_BLUE_CONTENT_BACKGROUND;
private static final String TREE_NODE_TOGGLE_HOVER_BACKGROUND_COLOR = OPENQUARK_SECONDARY_LIGHT_BLUE;
private static final String CAL_EDITOR_HOVER_BACKGROUND_COLOR = OPENQUARK_CREAM;
private static final String TOOLBAR_BACKGROUND_COLOR = "#d3f2eb";
private static final String TOOLBAR_BUTTON_BACKGROUND_COLOR = "#defff8";
private static final String TOOLBAR_BUTTON_BORDER_COLOR = "#9dccc2";
private static final String TOOLBAR_BUTTON_HOVER_BACKGROUND_COLOR = OPENQUARK_WEBSITE_KHAKI;
private static final String TOOLBAR_BUTTON_SELECTED_BACKGROUND_COLOR = OPENQUARK_SECONDARY_YELLOW;
private static final String SUB_TOOLBAR_BACKGROUND_COLOR = "#f2fffc";
////
/// Text style constants
//
private static final String BOLD = "bold";
private static final String ITALIC = "italic";
////
/// Text decoration constants
//
private static final String UNDERLINE = "underline";
////
/// Text size constants
//
private static final String LARGER = "larger";
private static final String X_LARGE = "x-large";
private static final String LARGE = "large";
private static final String MEDIUM = "medium";
private static final String SMALLER = "smaller";
private static final String INDICATOR_FONT_SIZE = "9px";
////
/// Text alignment constants
//
private static final String LEFT_ALIGN = "left";
private static final String RIGHT_ALIGN = "right";
////
/// Border style constants
//
private static final String THIN = "thin";
private static final String TWO_PX_THIN = "2px";
private static final String SOLID = "solid";
private static final String DOTTED = "dotted";
private static final String OUTSET_BORDER_STYLE = "outset";
private static final String INDEX_NAV_LINK_SEPARATOR_BORDER_STYLE = "1px dotted " + OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR;
private static final String INDEX_NAV_CURRENT_LINK_LEFT_BORDER_STYLE = "3px solid " + OPENQUARK_BLUE;
private static final String INDEX_NAV_CURRENT_LINK_BORDER_STYLE = "1px solid #999";
private static final String MODULE_LIST_SECTION_TITLE_LEFT_BORDER_STYLE = "3px solid " + OPENQUARK_RED;
private static final String TREE_DIV_OVERVIEW_PAGE_LEFT_BORDER_STYLE = "1px dotted " + OPENQUARK_SECONDARY_LIGHT_BLUE;
private static final String TREE_DIV_OVERVIEW_PAGE_BOTTOM_BORDER_STYLE = "1px solid " + OPENQUARK_SECONDARY_LIGHT_BLUE;
private static final String DL_OVERVIEW_PAGE_BORDER_STYLE = "1px solid " + OPENQUARK_SECONDARY_KHAKI;
private static final String TOOLBAR_BUTTON_BORDER_STYLE = "1px solid " + TOOLBAR_BUTTON_BORDER_COLOR;
private static final String TOOLBAR_BUTTON_BLACK_BORDER_STYLE = "1px solid black";
private static final String TREE_NODE_TOGGLE_BORDER_STYLE = "1px solid #777";
////
/// Width constants
//
private static final String ZERO_WIDTH = "0px";
private static final String ONE_EM_WIDTH = "1em";
private static final String ONE_POINT_FIVE_EM_WIDTH = "1.5em";
private static final String TWO_EM_WIDTH = "2em";
private static final String MAJOR_SECTION_TOP_AND_SIDE_PADDING = "5px";
private static final String DEPRECATED_BLOCK_CLEARANCE = "0.5em";
private static final String DETAILS_LIST_MARGIN_TOP = "2.5em";
private static final String DETAILS_LIST_PADDING = "3px";
private static final String AUTO_WIDTH = "auto";
private static final String TYPE_SIGNATURE_HANGING_INDENT = "6em";
private static final String CODE_BLOCK_SIDE_PADDING = "0px";
private static final String SEARCH_BOX_TOP_PADDING = "5px";
private static final String SEARCH_BOX_RIGHT_PADDING = "10px";
private static final String ONE_HUNDRED_PERCENT = "100%";
private static final String MAIN_CONTENT_MARGIN = "8px";
private static final String SIDE_BAR_TITLE_PADDING = "6px";
private static final String INDEX_NAV_LINK_PADDING = "6px";
private static final String INDEX_NAV_LINK_PADDING_HALF = "3px";
private static final String INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE = "2px";
private static final String NAV_BAR_PADDING = "4px";
private static final String SCOPE_DISPLAY_SETTINGS_PADDING = "2px";
private static final String TREE_INDENT = "22px";
private static final String TREE_DIV_OVERVIEW_PAGE_BOTTOM_MARGIN = "6px";
private static final String DL_OVERVIEW_PAGE_BOTTOM_PADDING = "3px";
private static final String TOOLBAR_PADDING = "6px";
private static final String TOOLBAR_BUTTON_PADDING = "3px";
private static final String SUB_TOOLBAR_BUTTON_TOP_BOTTOM_PADDING = "1px";
private static final String RELATED_MODULES_GROUPED_LIST_HANGING_INDENT = "3em";
////
/// Display style constants
//
private static final String BLOCK = "block";
private static final String NONE = "none";
private static final String INLINE = "inline";
////
/// Text wrap style constants
//
private static final String NO_TEXT_WRAP = "none";
private static final String SUPPRESS_TEXT_WRAP = "suppress";
private static final String NOWRAP_WHITE_SPACE = "nowrap";
////
/// Cursor style constants
//
private static final String POINTER = "pointer";
}
/**
* CSS 2 attributes not in CSS.Attribute class.
*
* @author Joseph Wong
*/
private static final class CSS2Attribute {
/** Private constructor. */
private CSS2Attribute() {}
// good advice for preventing word-wrap can be found here: http://www.cs.tut.fi/~jkorpela/html/nobr.html
private static final String TEXT_WRAP = "text-wrap";
private static final String CURSOR = "cursor";
}
/**
* HTML 4 tags and attributes not in HTML.Tag and HTML.Attribute classes.
*
* @author Joseph Wong
*/
private static final class HTML4 {
/** Private constructor. */
private HTML4() {}
private static final HTML.Tag TBODY_TAG = new HTML.Tag("tbody", true, true) {};
private static final String RULES_ATTRIBUTE = "rules";
private static final String ONLOAD_ATTRIBUTE = "onload";
private static final String MEDIA_ATTRIBUTE = "media";
private static final String ONCLICK_ATTRIBUTE = "onclick";
}
/**
* DocType declarations for HTML.
*
* @author Joseph Wong
*/
private static final class DocTypeDecl {
/** Private constructor. */
private DocTypeDecl() {}
/** DocType for HTML 4.01 Strict. */
private static final String HTML_4_01_STRICT =
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01//EN' 'http://www.w3.org/TR/html4/strict.dtd'>\n";
/** DocType for HTML 4.01 Frameset. Used for the master frameset. */
private static final String HTML_4_01_FRAMESET =
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Frameset//EN' 'http://www.w3.org/TR/html4/frameset.dtd'>\n";
/**
* DocType for HTML 4.01 Transitional. Used for the navigation pages in
* the smaller frames, because the 'target' attribute is <i>not</i> in
* HTML 4.01 Strict.
*
* Now also used for all documentation pages appearing in the main frame,
* because of the appearance of the "Search" link targeting the right-hand-side frame.
*/
private static final String HTML_4_01_TRANSITIONAL =
"<!DOCTYPE HTML PUBLIC '-//W3C//DTD HTML 4.01 Transitional//EN' 'http://www.w3.org/TR/html4/loose.dtd'>\n";
}
/**
* A comparator for IndexEntry instances that orders them by their display names in a case-insensitive manner.
*
* @author Joseph Wong
*/
private static final class IndexEntryComparator implements Comparator<IndexEntry> {
/** {@inheritDoc} */
public int compare(IndexEntry a, IndexEntry b) {
int ignoreCaseComparison = a.getDisplayName().compareToIgnoreCase(b.getDisplayName());
if (ignoreCaseComparison != 0) {
return ignoreCaseComparison;
} else {
return a.getDisplayName().compareTo(b.getDisplayName());
}
}
}
/////====================================================================================================
////
/// Source model traverser for generating a hyperlinked type signature
//
/**
* This class implements a traverser which traverses through a type signature and generates its source representation,
* with type classes and type constructors appropriate hyperlinked if requested.
*
* @author Joseph Wong
*/
private class TypeSignatureHTMLGenerator extends SourceModelTraverser<Void, Void> {
/** Whether hyperlinks should be generated. */
private final boolean shouldGenerateHyperlinks;
/**
* Constructs an instance of this traverser/generator.
* @param shouldGenerateHyperlinks whether hyperlinks should be generated.
*/
private TypeSignatureHTMLGenerator(boolean shouldGenerateHyperlinks) {
this.shouldGenerateHyperlinks = shouldGenerateHyperlinks;
}
/**
* Generates the source representation of a type application, e.g. Either a b.
*/
@Override
public Void visit_TypeExprDefn_Application(SourceModel.TypeExprDefn.Application application, Void arg) {
verifyArg(application, "application");
/// Loop through each type expression in the application, and generate each one, properly parenthesized as required.
//
final int nTypeExpressions = application.getNTypeExpressions();
for (int i = 0; i < nTypeExpressions; i++) {
if (i > 0) {
currentPage.addText(" ");
}
SourceModel.TypeExprDefn nthTypeExpr = application.getNthTypeExpression(i);
if (nthTypeExpr instanceof SourceModel.TypeExprDefn.Application || nthTypeExpr instanceof SourceModel.TypeExprDefn.Function) {
currentPage.addText(CALFragments.OPEN_PAREN);
nthTypeExpr.accept(this, arg);
currentPage.addText(CALFragments.CLOSE_PAREN);
} else {
nthTypeExpr.accept(this, arg);
}
}
return null;
}
/**
* Generates the source representation of a function type, e.g. Int -> String.
*/
@Override
public Void visit_TypeExprDefn_Function(SourceModel.TypeExprDefn.Function function, Void arg) {
verifyArg(function, "function");
//we never need to parenthesize the type on the right hand side of a "->".
//This is because "->" is the lowest precedence operator in the type grammar.
//We only parenthesize the lhs if it is a "->".
SourceModel.TypeExprDefn domain = function.getDomain();
SourceModel.TypeExprDefn codomain = function.getCodomain();
if (domain instanceof SourceModel.TypeExprDefn.Function) {
currentPage.addText(CALFragments.OPEN_PAREN);
domain.accept(this, arg);
currentPage.addText(CALFragments.CLOSE_PAREN);
} else {
domain.accept(this, arg);
}
currentPage.addText(" ").addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.CAL_SYMBOL), CALFragments.RARROW + " ");
codomain.accept(this, arg);
return null;
}
/**
* Generates the source representation of a list type, e.g. [Int].
*/
@Override
public Void visit_TypeExprDefn_List(SourceModel.TypeExprDefn.List list, Void arg) {
verifyArg(list, "list");
currentPage.addText(CALFragments.OPEN_BRACKET);
list.getElement().accept(this, arg);
currentPage.addText(CALFragments.CLOSE_BRACKET);
return null;
}
/**
* Generates the source representation of a record type, e.g. {r | a :: Int, b :: String}.
*/
@Override
public Void visit_TypeExprDefn_Record(SourceModel.TypeExprDefn.Record record, Void arg) {
verifyArg(record, "record");
final int nExtensionFields = record.getNExtensionFields();
currentPage.addText(CALFragments.OPEN_BRACE);
/// Generate the base record
//
if (record.getBaseRecordVar() != null) {
record.getBaseRecordVar().accept(this, arg);
if (nExtensionFields > 0) {
currentPage.addText(CALFragments.SEPARATOR_BETWEEN_BASE_RECORD_AND_EXTENSION_FIELDS);
}
}
/// Generate the extension fields
//
for (int i = 0; i < nExtensionFields; i++) {
if (i > 0) {
currentPage.addText(CALFragments.COMMA_AND_SPACE);
}
record.getNthExtensionField(i).accept(this, arg);
}
currentPage.addText(CALFragments.CLOSE_BRACE);
return null;
}
/**
* Generates the source representation of a field-type pair in a record type, e.g. a :: Int.
*/
@Override
public Void visit_TypeExprDefn_Record_FieldTypePair(SourceModel.TypeExprDefn.Record.FieldTypePair pair, Void arg) {
verifyArg(pair, "pair");
currentPage.addText(pair.getFieldName().getName().getCalSourceForm() + " " + CALFragments.COLON_COLON + " ");
pair.getFieldType().accept(this, arg);
return null;
}
/**
* Generates the source representation of a tuple type, e.g. (Int, String, a).
*/
@Override
public Void visit_TypeExprDefn_Tuple(SourceModel.TypeExprDefn.Tuple tuple, Void arg) {
verifyArg(tuple, "tuple");
currentPage.addText(CALFragments.OPEN_PAREN);
/// Generate the source representation for each component
//
final int nComponents = tuple.getNComponents();
for (int i = 0; i < nComponents; i++) {
if (i > 0) {
currentPage.addText(CALFragments.COMMA_AND_SPACE);
}
tuple.getNthComponent(i).accept(this, arg);
}
currentPage.addText(CALFragments.CLOSE_PAREN);
return null;
}
/**
* Generates the source representation of a type constructor type expression, hyperlinked if requested.
*/
@Override
public Void visit_TypeExprDefn_TypeCons(SourceModel.TypeExprDefn.TypeCons cons, Void arg) {
verifyArg(cons, "cons");
// NOTE: We require that the type cons name be fully qualified with a non-null module name.
SourceModel.Name.TypeCons name = cons.getTypeConsName();
if (shouldGenerateHyperlinks) {
generateTypeConsReference(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName());
} else {
currentPage.addText(getAppropriatelyQualifiedName(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName()));
}
return null;
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.<p>
*
* This method is meant to be overridden in subclasses that need to generate the hyperlink differently.
*
* @param moduleName the module name of the type constructor.
* @param unqualifiedName the unqualified name of the type constructor.
*/
void generateTypeConsReference(ModuleName moduleName, String unqualifiedName) {
HTMLDocumentationGenerator.this.generateTypeConsReference(moduleName, unqualifiedName);
}
/**
* Generates the source representation of a type variable type expression.
*/
@Override
public Void visit_TypeExprDefn_TypeVar(SourceModel.TypeExprDefn.TypeVar var, Void arg) {
verifyArg(var, "var");
currentPage.addText(var.getTypeVarName().getName());
return null;
}
/**
* Generates the source representation of the Unit type, i.e. ().
*/
@Override
public Void visit_TypeExprDefn_Unit(SourceModel.TypeExprDefn.Unit unit, Void arg) {
verifyArg(unit, "unit");
currentPage.addText(CALFragments.UNIT_TYPE_CONS);
return null;
}
/**
* Generates the source representation of a lacks constraint, e.g. r\a.
*/
@Override
public Void visit_Constraint_Lacks(SourceModel.Constraint.Lacks lacks, Void arg) {
verifyArg(lacks, "lacks");
currentPage.addText(lacks.getTypeVarName().getName() + CALFragments.BACKSLASH + lacks.getLacksField().getName().getCalSourceForm());
return null;
}
/**
* Generates the source representation of a type class constraint, hyperlinked if requested.
*/
@Override
public Void visit_Constraint_TypeClass(SourceModel.Constraint.TypeClass typeClass, Void arg) {
verifyArg(typeClass, "typeClass");
// NOTE: We require that the type class name be fully qualified with a non-null module name.
SourceModel.Name.TypeClass name = typeClass.getTypeClassName();
if (shouldGenerateHyperlinks) {
generateTypeClassReference(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName());
} else {
currentPage.addText(getAppropriatelyQualifiedName(SourceModel.Name.Module.toModuleName(name.getModuleName()), name.getUnqualifiedName()));
}
currentPage.addText(" " + typeClass.getTypeVarName().getName());
return null;
}
/**
* Generates a reference to a type class, appropriately hyperlinked.<p>
*
* This method is meant to be overriden in subclasses that need to generate the hyperlink differently.
*
* @param moduleName the module name of the type class.
* @param unqualifiedName the unqualified name of the type class.
*/
void generateTypeClassReference(ModuleName moduleName, String unqualifiedName) {
HTMLDocumentationGenerator.this.generateTypeClassReference(moduleName, unqualifiedName);
}
/**
* Generates the source representation of a type signature.
*/
@Override
public Void visit_TypeSignature(SourceModel.TypeSignature signature, Void arg) {
verifyArg(signature, "signature");
generateConstraintsFromSignature(signature, arg);
signature.getTypeExprDefn().accept(this, arg);
return null;
}
/**
* Generates the source representation of the constraints portion of a type signature.
* @param signature the type signature.
* @param arg the argument to pass through the traversal.
*/
private void generateConstraintsFromSignature(SourceModel.TypeSignature signature, Void arg) {
final int nConstraints = signature.getNConstraints();
if (nConstraints > 0) {
currentPage.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TYPE_CONSTRAINT));
if (nConstraints == 1) {
signature.getNthConstraint(0).accept(this, arg);
} else {
currentPage.addText(CALFragments.OPEN_PAREN);
for (int i = 0; i < nConstraints; i++) {
if (i > 0) {
currentPage.addText(CALFragments.COMMA_AND_SPACE);
}
signature.getNthConstraint(i).accept(this, arg);
}
currentPage.addText(CALFragments.CLOSE_PAREN);
}
currentPage.addText(" ").addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.CAL_SYMBOL), CALFragments.IMPLIES).closeTag(HTML.Tag.SPAN).addText(" ");
}
}
}
/**
* A subclass of TypeSignatureHTMLGenerator that generates all its hyperlinks as non-local references.
*
* @author Joseph Wong
*/
private final class TypeSignatureHTMLGeneratorUsingNonLocalReferences extends TypeSignatureHTMLGenerator {
/** The relative path to the base directory for documentation generation. */
private final String relativePathToBaseDirectory;
/**
* Constructs an instance of this traverser/generator.
* @param relativePathToBaseDirectory the relative path to the base directory for documentation generation.
*/
TypeSignatureHTMLGeneratorUsingNonLocalReferences(String relativePathToBaseDirectory) {
super(true);
this.relativePathToBaseDirectory = relativePathToBaseDirectory;
}
/**
* Generates a reference to a type class, hyperlinked as non-local references.
*
* @param moduleName the module name of the type class.
* @param unqualifiedName the unqualified name of the type class.
*/
@Override
void generateTypeClassReference(ModuleName moduleName, String unqualifiedName) {
String typeClassLabel = labelMaker.getTypeClassLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName);
if (!isDocForTypeClassGenerated(moduleName, unqualifiedName)) {
currentPage.addText(appropriatelyQualifiedName);
} else {
generateNonLocalReference(currentPage, relativePathToBaseDirectory, moduleName, typeClassLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
/**
* Generates a reference to a type constructor, hyperlinked as non-local references.
*
* @param moduleName the module name of the type constructor.
* @param unqualifiedName the unqualified name of the type constructor.
*/
@Override
void generateTypeConsReference(ModuleName moduleName, String unqualifiedName) {
String typeConsLabel = labelMaker.getTypeConsLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName);
if (!isDocForTypeConsGenerated(moduleName, unqualifiedName)) {
currentPage.addText(appropriatelyQualifiedName);
} else {
generateNonLocalReference(currentPage, relativePathToBaseDirectory, moduleName, typeConsLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
}
/**
* Implements a cross-reference generator to be used by the text-block-to-HTML generation utility.
* The implementation simply bridges to existing methods for generating references in the outer class.
*
* @author Joseph Wong
*/
private final class ReferenceGenerator extends CALDocToHTMLUtilities.CrossReferenceHTMLGenerator {
/**
* The relative directory path for getting to the modules subdirectory.
*/
private final String relativeDirectory;
/**
* Constructs a ReferenceGenerator where the file to receive the cross-references is itself located
* in the modules directory.
*/
private ReferenceGenerator() {
this.relativeDirectory = null;
}
/**
* Constructs a ReferenceGenerator with the given relative directory path for getting to the modules subdirectory.
* @param relativeDirectory the relative directory path for getting to the modules subdirectory.
*/
private ReferenceGenerator(String relativeDirectory) {
this.relativeDirectory = relativeDirectory;
}
/**
* Generates HTML for a module cross-reference.
* @param builder the HTMLBuilder to use for generating the cross-reference.
* @param reference the module cross-reference.
*/
@Override
final void generateModuleReference(HTMLBuilder builder, CALDocComment.ModuleReference reference) {
HTMLDocumentationGenerator.this.generateModuleReference(builder, relativeDirectory, reference);
}
/**
* Generates HTML for a type constructor cross-reference.
* @param builder the HTMLBuilder to use for generating the cross-reference.
* @param reference the type constructor cross-reference.
*/
@Override
final void generateTypeConsReference(HTMLBuilder builder, CALDocComment.ScopedEntityReference reference) {
HTMLDocumentationGenerator.this.generateTypeConsReference(builder, relativeDirectory, reference.getName(), reference.getModuleNameInSource());
}
/**
* Generates HTML for a data constructor cross-reference.
* @param builder the HTMLBuilder to use for generating the cross-reference.
* @param reference the data constructor cross-reference.
*/
@Override
final void generateDataConsReference(HTMLBuilder builder, CALDocComment.ScopedEntityReference reference) {
HTMLDocumentationGenerator.this.generateDataConsReference(builder, relativeDirectory, reference.getName(), reference.getModuleNameInSource());
}
/**
* Generates HTML for a function or class method cross-reference.
* @param builder the HTMLBuilder to use for generating the cross-reference.
* @param reference the function or class method cross-reference.
*/
@Override
final void generateFunctionOrClassMethodReference(HTMLBuilder builder, CALDocComment.ScopedEntityReference reference) {
HTMLDocumentationGenerator.this.generateFunctionOrClassMethodReference(builder, relativeDirectory, reference.getName(), reference.getModuleNameInSource());
}
/**
* Generates HTML for a type class cross-reference.
* @param builder the HTMLBuilder to use for generating the cross-reference.
* @param reference the type class cross-reference.
*/
@Override
final void generateTypeClassReference(HTMLBuilder builder, CALDocComment.ScopedEntityReference reference) {
HTMLDocumentationGenerator.this.generateTypeClassReference(builder, relativeDirectory, reference.getName(), reference.getModuleNameInSource());
}
}
/**
* Encapsulates the information for a node representing a module in a tree view
* (e.g. in the module list and in the overview page).
*
* @author Joseph Wong
*/
private static final class ModuleHierarchyInfo {
/**
* A sorted map from the pairs (ModuleName, (Boolean)isActualModule) of children to the corresponding ModuleHierarchyInfos.
*/
private final SortedMap<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> children =
new TreeMap<Pair<ModuleName, Boolean>, ModuleHierarchyInfo>(
new Comparator<Pair<ModuleName, Boolean>>() {
public int compare(final Pair<ModuleName, Boolean> a, final Pair<ModuleName, Boolean> b) {
final int moduleNameResult = a.fst().compareTo(b.fst());
if (moduleNameResult != 0) {
// first order by module names
return moduleNameResult;
} else {
// if module names are equal
// we want true < false so that actual modules come before namespaces with the same name
if (a.snd() == Boolean.TRUE) {
if (b.snd() == Boolean.FALSE) {
return -1;
} else {
return 0;
}
} else {
if (b.snd() == Boolean.TRUE) {
return 1;
} else {
return 0;
}
}
}
}});
/**
* Returns the ModuleHierarchyInfo for the child with the given name, creating it if necessary.
* @param childName the name of the child.
* @param isActualModule whether the child represents an actual module.
* @return the ModuleHierarchyInfo for the child.
*/
ModuleHierarchyInfo makeChild(final ModuleName childName, final boolean isActualModule) {
final Pair<ModuleName, Boolean> key = new Pair<ModuleName, Boolean>(childName, Boolean.valueOf(isActualModule));
final ModuleHierarchyInfo childFromMap = children.get(key);
if (childFromMap != null) {
return childFromMap;
} else {
final ModuleHierarchyInfo newChild = new ModuleHierarchyInfo();
children.put(key, newChild);
return newChild;
}
}
/**
* Returns the children map.
* @return the children map.
*/
SortedMap<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> getChildren() {
// this method is meant for internal use only, so we return the mutable map without wrapping it
return children;
}
}
/////====================================================================================================
////
/// Constructor and private helper methods
//
/////====================================================================================================
/**
* Package-scoped constructor for creating an instance of this class.
* @param workspaceManager the workspace manager.
* @param config the configuration.
*/
HTMLDocumentationGenerator(WorkspaceManager workspaceManager, HTMLDocumentationGeneratorConfiguration config) {
this(workspaceManager, workspaceManager.getWorkspace(), config, false);
}
/**
* Package-scoped constructor for creating an instance of this class.
* @param programModelManager the program model manager.
* @param workspace the CALWorkspace for metadata access. Can be null.
* @param config the configuration.
* @param disableAllHyperlinks whether to disable all hyperlinks globally.
*/
HTMLDocumentationGenerator(final ProgramModelManager programModelManager, final CALWorkspace workspace, final HTMLDocumentationGeneratorConfiguration config, final boolean disableAllHyperlinks) {
super(programModelManager, config.filter, config.shouldGenerateUsageIndices, config.logger);
this.workspace = workspace;
this.config = config;
this.disableAllHyperlinks = disableAllHyperlinks;
}
/**
* @return whether the documentation should include metadata.
*/
private boolean shouldGenerateFromMetadata() {
return config.shouldGenerateFromMetadata;
}
/**
* @return whether CALDoc should always be included in the documentation regardless of whether metadata is included or not.
*/
private boolean shouldAlwaysGenerateFromCALDoc() {
return config.shouldAlwaysGenerateFromCALDoc;
}
/**
* @return whether author info should be generated.
*/
private boolean shouldGenerateAuthorInfo() {
return config.shouldGenerateAuthorInfo;
}
/**
* @return whether version info should be generated.
*/
private boolean shouldGenerateVersionInfo() {
return config.shouldGenerateVersionInfo;
}
/**
* @return whether Prelude names should always be displayed as unqualified.
*/
private boolean shouldDisplayPreludeNamesAsUnqualified() {
return config.shouldDisplayPreludeNamesAsUnqualified;
}
/**
* @return the Locale for the generated documentation, in particular the metadata if included.
*/
private Locale getLocale() {
return config.locale;
}
/**
* Generates a text file using the UTF-8 encoding.
* @param fileName the name of the file to be generated.
* @param content the content of the file to be generated.
*/
private void generateTextFile(String fileName, String content) {
config.fileGenerator.generateTextFile(fileName, content, FileGenerator.UTF_8_CHARSET);
}
/**
* Generates a text file in a particular subdirectory of the base directory using the UTF-8 encoding.
* The subdirectory will be created if it does not exist.
*
* @param subdirectory the subdirectory name.
* @param fileName the name of the file to be generated.
* @param content the content of the file to be generated.
*/
private void generateTextFile(String subdirectory, String fileName, String content) {
config.fileGenerator.generateTextFile(subdirectory, fileName, content, FileGenerator.UTF_8_CHARSET);
}
/**
* Returns the metadata for the given feature.
* @param featureName the name of the feature.
* @param locale the locale associated with the metadata.
* @return the metadata, or which could be empty if the workspace is null or if there is no metadata for the feature.
*/
private CALFeatureMetadata getMetadata(final CALFeatureName featureName, final Locale locale) {
if (workspace == null) {
return MetadataManager.getEmptyMetadata(featureName, locale);
} else {
return workspace.getMetadata(featureName, locale);
}
}
/**
* Returns the metadata for a scoped entity.
* @param entity the entity.
* @param locale the locale associated with the metadata.
* @return the metadata, or which could be empty if the workspace is null or if there is no metadata for the entity.
*/
private ScopedEntityMetadata getMetadata(final FunctionalAgent entity, final Locale locale) {
if (workspace == null) {
return MetadataManager.getEmptyMetadata(entity, locale);
} else {
return workspace.getMetadata(entity, locale);
}
}
/**
* Helper method to create a new HTMLBuilder to start a new page.
*/
private void startNewCurrentPage() {
currentPage = new HTMLBuilder();
}
/**
* Helper method to create a new HTMLBuilder to start a new page.
*/
void startNewCurrentPageWithModule(ModuleName moduleName) {
startNewCurrentPage();
currentModuleName = moduleName;
}
/**
* Helper method (for other clients in this package) to obtain the HTML for the currently generated page.
* @return the HTML.
*/
String getCurrentPageHTML() {
return currentPage.toHTML();
}
/////====================================================================================================
////
/// General HTML and CSS generation helpers
//
/**
* Constructs the title text of the page, to be displayed in the window title.
* @param mainTitle the main identifying component of the title.
* @return the proper title for the page.
*/
private String makePageTitle(String mainTitle) {
if (config.windowTitle.length() > 0) {
return LocalizableUserVisibleString.WINDOW_TITLE_TEMPLATE.toResourceString(mainTitle, config.windowTitle);
} else {
return mainTitle;
}
}
/**
* Constructs the HTML attributes for a <tt>link</tt> element for associating
* the HTML page with an external CSS file.
*
* @param rel the rel attribute.
* @param title the title attribute.
* @param href the href attribute.
* @return the list of HTML attributes for the <tt>link</tt> element.
*/
private static HTMLBuilder.AttributeList getStylesheetAttributes(String rel, String title, String href) {
return HTMLBuilder.AttributeList.make(
HTML.Attribute.REL, rel,
HTML.Attribute.TYPE, "text/css",
HTML.Attribute.TITLE, title,
HTML.Attribute.HREF, href);
}
/**
* Generates the <tt>head</tt> section of the HTML file.
*
* @param title the title of the page.
* @param relativePathToBaseDirectory the relative path to the base documentation directory.
* @param linkTargetName if not null, specifies that a <tt>base</tt> element should be included containing the target name. Can be null.
* @param javascript if not null, specifies a javascript section to be included with the head section.
* @param additionalCSS if not null, specifies a Map (style id -> css text) of additional style sheets to include.
*/
private void generateHeadSection(String title, String relativePathToBaseDirectory, String linkTargetName, String javascript, Map<String, String> additionalCSS) {
currentPage
.openTag(HTML.Tag.HEAD)
.addTaggedText(HTML.Tag.TITLE, title)
.emptyTag(HTML.Tag.META, HTMLBuilder.AttributeList.make(
HTML.Attribute.HTTPEQUIV, "Content-Type",
HTML.Attribute.CONTENT, "text/html; charset=UTF-8"));
if (additionalCSS != null) {
for (final Map.Entry<String, String> entry : additionalCSS.entrySet()) {
String id = entry.getKey();
String css = entry.getValue();
currentPage.addTaggedText(HTML.Tag.STYLE, idAttribute(id).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/css")), css);
}
}
currentPage
.emptyTag(HTML.Tag.LINK,
getStylesheetAttributes("stylesheet", LocalizableUserVisibleString.DEFAULT.toResourceString(), relativePathToBaseDirectory + DEFAULT_CSS_FILENAME))
.emptyTag(HTML.Tag.LINK,
getStylesheetAttributes("alternate stylesheet", LocalizableUserVisibleString.FOR_PRINTING.toResourceString(), relativePathToBaseDirectory + PRINTED_VERSION_CSS_FILENAME))
.emptyTag(HTML.Tag.LINK,
HTMLBuilder.AttributeList.make(HTML4.MEDIA_ATTRIBUTE, "print")
.concat(getStylesheetAttributes("stylesheet", LocalizableUserVisibleString.FOR_PRINTING.toResourceString(), relativePathToBaseDirectory + PRINTED_VERSION_CSS_FILENAME)));
if (linkTargetName != null) {
currentPage.emptyTag(HTML.Tag.BASE, HTMLBuilder.AttributeList.make(HTML.Attribute.TARGET, linkTargetName));
}
if (javascript != null) {
currentPage.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"), javascript);
}
currentPage.closeTag(HTML.Tag.HEAD);
}
/**
* Generates the <tt>head</tt> section of the HTML file.
*
* @param title the title of the page.
* @param relativePathToBaseDirectory the relative path to the base documentation directory.
* @param linkTargetName if not null, specifies that a <tt>base</tt> element should be included containing the target name. Can be null.
* @param javascript if not null, specifies a javascript section to be included with the head section.
*/
private void generateHeadSection(String title, String relativePathToBaseDirectory, String linkTargetName, String javascript) {
String hideNonPublicStyleCSS =
new CSSBuilder().addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NON_PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.NONE)).toCSS();
generateHeadSection(title, relativePathToBaseDirectory, linkTargetName, javascript, Collections.singletonMap(ElementID.HIDE_NONPUBLIC_STYLE, hideNonPublicStyleCSS));
}
/**
* Generates the javascript function for updating the scope display settings on the current page based on the settings
* stored in the top level frameset (if it exists).
*/
private void generateUpdateScopeDisplaySettingsJavascript() {
String script = getUpdateScopeDisplaySettingsJavascript();
currentPage.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"), script);
}
/**
* @return the javascript function for updating the scope display settings on the current page based on the settings
* stored in the top level frameset (if it exists).
*/
private String getUpdateScopeDisplaySettingsJavascript() {
String script =
"\n" +
"function getCssRule(styleElem, index) {\n" +
" if (styleElem.cssRules) {\n" +
" return styleElem.cssRules[index];\n" +
" } else if (styleElem.rules) {\n" +
" return styleElem.rules[index];\n" +
" }\n" +
"}\n" +
"var safari = (('' + navigator.vendor).indexOf('Apple') >= 0);\n" +
"\n" +
"function changeStyle(styleElem, disabled) {\n" +
" if (safari) {\n" +
" getCssRule(styleElem, 0).style.cssText = !parent.isPublicOnlyScope() ? '' : 'display: none';\n" +
" } else {\n" +
" styleElem.disabled = disabled;\n" +
" }\n" +
"}\n" +
"\n" +
"function updateScopeDisplaySettings() {\n" +
" var styleElement = document.styleSheets[0]; //document.getElementById('" + ElementID.HIDE_NONPUBLIC_STYLE + "');\n" +
" if (styleElement) {\n" +
" if (parent && parent.isPublicOnlyScope) {\n" +
" changeStyle(styleElement, !parent.isPublicOnlyScope());\n" +
" } else {\n" +
" changeStyle(styleElement, true);\n" +
" }\n" +
" }\n" +
"}\n" +
"\n" +
"updateScopeDisplaySettings(); // run it immediately\n";
return script;
}
/**
* Constructs the text of the default CSS file for display within a small area.
* @return the CSS file's contents.
*/
/*
* @implementation this method is exposed via package scope to allow reuse by the CALDocToTooltipHTMLUtilities
*/
static String getCompactDisplayCSS() {
CSSBuilder cssBuilder = new CSSBuilder();
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.BODY))
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_SIZE, "11px")
.addAttribute(CSS.Attribute.LINE_HEIGHT, "14px")
.addAttribute(CSS.Attribute.MARGIN, "3px")
.addAttribute(CSS.Attribute.PADDING, "0px"));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.DL))
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.TWO_PX_THIN));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.DD))
.addAttribute(CSS.Attribute.MARGIN_LEFT, "10px"));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeType(HTML.Tag.DD), CSSBuilder.Selector.makeType(HTML.Tag.DD)))
.addAttribute(CSS.Attribute.MARGIN_LEFT, "20px"));
return getStandardCSS(cssBuilder, "2px", StyleValueConstants.CAL_EDITOR_HOVER_BACKGROUND_COLOR);
}
/**
* Constructs the text of the default CSS file.
* @return the CSS file's contents.
*/
private static String getDefaultCSS() {
CSSBuilder cssBuilder = new CSSBuilder();
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.BODY))
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_SIZE, "11px"));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.BODY))
.addAttribute(CSS.Attribute.LINE_HEIGHT, "1.7em"));
return getStandardCSS(cssBuilder, StyleValueConstants.ONE_EM_WIDTH,
StyleValueConstants.WHITE);
}
/**
* Constructs the text of the CSS file for formatting for printing.
* @return the CSS file's contents.
*/
private static String getPrintedVersionCSS() {
CSSBuilder cssBuilder = new CSSBuilder();
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.BODY))
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_SIZE, "11pt"));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.CODE))
.addAttribute(CSS.Attribute.FONT_SIZE, "10pt"));
return getStandardCSS(cssBuilder, StyleValueConstants.ONE_EM_WIDTH, StyleValueConstants.WHITE);
}
/**
* Constructs the common portion of the CSS files using the specified builder.
* @param cssBuilder the builder to use for building the CSS.
* @param defintionLineTopBottomMargin the top/bottom margin surrounding a line containing a definition.
* @return the CSS file's contents.
*/
private static String getStandardCSS(final CSSBuilder cssBuilder,
final String defintionLineTopBottomMargin,
final String bodyBackgroundColor) {
////
/// General styles
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.WITH_MAIN_CONTENT))
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.ZERO_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MAIN_CONTENT))
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.MAIN_CONTENT_MARGIN));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.BODY))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, bodyBackgroundColor));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NON_DISPLAYED_HEADER))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.NONE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.H1))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.X_LARGE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.H2))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.H1), CSSBuilder.Selector.makeType(HTML.Tag.H2))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(StyleClassConstants.A_LINK_PSEUDOCLASS_SELECTOR)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(
StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR,
CSSBuilder.Selector.makeDescendant(StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR, CSSBuilder.Selector.makeClass(StyleClassConstants.TYPE_CONSTRAINT)))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeType(HTML.Tag.A), CSSBuilder.Selector.makeClass(StyleClassConstants.TYPE_CONSTRAINT)))
.addAttribute(CSS.Attribute.TEXT_DECORATION, StyleValueConstants.UNDERLINE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(StyleClassConstants.A_VISITED_PSEUDOCLASS_SELECTOR)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.VISITED_LINK_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.IMPORTANT_LINK))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGER));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(
CSSBuilder.Selector.makeClass(CSSBuilder.Selector.makeType(HTML.Tag.DIV), StyleClassConstants.PUBLIC_SCOPE),
CSSBuilder.Selector.makeClass(CSSBuilder.Selector.makeType(HTML.Tag.DIV), StyleClassConstants.NON_PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.ZERO_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MAJOR_SECTION))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.MAJOR_SECTION_TOP_AND_SIDE_PADDING)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.ONE_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MINOR_SECTION))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGER)
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.TWO_PX_THIN + " " + StyleValueConstants.SOLID + " " + StyleValueConstants.OPENQUARK_RED));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MINOR_SECTION_ALTERNATE))
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.TWO_PX_THIN + " " + StyleValueConstants.SOLID + " " + StyleValueConstants.OPENQUARK_SECONDARY_KHAKI));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.PAGE_BOTTOM))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.SMALLER));
// Create a hanging indent look for a type signature (namd and type).
// This is done by making the type signature display as a block, with some padding on the left,
// but with a *negative* text indent by the same amount applied so that the first line juts out to the left.
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NAME_AND_TYPE))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.BLOCK)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.TYPE_SIGNATURE_HANGING_INDENT)
.addAttribute(CSS.Attribute.TEXT_INDENT, "-" + StyleValueConstants.TYPE_SIGNATURE_HANGING_INDENT));
////
/// Side bars
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MODULE_LIST_PAGE_TITLE))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.MEDIUM)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.NAV_BAR_PADDING)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.ZERO_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MODULE_LIST_NAV_BAR))
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.NAV_BAR_PADDING)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.MODULE_LIST_SECTION_TITLE))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_LIGHTER)
.addAttribute(CSS.Attribute.BORDER_LEFT, StyleValueConstants.MODULE_LIST_SECTION_TITLE_LEFT_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF)
.addAttribute(CSS.Attribute.BORDER_TOP, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_RIGHT, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE));
// we do not indent the <div> for the outermost level, so we use a descendant selector
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_DIV), CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_DIV)))
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.TREE_INDENT));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_NODE_TOGGLE))
.addAttribute(CSS2Attribute.CURSOR, StyleValueConstants.POINTER)
.addAttribute(CSS.Attribute.BORDER, StyleValueConstants.TREE_NODE_TOGGLE_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.TWO_PX_THIN)
.addAttribute(CSS.Attribute.PADDING_RIGHT, StyleValueConstants.TWO_PX_THIN)
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.MONOSPACE_FONT_LIST));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makePseudoClass(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_NODE_TOGGLE), "hover"))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TREE_NODE_TOGGLE_HOVER_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_NODE_TOGGLE_PLACEHOLDER))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.WHITE)
.addAttribute(CSS.Attribute.BORDER_COLOR, StyleValueConstants.WHITE)
.addAttribute(CSS.Attribute.BORDER_STYLE, StyleValueConstants.SOLID)
.addAttribute(CSS.Attribute.BORDER_WIDTH, StyleValueConstants.THIN)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.TWO_PX_THIN)
.addAttribute(CSS.Attribute.PADDING_RIGHT, StyleValueConstants.TWO_PX_THIN)
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.MONOSPACE_FONT_LIST));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SIDE_BAR_KHAKI_TITLE))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.MEDIUM)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_COLOR)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.SIDE_BAR_TITLE_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SIDE_BAR_KHAKI_SUPERTITLE))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_SUPERTITLE_COLOR)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.SIDE_BAR_TITLE_PADDING)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.ZERO_WIDTH));
////
/// Display mode toolbar
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TOOLBAR))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TOOLBAR_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.TOOLBAR_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.TOOLBAR), CSSBuilder.Selector.makeType(HTML.Tag.A)))
.addAttribute(CSS2Attribute.CURSOR, StyleValueConstants.POINTER)
.addAttribute(CSS.Attribute.BORDER, StyleValueConstants.TOOLBAR_BUTTON_BORDER_STYLE)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TOOLBAR_BUTTON_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.TOOLBAR_BUTTON_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.TOOLBAR), StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR))
.addAttribute(CSS.Attribute.BORDER, StyleValueConstants.TOOLBAR_BUTTON_BLACK_BORDER_STYLE)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TOOLBAR_BUTTON_HOVER_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.TOOLBAR), CSSBuilder.Selector.makeClass(CSSBuilder.Selector.makeType(HTML.Tag.A), StyleClassConstants.BUTTON_SELECTED)))
.addAttribute(CSS.Attribute.BORDER, StyleValueConstants.TOOLBAR_BUTTON_BLACK_BORDER_STYLE)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TOOLBAR_BUTTON_SELECTED_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SUB_TOOLBAR))
.addAttribute(CSS.Attribute.TEXT_ALIGN, StyleValueConstants.RIGHT_ALIGN)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.SUB_TOOLBAR_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.SUB_TOOLBAR_BUTTON_TOP_BOTTOM_PADDING)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.SUB_TOOLBAR_BUTTON_TOP_BOTTOM_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.SUB_TOOLBAR), CSSBuilder.Selector.makePseudoClass(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_NODE_TOGGLE), "hover")))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TOOLBAR_BUTTON_HOVER_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.BORDER, StyleValueConstants.TOOLBAR_BUTTON_BLACK_BORDER_STYLE));
////
/// Overview Page
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_DIV_OVERVIEW_PAGE), CSSBuilder.Selector.makeClass(StyleClassConstants.TREE_DIV_OVERVIEW_PAGE)))
.addAttribute(CSS.Attribute.BORDER_LEFT, StyleValueConstants.TREE_DIV_OVERVIEW_PAGE_LEFT_BORDER_STYLE)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.TREE_DIV_OVERVIEW_PAGE_BOTTOM_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.TREE_DIV_OVERVIEW_PAGE_BOTTOM_MARGIN));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DL_OVERVIEW_PAGE))
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.TREE_DIV_OVERVIEW_PAGE_BOTTOM_MARGIN)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.DL_OVERVIEW_PAGE_BOTTOM_PADDING)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.DL_OVERVIEW_PAGE_BORDER_STYLE));
////
/// Search Page
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SEARCH_BOX_TITLE))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGER)
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_COLOR)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SEARCH_BOX))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.SEARCH_BOX_TOP_PADDING)
.addAttribute(CSS.Attribute.PADDING_RIGHT, StyleValueConstants.SEARCH_BOX_RIGHT_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.SEARCH_FIELD))
.addAttribute(CSS.Attribute.WIDTH, StyleValueConstants.ONE_HUNDRED_PERCENT));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeType(HTML.Tag.FORM))
.addAttribute(CSS.Attribute.MARGIN, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.ZERO_WIDTH));
////
/// Code blocks
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.CODE_BLOCK))
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.MONOSPACE_FONT_LIST)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.CODE_BLOCK_SIDE_PADDING)
.addAttribute(CSS.Attribute.PADDING_RIGHT, StyleValueConstants.CODE_BLOCK_SIDE_PADDING)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.CODE_BLOCK_COLOR)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.CODE_BLOCK_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(CSSBuilder.Selector.makeType(HTML.Tag.PRE), StyleClassConstants.CODE_BLOCK))
.addAttribute(CSS.Attribute.BORDER_STYLE, StyleValueConstants.SOLID)
.addAttribute(CSS.Attribute.BORDER_WIDTH, StyleValueConstants.THIN)
.addAttribute(CSS.Attribute.BORDER_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_SIDE_BAR_TITLE_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.CODE_BLOCK), CSSBuilder.Selector.makeType(HTML.Tag.A)))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.CODE_BLOCK_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.ABSTRACT_DEPRECATED_BLOCK), CSSBuilder.Selector.makeClass(StyleClassConstants.CODE_BLOCK)))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.DEPRECATED_BLOCK_CODE_BLOCK_COLOR));
////
/// Deprecated blocks
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.ABSTRACT_DEPRECATED_BLOCK))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.DEPRECATED_BLOCK_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.BORDER_WIDTH, StyleValueConstants.THIN)
.addAttribute(CSS.Attribute.BORDER_STYLE, StyleValueConstants.SOLID)
.addAttribute(CSS.Attribute.BORDER_COLOR, StyleValueConstants.DEPRECATED_BLOCK_BORDER_COLOR)
.addAttribute(CSS.Attribute.FONT_STYLE, StyleValueConstants.ITALIC)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.ONE_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_DEPRECATED_BLOCK))
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.DEPRECATED_BLOCK_CLEARANCE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DEPRECATED_BLOCK))
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.DEPRECATED_BLOCK_CLEARANCE));
////
/// Module overview
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_TABLE))
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.TWO_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_TABLE), CSSBuilder.Selector.makeType(HTML.Tag.DL)))
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.ZERO_WIDTH)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.ZERO_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_TABLE), CSSBuilder.Selector.makeType(HTML.Tag.CAPTION)))
.addAttribute(CSS.Attribute.WIDTH, StyleValueConstants.AUTO_WIDTH)
.addAttribute(CSS.Attribute.TEXT_ALIGN, StyleValueConstants.LEFT_ALIGN));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN))
.addAttribute(CSS.Attribute.WIDTH, StyleValueConstants.TWO_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_NESTED_TABLE))
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.ONE_POINT_FIVE_EM_WIDTH)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OVERVIEW_NESTED_TABLE_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.BORDER_COLOR, StyleValueConstants.OVERVIEW_NESTED_TABLE_BORDER_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_TABLE_DESCRIPTION))
.addAttribute(CSS.Attribute.MARGIN_LEFT, StyleValueConstants.TWO_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OVERVIEW_REFERENCE))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
// Create a hanging indent look for a related modules list.
// This is done by making the display as a block, with some padding on the left,
// but with a *negative* text indent by the same amount applied so that the first line juts out to the left.
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.RELATED_MODULES_LIST))
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.RELATED_MODULES_GROUPED_LIST_HANGING_INDENT)
.addAttribute(CSS.Attribute.TEXT_INDENT, "-" + StyleValueConstants.RELATED_MODULES_GROUPED_LIST_HANGING_INDENT));
////
/// Details section: high-level style classes
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DETAILS_LIST_HEADER))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI)
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DETAILS_LIST))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OVERVIEW_NESTED_TABLE_BACKGROUND_COLOR)
.addAttribute(CSS.Attribute.BORDER_WIDTH, StyleValueConstants.THIN)
.addAttribute(CSS.Attribute.BORDER_STYLE, StyleValueConstants.OUTSET_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.DETAILS_LIST_PADDING)
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.DETAILS_LIST_MARGIN_TOP));
////
/// Details section: low-level style classes
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.ATTRIBUTE_HEADER))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
/// CALDoc/metadata indicator
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.ABSTRACT_INDICATOR))
.addAttribute(CSS.Attribute.FONT_FAMILY, StyleValueConstants.SANS_SERIF_FONT_LIST)
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.INDICATOR_FONT_SIZE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.METADATA_INDICATOR))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.METADATA_INDICATOR_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.CALDOC_INDICATOR))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.CALDOC_INDICATOR_COLOR));
/// Class method indicator
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.CLASS_METHOD_INDICATOR))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.BLOCK)
.addAttribute(CSS.Attribute.FONT_STYLE, StyleValueConstants.ITALIC));
/// Definition - header section
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.ABSTRACT_DEFINITION_SECTION_START))
.addAttribute(CSS.Attribute.MARGIN_TOP, defintionLineTopBottomMargin));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DEFINITION_SECTION_START))
.addAttribute(CSS.Attribute.BORDER_TOP, StyleValueConstants.THIN + " " + StyleValueConstants.SOLID)
.addAttribute(CSS.Attribute.PADDING_TOP, defintionLineTopBottomMargin));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DEFINITION_HEADER))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGER));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DEFINITION_HEADER_FIRST_LINE))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.BLOCK)
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, defintionLineTopBottomMargin));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DECLARED_NAME))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DESCRIPTION_BLOCK))
.addAttribute(CSS.Attribute.MARGIN_TOP, StyleValueConstants.ONE_EM_WIDTH)
.addAttribute(CSS.Attribute.MARGIN_BOTTOM, StyleValueConstants.ONE_EM_WIDTH));
/// Argument names
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.ARG_NAME_NOT_FROM_CODE))
.addAttribute(CSS.Attribute.FONT_STYLE, StyleValueConstants.ITALIC));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.RETURN_VALUE_INDICIATOR))
.addAttribute(CSS.Attribute.FONT_STYLE, StyleValueConstants.ITALIC));
/// Type signatures
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TYPE_SIGNATURE))
.addAttribute(CSS2Attribute.TEXT_WRAP, StyleValueConstants.SUPPRESS_TEXT_WRAP));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TYPE_CONSTRAINT))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.TYPE_CONSTRAINT_BACKGROUND_COLOR));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.CAL_SYMBOL))
.addAttribute(CSS2Attribute.TEXT_WRAP, StyleValueConstants.NO_TEXT_WRAP)
.addAttribute(CSS.Attribute.WHITE_SPACE, StyleValueConstants.NOWRAP_WHITE_SPACE));
////
/// Navigation frames
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.INDEX_NAV))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI)
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.INDEX_NAV_LINK), CSSBuilder.Selector.makeType(HTML.Tag.A)))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.BLOCK)
.addAttribute(CSS.Attribute.BORDER_TOP, StyleValueConstants.INDEX_NAV_LINK_SEPARATOR_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.INDEX_NAV_LINK_PADDING)
.addAttribute(CSS.Attribute.PADDING_RIGHT, StyleValueConstants.INDEX_NAV_LINK_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.INDEX_NAV_CURRENT_LINK))
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD)
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI_LIGHTER)
.addAttribute(CSS.Attribute.BORDER_LEFT, StyleValueConstants.INDEX_NAV_CURRENT_LINK_LEFT_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF)
.addAttribute(CSS.Attribute.BORDER_TOP, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_RIGHT, StyleValueConstants.INDEX_NAV_CURRENT_LINK_BORDER_STYLE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.INDEX_NAV_LINK), StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_LIGHT_BLUE_HEADER_BACKGROUND)
.addAttribute(CSS.Attribute.BORDER_LEFT, StyleValueConstants.INDEX_NAV_CURRENT_LINK_LEFT_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF)
.addAttribute(CSS.Attribute.BORDER_TOP, StyleValueConstants.INDEX_NAV_LINK_SEPARATOR_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_TOP, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_BOTTOM, StyleValueConstants.INDEX_NAV_LINK_SEPARATOR_BORDER_STYLE)
.addAttribute(CSS.Attribute.PADDING_BOTTOM, StyleValueConstants.INDEX_NAV_LINK_PADDING_HALF_MINUS_ONE)
.addAttribute(CSS.Attribute.BORDER_RIGHT, StyleValueConstants.INDEX_NAV_LINK_SEPARATOR_BORDER_STYLE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.DISABLED_LINK))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.DISABLED_LINK_COLOR));
////
/// Options box
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeID(ElementID.OPTIONS_BOX))
.addAttribute(CSS.Attribute.DISPLAY, StyleValueConstants.NONE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OPTIONS_HEADER))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_LIGHT_BLUE_HEADER_BACKGROUND)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.SCOPE_DISPLAY_SETTINGS_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OPTIONS_BODY))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPTIONS_BODY_BACKGROUND)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE)
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.SCOPE_DISPLAY_SETTINGS_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.OPTIONS_CHOICE))
.addAttribute(CSS.Attribute.PADDING_LEFT, StyleValueConstants.ONE_EM_WIDTH));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.FAKE_LINK))
.addAttribute(CSS2Attribute.CURSOR, StyleValueConstants.POINTER)
.addAttribute(CSS.Attribute.TEXT_DECORATION, StyleValueConstants.UNDERLINE));
////
/// Navigation bars
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR))
.addAttribute(CSS.Attribute.FONT_SIZE, StyleValueConstants.LARGER));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR), CSSBuilder.Selector.makeType(HTML.Tag.DIV)))
.addAttribute(CSS.Attribute.PADDING, StyleValueConstants.NAV_BAR_PADDING));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_GLOBAL_ROW))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_LIGHT_BLUE_HEADER_BACKGROUND)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(
CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_GLOBAL_ROW), StyleClassConstants.A_LINK_PSEUDOCLASS_SELECTOR),
CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_GLOBAL_ROW), StyleClassConstants.A_VISITED_PSEUDOCLASS_SELECTOR))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_LIGHT_BLUE_HEADER_BACKGROUND)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_GLOBAL_ROW), StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI)
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_BLUE));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_LOCAL_ROW))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_LIGHT_BLUE_CONTENT_BACKGROUND));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeDescendant(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_LOCAL_ROW), StyleClassConstants.A_HOVER_PSEUDOCLASS_SELECTOR))
.addAttribute(CSS.Attribute.BACKGROUND_COLOR, StyleValueConstants.OPENQUARK_WEBSITE_KHAKI));
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NAV_BAR_HEADER_FOOTER))
.addAttribute(CSS.Attribute.TEXT_ALIGN, StyleValueConstants.RIGHT_ALIGN)
.addAttribute(CSS.Attribute.FONT_WEIGHT, StyleValueConstants.BOLD));
////
/// Tooltip fragments
//
cssBuilder.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.TOOLTIP_HEADER))
.addAttribute(CSS.Attribute.FONT_STYLE, StyleValueConstants.ITALIC));
return cssBuilder.toCSS();
}
/**
* Constructs the contents for an HTML file that is to comply with HTML 4.01 Transitional.
* @param htmlBuilder the builder containing the body of the HTML file (without the doctype).
* @return the contents of the file, with the doctype prepended.
*/
private static String getHTMLFileContentsWithDocTypeForMainFramePage(HTMLBuilder htmlBuilder) {
return DocTypeDecl.HTML_4_01_TRANSITIONAL + htmlBuilder.toHTML();
}
/////====================================================================================================
////
/// Generation of auxiliary pages (main frameset, module list, overview, navigational indices)
//
/**
* Constructs the contents for the main documentation HTML file, i.e. the frameset.
* @return the contents of the file.
*/
private String getMainPageHTML() {
startNewCurrentPage();
// Create the scope display javascript
String javascript =
"\n" +
"var scopeDisplay = 'publicOnly';\n" +
"function setPublicOnlyScope() { scopeDisplay = 'publicOnly'; updateFrames(); }\n" +
"function isPublicOnlyScope() { return scopeDisplay == 'publicOnly'; }\n" +
"function setDisplayAllScopes() { scopeDisplay = 'all'; updateFrames(); }\n" +
"function updateFrames() { for (var i = 0; i < frames.length; i++) { var f = frames[i]; if (f.updateScopeDisplaySettings) { f.updateScopeDisplaySettings() } } }";
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = ""; // the main page is in the base directory
generateHeadSection(config.windowTitle, relativePathToBaseDirectory, null, javascript);
currentPage
.openTag(HTML.Tag.FRAMESET, idAttribute(ElementID.OUTER_FRAMESET).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.COLS, "250, 100%, 0%")))
.openTag(HTML.Tag.FRAMESET, HTMLBuilder.AttributeList.make(HTML.Attribute.ROWS, "45%, 55%"))
.emptyTag(HTML.Tag.FRAME, HTMLBuilder.AttributeList.make(HTML.Attribute.NAME, MODULE_LIST_FRAME_NAME, HTML.Attribute.SRC, MODULE_LIST_FILENAME, HTML.Attribute.SCROLLING, "yes"))
.emptyTag(HTML.Tag.FRAME, HTMLBuilder.AttributeList.make(HTML.Attribute.NAME, NAV_FRAME_NAME, HTML.Attribute.SCROLLING, "yes"))
.closeTag(HTML.Tag.FRAMESET)
.emptyTag(HTML.Tag.FRAME, HTMLBuilder.AttributeList.make(HTML.Attribute.NAME, MAIN_FRAME_NAME, HTML.Attribute.SRC, OVERVIEW_PAGE_FILENAME, HTML.Attribute.SCROLLING, "yes"))
.emptyTag(HTML.Tag.FRAME, HTMLBuilder.AttributeList.make(HTML.Attribute.NAME, SEARCH_FRAME_NAME, HTML.Attribute.SCROLLING, "yes"))
.closeTag(HTML.Tag.FRAMESET)
.closeTag(HTML.Tag.HTML);
return DocTypeDecl.HTML_4_01_FRAMESET + currentPage.toHTML();
}
/**
* Returns a representation of the modules arranged in a hierarchy.
* @param moduleNames the names of the modules.
* @return a representation of the modules arranged in a hierarchy.
*/
private ModuleHierarchyInfo getModuleHierarchy(final Set<ModuleName> moduleNames) {
final ModuleHierarchyInfo root = new ModuleHierarchyInfo();
for (final ModuleName moduleName : moduleNames) {
final int nModuleNameComponents = moduleName.getNComponents();
ModuleHierarchyInfo parent = root;
for (int i = 0; i < nModuleNameComponents; i++) {
final ModuleName prefix = moduleName.getPrefix(i+1); // goes from 1 to nComponents
final boolean isActualModule = (i == nModuleNameComponents - 1);
final ModuleHierarchyInfo child = parent.makeChild(prefix, isActualModule);
// for next iteration:
parent = child;
}
}
return root;
}
/**
* Returns a representation of the modules arranged into groups, categorized by their
* immediate prefixes.
* @param moduleNames the names of the modules.
* @return a representation of the modules arranged into groups.
*/
private ModuleHierarchyInfo getFlatModuleGrouping(final Set<ModuleName> moduleNames) {
final ModuleHierarchyInfo root = new ModuleHierarchyInfo();
for (final ModuleName moduleName : moduleNames) {
final ModuleName immediatePrefix = moduleName.getImmediatePrefix();
if (immediatePrefix == null) {
root.makeChild(moduleName, true);
} else {
final ModuleHierarchyInfo parent = root.makeChild(immediatePrefix, false);
parent.makeChild(moduleName, true);
}
}
return root;
}
/**
* Constructs the contents for the module list HTML file.
* @return the contents of the file.
*/
private String getModuleListPageHTML() {
startNewCurrentPage();
currentPage.openTag(HTML.Tag.HTML);
String highlightPublicCSS =
new CSSBuilder()
.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NON_PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPTIONS_BODY_BACKGROUND))
.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_RED))
.toCSS();
String highlightNonPublicCSS =
new CSSBuilder()
.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.NON_PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPENQUARK_RED))
.addRuleSet(new CSSBuilder.RuleSet(CSSBuilder.Selector.makeClass(StyleClassConstants.PUBLIC_SCOPE))
.addAttribute(CSS.Attribute.COLOR, StyleValueConstants.OPTIONS_BODY_BACKGROUND))
.toCSS();
LinkedHashMap<String, String> cssMap = new LinkedHashMap<String, String>();
cssMap.put(ElementID.HIGHLIGHT_PUBLIC_STYLE, highlightPublicCSS);
cssMap.put(ElementID.HIGHLIGHT_NONPUBLIC_STYLE, highlightNonPublicCSS);
String relativePathToBaseDirectory = ""; // the module list page is in the base directory
generateHeadSection(
makePageTitle(LocalizableUserVisibleString.MODULES.toResourceString()),
relativePathToBaseDirectory,
MAIN_FRAME_NAME,
null,
cssMap);
currentPage.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "setInitialModuleListDisplayMode()")));
/// Set up scope display options box's javascript support
//
currentPage
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"var pubStyleElement = document.styleSheets[0]; //document.getElementById('" + ElementID.HIGHLIGHT_PUBLIC_STYLE + "');\n" +
"var nonPubStyleElement = document.styleSheets[1]; //document.getElementById('" + ElementID.HIGHLIGHT_NONPUBLIC_STYLE + "');\n" +
"\n" +
"function getCssRule(styleElem, index) {\n" +
" if (styleElem.cssRules) {\n" +
" return styleElem.cssRules[index];\n" +
" } else if (styleElem.rules) {\n" +
" return styleElem.rules[index];\n" +
" }\n" +
"}\n" +
"\n" +
"var allRules = new Array(\n" +
" new Array(\n" +
" getCssRule(pubStyleElement, 0).style.cssText,\n" +
" getCssRule(pubStyleElement, 1).style.cssText),\n" +
" new Array(\n" +
" getCssRule(nonPubStyleElement, 0).style.cssText,\n" +
" getCssRule(nonPubStyleElement, 1).style.cssText));\n" +
"\n" +
"var safari = (('' + navigator.vendor).indexOf('Apple') >= 0);\n" +
"\n" +
"function changeStyle(styleElem, rules, disabled) {\n" +
" if (safari) {\n" +
" for (var i = 0; i < 2; i++) {\n" +
" getCssRule(styleElem, i).style.cssText = disabled ? '' : rules[i];\n" +
" }\n" +
" } else {\n" +
" styleElem.disabled = disabled;\n" +
" }\n" +
"}\n" +
"\n" +
"function updateScopeDisplaySettings() {\n" +
" if (pubStyleElement && nonPubStyleElement) {\n" +
" if (parent && parent.isPublicOnlyScope) {\n" +
" changeStyle(pubStyleElement, allRules[0], !parent.isPublicOnlyScope());\n" +
" changeStyle(nonPubStyleElement, allRules[1], parent.isPublicOnlyScope());\n" +
" } else {\n" +
" changeStyle(pubStyleElement, allRules[0], true);\n" +
" changeStyle(nonPubStyleElement, allRules[1], false);\n" +
" }\n" +
" }\n" +
"}\n" +
"\n" +
"updateScopeDisplaySettings(); // run it immediately\n");
currentPage
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"function toggleOptionsBox() {\n" +
" var optionsBox = document.getElementById('" + ElementID.OPTIONS_BOX + "');\n" +
" if (optionsBox && optionsBox.style) {\n" +
" if (optionsBox.style.display != 'block') {\n" + // by default the box is hidden, so the first toggle operation should show it
" optionsBox.style.display = 'block';\n" +
" } else {\n" +
" optionsBox.style.display = 'none';\n" +
" }\n" +
" }\n" +
"}\n" +
"\n" +
"function setPublicOnlyScope() {\n" +
" if (parent && parent.setPublicOnlyScope) {\n" +
" parent.setPublicOnlyScope();\n" +
" }\n" +
"}\n" +
"\n" +
"function setDisplayAllScopes() {\n" +
" if (parent && parent.setDisplayAllScopes) {\n" +
" parent.setDisplayAllScopes();\n" +
" }\n" +
"}\n");
generateModuleListDisplayModeJavascript(0, "moduleList");
/// Add the main links
//
currentPage
.addTaggedText(HTML.Tag.H2, classAttribute(StyleClassConstants.MODULE_LIST_PAGE_TITLE), config.docTitle)
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MODULE_LIST_NAV_BAR))
.addTaggedText(HTML.Tag.A, classAttribute(StyleClassConstants.IMPORTANT_LINK).concat(nonLocalHrefAttribute(OVERVIEW_PAGE_FILENAME)), LocalizableUserVisibleString.OVERVIEW.toResourceString())
.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString())
.addTaggedText(HTML.Tag.A, classAttribute(StyleClassConstants.IMPORTANT_LINK).concat(nonLocalHrefAttribute(MASTER_SCOPED_ENTITY_SEARCH_PAGE_FILENAME)).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TARGET, SEARCH_FRAME_NAME)), LocalizableUserVisibleString.SEARCH.toResourceString())
.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString())
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.IMPORTANT_LINK))
.addTaggedText(HTML.Tag.A, classAttribute(StyleClassConstants.FAKE_LINK).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "toggleOptionsBox();")).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TARGET, SEARCH_FRAME_NAME)), LocalizableUserVisibleString.OPTIONS.toResourceString())
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DIV);
/// Add scope display controls
//
currentPage
.openTag(HTML.Tag.DIV, idAttribute(ElementID.OPTIONS_BOX))
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT))
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.OPTIONS_HEADER), LocalizableUserVisibleString.OPTIONS.toResourceString())
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.OPTIONS_BODY))
.addText(LocalizableUserVisibleString.SCOPE_FILTER_COLON.toResourceString())
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.OPTIONS_CHOICE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.PUBLIC_SCOPE), "• ")
.addTaggedText(HTML.Tag.A, classAttribute(StyleClassConstants.FAKE_LINK).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "setPublicOnlyScope();")), LocalizableUserVisibleString.PUBLIC_ITEMS_ONLY.toResourceString())
.closeTag(HTML.Tag.DIV)
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.OPTIONS_CHOICE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NON_PUBLIC_SCOPE), "• ")
.addTaggedText(HTML.Tag.A, classAttribute(StyleClassConstants.FAKE_LINK).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "setDisplayAllScopes();")), LocalizableUserVisibleString.SHOW_ALL_ITEMS.toResourceString())
.closeTag(HTML.Tag.DIV)
.closeTag(HTML.Tag.DIV)
.closeTag(HTML.Tag.DIV)
.closeTag(HTML.Tag.DIV);
/// Generate a link for each module documented.
/// The names of the documented modules form the keys in the moduleIndices map.
//
generateDisplayModeToolbars();
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_FLAT));
generateFlatModuleList();
currentPage.closeTag(HTML.Tag.DIV);
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_GROUPED));
final List<String> groupedNodeElementIDs = generateGroupedModuleList(getFlatModuleGrouping(moduleIndices.keySet()), false, null);
currentPage.closeTag(HTML.Tag.DIV);
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_HIERARCHICAL));
final List<String> hierarchicalNodeElementIDs = generateHierarchicalModuleList(getModuleHierarchy(moduleIndices.keySet()), 0, null);
currentPage.closeTag(HTML.Tag.DIV);
currentPage.closeTag(HTML.Tag.DIV);
generateExpandCollapseAllJavascript(groupedNodeElementIDs, hierarchicalNodeElementIDs);
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
return DocTypeDecl.HTML_4_01_TRANSITIONAL + currentPage.toHTML();
}
/**
* Generates the display mode toolbar and the sub-toolbars for expanding and collapsing trees.
*/
private void generateDisplayModeToolbars() {
// main toolbar
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLBAR))
.addTaggedText(HTML.Tag.B, LocalizableUserVisibleString.VIEW_COLON.toResourceString())
.addText(" ")
.addTaggedText(HTML.Tag.A, idAttribute(ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_FLAT).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "setModuleListDisplayMode(0);")), LocalizableUserVisibleString.FLAT.toResourceString())
.addText(" ")
.addTaggedText(HTML.Tag.A, idAttribute(ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_GROUPED).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "setModuleListDisplayMode(1);")), LocalizableUserVisibleString.GROUPED.toResourceString())
.addText(" ")
.addTaggedText(HTML.Tag.A, idAttribute(ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_HIERARCHICAL).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "setModuleListDisplayMode(2);")), LocalizableUserVisibleString.HIERARCHICAL.toResourceString())
.closeTag(HTML.Tag.DIV);
// flat tree toolbar (empty)
currentPage.addTaggedText(HTML.Tag.DIV, idAttribute(ElementID.SUB_TOOLBAR_MODULE_LIST_FLAT), "");
// grouped tree toolbar
final String callToExpandAllGroupedNodes = "expandAllGroupedNodes();";
final String callToCollapseAllGroupedNodes = "collapseAllGroupedNodes();";
generateExpandCollapseAllSubToolbar(ElementID.SUB_TOOLBAR_MODULE_LIST_GROUPED, callToExpandAllGroupedNodes, callToCollapseAllGroupedNodes);
// hierarchical tree toolbar
final String callToExpandAllHierarchicalNodes = "expandAllHierarchicalNodes();";
final String callToCollapseAllHierarchicalNodes = "collapseAllHierarchicalNodes();";
generateExpandCollapseAllSubToolbar(ElementID.SUB_TOOLBAR_MODULE_LIST_HIERARCHICAL, callToExpandAllHierarchicalNodes, callToCollapseAllHierarchicalNodes);
}
/**
* Generates a sub-toolbar containing an "expand all" and a "collapse all" button.
* @param subToolbarElementID the element ID for the toolbar.
* @param callToExpandAll the javascript call to the expand all function.
* @param callToCollapseAll the javascript call to the collapse all function.
*/
private void generateExpandCollapseAllSubToolbar(final String subToolbarElementID, final String callToExpandAll, final String callToCollapseAll) {
currentPage
.openTag(HTML.Tag.DIV, idAndClassAttributes(subToolbarElementID, StyleClassConstants.SUB_TOOLBAR))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TREE_NODE_TOGGLE).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, callToExpandAll)), LocalizableUserVisibleString.EXPAND_BUTTON_LABEL.toResourceString())
.addText(" ")
.addText(LocalizableUserVisibleString.EXPAND_ALL.toResourceString().replaceAll(" ", " "))
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TREE_NODE_TOGGLE).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, callToCollapseAll)), LocalizableUserVisibleString.COLLAPSE_BUTTON_LABEL.toResourceString())
.addText(" ")
.addText(LocalizableUserVisibleString.COLLAPSE_ALL.toResourceString().replaceAll(" ", " "))
.closeTag(HTML.Tag.DIV);
}
/**
* Generates the javascript for switching the display mode of the module list and the overview page.
* @param initialDisplayMode the initial display mode to use (if there is no persisted user preference).
* @param cookiePrefix the prefix to use for the cookie for storing the user preference.
*/
private void generateModuleListDisplayModeJavascript(int initialDisplayMode, String cookiePrefix) {
currentPage
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"function setModuleListDisplayMode(mode) {\n" +
" var moduleLists = new Array(\n" +
" document.getElementById('" + ElementID.MODULE_LIST_FLAT + "'),\n" +
" document.getElementById('" + ElementID.MODULE_LIST_GROUPED + "'),\n" +
" document.getElementById('" + ElementID.MODULE_LIST_HIERARCHICAL + "')\n" +
" );\n" +
" var subToolbars = new Array(\n" +
" document.getElementById('" + ElementID.SUB_TOOLBAR_MODULE_LIST_FLAT + "'),\n" +
" document.getElementById('" + ElementID.SUB_TOOLBAR_MODULE_LIST_GROUPED + "'),\n" +
" document.getElementById('" + ElementID.SUB_TOOLBAR_MODULE_LIST_HIERARCHICAL + "')\n" +
" );\n" +
" var displayModeButtons = new Array(\n" +
" document.getElementById('" + ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_FLAT + "'),\n" +
" document.getElementById('" + ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_GROUPED + "'),\n" +
" document.getElementById('" + ElementID.DISPLAY_MODE_BUTTON_MODULE_LIST_HIERARCHICAL + "')\n" +
" );\n" +
" for (var i in moduleLists) {\n" +
" var moduleList = moduleLists[i];\n" +
" var displayModeButton = displayModeButtons[i];\n" +
" var subToolbar = subToolbars[i];\n" +
" if (i == mode) {\n" +
" moduleList.style.display = 'block';\n" +
" displayModeButton.className = '" + StyleClassConstants.BUTTON_SELECTED + "';\n" +
" subToolbar.style.display = 'block';\n" +
" } else {\n" +
" moduleList.style.display = 'none';\n" +
" displayModeButton.className = '" + StyleClassConstants.BUTTON_NOT_SELECTED + "';\n" +
" subToolbar.style.display = 'none';\n" +
" }\n" +
" }\n" +
" // set the cookie\n" +
" var cookie = getCookieName() + '=' + mode + '; expires=' + (new Date(new Date().getTime() + 365*24*3600*1000).toUTCString()) + '; path=/';\n" +
" document.cookie = cookie;\n" +
"}\n" +
"function getCookieName() {\n" +
" return 'org.openquark.cal.caldoc." + cookiePrefix + ".displayMode';\n" +
"}\n" +
"function setInitialModuleListDisplayMode() {\n" +
" var cookies = document.cookie.split(/;\\s*/);\n" +
" var displayMode = " + initialDisplayMode + ";\n" +
" for (var i in cookies) {\n" +
" var cookie = cookies[i];\n" +
" if (cookie.indexOf(getCookieName() + '=') == 0) {\n" +
" displayMode = cookie.substr(getCookieName().length + 1);\n" +
" }\n" +
" }\n" +
" setModuleListDisplayMode(displayMode);\n" +
"}\n" +
"function setBlockDisplayMode(elementID, mode) {\n" +
" var isShown = false;\n" +
" var element = document.getElementById(elementID);\n" +
" if (element && element.style) {\n" +
" element.style.display = mode;\n" +
" isShown = (mode == 'block');\n" +
" }\n" +
" updateToggle(elementID, isShown);\n" +
"}\n" +
"function toggleBlockDisplayMode(elementID) {\n" +
" var isShown = false;\n" +
" var element = document.getElementById(elementID);\n" +
" if (element && element.style) {\n" +
" if (element.style.display != 'none') {\n" + // we assume that by default the element is displayed, so the first toggle operation should hide it
" element.style.display = 'none';\n" +
" } else {\n" +
" element.style.display = 'block';\n" +
" isShown = true;\n" +
" }\n" +
" }\n" +
" updateToggle(elementID, isShown);\n" +
"}\n" +
"function updateToggle(elementID, isShown) {\n" +
" var toggle = document.getElementById('tog:' + elementID);\n" +
" if (toggle) {\n" +
" toggle.innerHTML = isShown ? '" + LocalizableUserVisibleString.COLLAPSE_BUTTON_LABEL.toResourceString() + "' : '" + LocalizableUserVisibleString.EXPAND_BUTTON_LABEL.toResourceString() + "';\n" +
" }\n" +
"}\n");
}
/**
* Generates the javascript for the "expand all" and "collapse all" functionality.
* @param groupedNodeElementIDs a list of the element IDs for the nodes in the "grouped" display.
* @param hierarchicalNodeElementIDs a list of the element IDs for the nodes in the "hierarchical" display.
*/
private void generateExpandCollapseAllJavascript(final List<String> groupedNodeElementIDs, final List<String> hierarchicalNodeElementIDs) {
currentPage
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"var groupedNodeElementIDs = " + getNewStringArrayJavascript(groupedNodeElementIDs) + ";\n" +
"var hierarchicalNodeElementIDs = " + getNewStringArrayJavascript(hierarchicalNodeElementIDs) + ";\n" +
"function expandAllGroupedNodes() {\n" +
" for (var i in groupedNodeElementIDs) {\n" +
" var groupedNodeElementID = groupedNodeElementIDs[i];\n" +
" setBlockDisplayMode(groupedNodeElementID, 'block');\n" +
" }\n" +
"}\n" +
"function collapseAllGroupedNodes() {\n" +
" for (var i in groupedNodeElementIDs) {\n" +
" var groupedNodeElementID = groupedNodeElementIDs[i];\n" +
" setBlockDisplayMode(groupedNodeElementID, 'none');\n" +
" }\n" +
"}\n" +
"function expandAllHierarchicalNodes() {\n" +
" for (var i in hierarchicalNodeElementIDs) {\n" +
" var hierarchicalNodeElementID = hierarchicalNodeElementIDs[i];\n" +
" setBlockDisplayMode(hierarchicalNodeElementID, 'block');\n" +
" }\n" +
"}\n" +
"function collapseAllHierarchicalNodes() {\n" +
" for (var i in hierarchicalNodeElementIDs) {\n" +
" var hierarchicalNodeElementID = hierarchicalNodeElementIDs[i];\n" +
" setBlockDisplayMode(hierarchicalNodeElementID, 'none');\n" +
" }\n" +
"}\n");
}
/**
* Returns a javascript expression for creating a new string array.
* @param elements the elements to be put into the array.
* @return the javascript expression.
*/
private String getNewStringArrayJavascript(final List<String> elements) {
StringBuilder buffer = new StringBuilder("new Array(\n");
for (int i = 0, n = elements.size(); i < n; i++) {
if (i > 0) {
buffer.append(",\n");
}
buffer.append(" '").append(elements.get(i)).append("'");
}
buffer.append(")");
return buffer.toString();
}
/**
* Generates a hierarchical module list.
* @param node the current node to process.
* @param level the current level in the tree.
* @param moduleNameOrNull the module name corresponding to the node, or null if this is the root of the tree.
* @return a list of the element IDs for the DIVs generated (except the root).
*/
private List<String> generateHierarchicalModuleList(final ModuleHierarchyInfo node, final int level, final ModuleName moduleNameOrNull) {
// just return if there are no children to generate
if (node.getChildren().isEmpty()) {
return Collections.emptyList();
}
final String moduleTreeNodeElementID = getModuleTreeNodeElementID("mlH", moduleNameOrNull);
final List<String> elementIDs = new ArrayList<String>();
if (moduleNameOrNull != null) {
// the current node is not the root, so add the elementID
elementIDs.add(moduleTreeNodeElementID);
}
currentPage.openTag(HTML.Tag.DIV, idAndClassAttributes(moduleTreeNodeElementID, StyleClassConstants.TREE_DIV));
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final boolean childIsActualModule = key.snd().booleanValue();
final ModuleHierarchyInfo child = entry.getValue();
final String childDisplayName = childName.getNthComponent(level);
final String fullyQualifiedNameForChildModule = getFullyQualifiedNameForModule(childName);
final String childDivElementID = getModuleTreeNodeElementID("mlH", childName);
currentPage.openTag(HTML.Tag.DIV);
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
if (childIsActualModule) {
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, childName, labelMaker.getModuleLabel(childName), childDisplayName, fullyQualifiedNameForChildModule);
} else {
currentPage.addText(childDisplayName);
}
currentPage.closeTag(HTML.Tag.DIV);
final List<String> elementIDsFromChild = generateHierarchicalModuleList(child, level+1, childName);
elementIDs.addAll(elementIDsFromChild);
}
currentPage.closeTag(HTML.Tag.DIV);
return elementIDs;
}
/**
* Generates a grouped module list.
* @param node the current node to process.
* @param isChildLevel whether this is the child level.
* @param moduleNameOrNull the module name corresponding to the node, or null if this is the root of the tree.
* @return a list of the element IDs for the DIVs generated (except the root).
*/
private List<String> generateGroupedModuleList(final ModuleHierarchyInfo node, final boolean isChildLevel, final ModuleName moduleNameOrNull) {
// just return if there are no children to generate
if (node.getChildren().isEmpty()) {
return Collections.emptyList();
}
final String moduleTreeNodeElementID = getModuleTreeNodeElementID("mlG", moduleNameOrNull);
final List<String> elementIDs = new ArrayList<String>();
if (moduleNameOrNull != null) {
// the current node is not the root, so add the elementID
elementIDs.add(moduleTreeNodeElementID);
}
currentPage.openTag(HTML.Tag.DIV, idAndClassAttributes(moduleTreeNodeElementID, StyleClassConstants.TREE_DIV));
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final boolean childIsActualModule = key.snd().booleanValue();
final ModuleHierarchyInfo child = entry.getValue();
final String childDisplayName = isChildLevel ? childName.getLastComponent() : childName.toSourceText();
final String fullyQualifiedNameForChildModule = getFullyQualifiedNameForModule(childName);
final String childDivElementID = getModuleTreeNodeElementID("mlG", childName);
currentPage.openTag(HTML.Tag.DIV);
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
if (childIsActualModule) {
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, childName, labelMaker.getModuleLabel(childName), childDisplayName, fullyQualifiedNameForChildModule);
} else {
currentPage.addText(childDisplayName);
}
currentPage.closeTag(HTML.Tag.DIV);
if (!isChildLevel) {
final List<String> elementIDsFromChild = generateGroupedModuleList(child, true, childName);
elementIDs.addAll(elementIDsFromChild);
}
}
currentPage.closeTag(HTML.Tag.DIV);
return elementIDs;
}
/**
* Generate a grouped view of a list of modules that are related to the current module
* (e.g. the imported modules, the friend modules, the directly and the indirectly
* dependent modules).
* @param node the root node of a grouped (two-level) tree.
*/
private void generateGroupedListOfRelatedModules(final ModuleHierarchyInfo node) {
SortedSet<ModuleName> rootLevelModules = new TreeSet<ModuleName>();
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final ModuleHierarchyInfo child = entry.getValue();
if (child.getChildren().isEmpty()) {
rootLevelModules.add(childName);
}
}
// first list out the modules with "namespaces" (i.e. their names have >1 components)
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final ModuleHierarchyInfo child = entry.getValue();
if (rootLevelModules.contains(childName)) {
continue;
}
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.RELATED_MODULES_LIST))
.addText(childName.toSourceText())
.addText(LocalizableUserVisibleString.COLON.toResourceString())
.addText(" ");
int counter2 = 0;
for (final Pair<ModuleName, Boolean> key2 : child.getChildren().keySet()) {
final ModuleName childName2 = key2.fst();
if (counter2 > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
generateModuleReference(currentPage, null, childName2, childName2.getLastComponent());
counter2++;
}
currentPage.closeTag(HTML.Tag.DIV);
}
// now list out the modules under the "root namespace" (i.e. their names have just 1 component)
int counter = 0;
for (final ModuleName moduleName : rootLevelModules) {
if (counter > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
generateModuleReference(currentPage, null, moduleName, moduleName.toSourceText());
counter++;
}
}
/**
* Generates an attribute header and a grouped view of a list of modules that are related to the current module
* (e.g. the imported modules, the friend modules, the directly and the indirectly
* dependent modules).
* @param attributeHeader the attribute header.
* @param moduleNames a set of ModuleNames.
*/
private void generateRelatedModulesList(final String attributeHeader, final Set<ModuleName> moduleNames) {
/// Generate the modules list only if there are some modules to list
//
if (moduleNames.size() > 0) {
currentPage
.openTag(HTML.Tag.DL)
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), attributeHeader)
.openTag(HTML.Tag.DD);
generateGroupedListOfRelatedModules(getFlatModuleGrouping(moduleNames));
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL);
}
}
/**
* Returns the element ID for a node in a module tree.
* @param idPrefix the prefix to use for the ID.
* @param moduleNameOrNull the module name corresponding to the node, or null if this is the root of the tree.
* @return the element ID.
*/
private String getModuleTreeNodeElementID(final String idPrefix, final ModuleName moduleNameOrNull) {
if (moduleNameOrNull == null) {
return idPrefix + ":root";
} else {
return idPrefix + ":" + moduleNameOrNull.toSourceText();
}
}
/**
* Generates a toggle (or a placeholder) for a node in a module tree.
* @param childDivElementID the element ID for the children block of the node whose display is to be controlled by the toggle.
* @param isPlaceholderOnly whether this is to be an inactive placeholder for a toggle.
*/
private void generateModuleListTreeNodeToggle(final String childDivElementID, boolean isPlaceholderOnly) {
final AttributeList attributes;
final String toggleText;
if (isPlaceholderOnly) {
attributes = classAttribute(StyleClassConstants.TREE_NODE_TOGGLE_PLACEHOLDER);
toggleText = " ";
} else {
attributes = idAndClassAttributes("tog:" + childDivElementID, StyleClassConstants.TREE_NODE_TOGGLE).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "toggleBlockDisplayMode(\"" + childDivElementID + "\");"));
toggleText = LocalizableUserVisibleString.COLLAPSE_BUTTON_LABEL.toResourceString();
}
currentPage
.addTaggedText(HTML.Tag.SPAN, attributes, toggleText)
.addText(" ");
}
/**
* Generates a flat module list.
*/
private void generateFlatModuleList() {
final SortedMap<String, ModuleName> displayNameToModuleNameMap = getAbbreviatedModuleNameToModuleNameMap();
for (final Map.Entry<String, ModuleName> entry : displayNameToModuleNameMap.entrySet()) {
final String displayName = entry.getKey();
final ModuleName moduleName = entry.getValue();
final String fullyQualifiedNameForModule = moduleName.toSourceText();
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, moduleName, labelMaker.getModuleLabel(moduleName), displayName, fullyQualifiedNameForModule);
currentPage.emptyTag(HTML.Tag.BR).newline();
}
}
/**
* Constructs a map from abbreviated names for modules to fully-qualified ModuleNames.
* @return the map.
*/
private SortedMap<String, ModuleName> getAbbreviatedModuleNameToModuleNameMap() {
final SortedMap<String, ModuleName> displayNameToModuleNameMap = new TreeMap<String, ModuleName>();
for (final ModuleName moduleName : moduleIndices.keySet()) {
final String lastComponent = moduleName.getLastComponent();
final ModuleName minimallyQualifiedModuleName = getModuleNameResolverForDocumentedModules().getMinimallyQualifiedModuleName(moduleName);
final String displayName;
if (minimallyQualifiedModuleName.getNComponents() == 1) {
displayName = lastComponent;
} else {
final int nMinusOne = minimallyQualifiedModuleName.getNComponents() - 1;
final StringBuilder sb = new StringBuilder(lastComponent).append(" (");
for (int i = 0; i < nMinusOne; i++) {
if (i > 0) {
sb.append(CALFragments.DOT);
}
sb.append(minimallyQualifiedModuleName.getNthComponent(i));
}
sb.append(")");
displayName = sb.toString();
}
displayNameToModuleNameMap.put(displayName, moduleName);
}
return displayNameToModuleNameMap;
}
/**
* Constructs the contents for the overview page HTML file.
* @return the contents of the file.
*/
private String getOverviewPageHTML() {
startNewCurrentPage();
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = ""; // the welcome page is in the base directory
generateHeadSection(makePageTitle(LocalizableUserVisibleString.OVERVIEW.toResourceString()), relativePathToBaseDirectory, null, null);
/// Generate the Javascript for changing the nav frame.
//
currentPage
.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "initPage()")))
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"function initPage() {\n" +
" clearNav();\n" +
" setInitialModuleListDisplayMode();\n" +
"}\n" +
"function clearNav() {\n" +
" if (parent.frames != undefined && parent.frames[1] != undefined && parent.frames[1].location != undefined) {\n" +
" parent.frames[1].location.replace('about:blank');\n" +
" }\n" +
"}");
generateModuleListDisplayModeJavascript(1, "overview");
generateGenericNavBar(false, relativePathToBaseDirectory);
/// Wrap the main content with a div tag
//
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
/// Generate the page heading
//
currentPage
.addTaggedText(HTML.Tag.H1, config.docTitle)
.addTaggedText(HTML.Tag.H2, LocalizableUserVisibleString.OVERVIEW.toResourceString());
////
/// For each module documented, generate a link to it and its short description.
/// The names of the documented modules form the keys in the moduleIndices map.
//
/// Close the main content div tag
//
currentPage.closeTag(HTML.Tag.DIV);
generateDisplayModeToolbars();
/// Wrap the main content with a div tag
//
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_FLAT));
generateFlatOverview();
currentPage.closeTag(HTML.Tag.DIV);
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_GROUPED));
final List<String> groupedNodeElementIDs = generateGroupedOverview(getFlatModuleGrouping(moduleIndices.keySet()), false, null);
currentPage.closeTag(HTML.Tag.DIV);
currentPage.openTag(HTML.Tag.DIV, idAttribute(ElementID.MODULE_LIST_HIERARCHICAL));
final List<String> hierarchicalNodeElementIDs = generateHierarchicalOverview(getModuleHierarchy(moduleIndices.keySet()), 0, null);
currentPage.closeTag(HTML.Tag.DIV);
/// Close the main content div tag
//
currentPage.closeTag(HTML.Tag.DIV);
generateGenericNavBar(true, "");
generatePageBottom();
generateExpandCollapseAllJavascript(groupedNodeElementIDs, hierarchicalNodeElementIDs);
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
return getHTMLFileContentsWithDocTypeForMainFramePage(currentPage);
}
/**
* Generates the short description for a module.
* @param moduleName the module to be described.
*/
private void generateShortDescriptionForModule(final ModuleName moduleName) {
ModuleTypeInfo moduleTypeInfo = programModelManager.getModuleTypeInfo(moduleName);
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getModuleFeatureName(moduleName), getLocale());
CALDocComment docComment = moduleTypeInfo.getCALDocComment();
generateShortDescription(metadata, docComment, new ReferenceGenerator(MODULES_SUBDIRECTORY));
}
/**
* Generates a hierarchical view for the overview page.
* @param node the current node to process.
* @param level the current level in the tree.
* @param moduleNameOrNull the module name corresponding to the node, or null if this is the root of the tree.
* @return a list of the element IDs for the DIVs generated (except the root).
*/
private List<String> generateHierarchicalOverview(final ModuleHierarchyInfo node, final int level, final ModuleName moduleNameOrNull) {
// just return if there are no children to generate
if (node.getChildren().isEmpty()) {
return Collections.emptyList();
}
final String moduleTreeNodeElementID = getModuleTreeNodeElementID("ovwH", moduleNameOrNull);
final List<String> elementIDs = new ArrayList<String>();
if (moduleNameOrNull != null) {
// the current node is not the root, so add the elementID
elementIDs.add(moduleTreeNodeElementID);
}
currentPage.openTag(HTML.Tag.DIV, idAndClassAttributes(moduleTreeNodeElementID, StyleClassConstants.TREE_DIV_OVERVIEW_PAGE));
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final boolean childIsActualModule = key.snd().booleanValue();
final ModuleHierarchyInfo child = entry.getValue();
final String childDisplayName = childName.getNthComponent(level);
final String fullyQualifiedNameForChildModule = getFullyQualifiedNameForModule(childName);
final String childDivElementID = getModuleTreeNodeElementID("ovwH", childName);
currentPage.openTag(HTML.Tag.DIV);
if (childIsActualModule) {
currentPage.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.DL_OVERVIEW_PAGE)).openTag(HTML.Tag.DT);
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, childName, labelMaker.getModuleLabel(childName), childDisplayName, fullyQualifiedNameForChildModule);
currentPage.closeTag(HTML.Tag.DT).openTag(HTML.Tag.DD);
generateShortDescriptionForModule(childName);
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
} else {
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
currentPage.addText(childDisplayName);
}
currentPage.closeTag(HTML.Tag.DIV);
final List<String> elementIDsFromChild = generateHierarchicalOverview(child, level+1, childName);
elementIDs.addAll(elementIDsFromChild);
}
currentPage.closeTag(HTML.Tag.DIV);
return elementIDs;
}
/**
* Generates a grouped view for the overview page.
* @param node the current node to process.
* @param isChildLevel whether this is the child level.
* @param moduleNameOrNull the module name corresponding to the node, or null if this is the root of the tree.
* @return a list of the element IDs for the DIVs generated (except the root).
*/
private List<String> generateGroupedOverview(final ModuleHierarchyInfo node, final boolean isChildLevel, final ModuleName moduleNameOrNull) {
// just return if there are no children to generate
if (node.getChildren().isEmpty()) {
return Collections.emptyList();
}
final String moduleTreeNodeElementID = getModuleTreeNodeElementID("ovwG", moduleNameOrNull);
final List<String> elementIDs = new ArrayList<String>();
if (moduleNameOrNull != null) {
// the current node is not the root, so add the elementID
elementIDs.add(moduleTreeNodeElementID);
}
currentPage.openTag(HTML.Tag.DIV, idAndClassAttributes(moduleTreeNodeElementID, StyleClassConstants.TREE_DIV_OVERVIEW_PAGE));
for (final Map.Entry<Pair<ModuleName, Boolean>, ModuleHierarchyInfo> entry : node.getChildren().entrySet()) {
final Pair<ModuleName, Boolean> key = entry.getKey();
final ModuleName childName = key.fst();
final boolean childIsActualModule = key.snd().booleanValue();
final ModuleHierarchyInfo child = entry.getValue();
final String childDisplayName = isChildLevel ? childName.getLastComponent() : childName.toSourceText();
final String fullyQualifiedNameForChildModule = getFullyQualifiedNameForModule(childName);
final String childDivElementID = getModuleTreeNodeElementID("ovwG", childName);
currentPage.openTag(HTML.Tag.DIV);
if (childIsActualModule) {
currentPage.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.DL_OVERVIEW_PAGE)).openTag(HTML.Tag.DT);
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, childName, labelMaker.getModuleLabel(childName), childDisplayName, fullyQualifiedNameForChildModule);
currentPage.closeTag(HTML.Tag.DT).openTag(HTML.Tag.DD);
generateShortDescriptionForModule(childName);
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
} else {
generateModuleListTreeNodeToggle(childDivElementID, child.getChildren().isEmpty());
currentPage.addText(childDisplayName);
}
currentPage.closeTag(HTML.Tag.DIV);
if (!isChildLevel) {
final List<String> elementIDsFromChild = generateGroupedOverview(child, true, childName);
elementIDs.addAll(elementIDsFromChild);
}
}
currentPage.closeTag(HTML.Tag.DIV);
return elementIDs;
}
/**
* Generates a flat view for the overview page.
*/
private void generateFlatOverview() {
final SortedMap<String, ModuleName> displayNameToModuleNameMap = getAbbreviatedModuleNameToModuleNameMap();
for (final Map.Entry<String, ModuleName> entry : displayNameToModuleNameMap.entrySet()) {
final String displayName = entry.getKey();
final ModuleName moduleName = entry.getValue();
final String fullyQualifiedNameForModule = moduleName.toSourceText();
currentPage.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.DL_OVERVIEW_PAGE)).openTag(HTML.Tag.DT);
generateNonLocalReference(currentPage, MODULES_SUBDIRECTORY, moduleName, labelMaker.getModuleLabel(moduleName), displayName, fullyQualifiedNameForModule);
currentPage.closeTag(HTML.Tag.DT).openTag(HTML.Tag.DD);
generateShortDescriptionForModule(moduleName);
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
}
/**
* Constructs the HTML contents of the master scoped entity search page.
* @return the contents of the file.
*/
private String getMasterScopedEntitySearchPageHTML() {
startNewCurrentPage();
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = ""; // the master index page is in the base directory
generateHeadSection(makePageTitle(LocalizableUserVisibleString.SEARCH.toResourceString()), relativePathToBaseDirectory, MAIN_FRAME_NAME, null);
////
/// Build up the javascript that initializes the index data structures in the search page
//
StringBuilder jsMasterIndexSetup = new StringBuilder("var modules = new Array(\n");
List<String> prefixes = new ArrayList<String>();
boolean isFirstTime = true;
for (final ModuleName moduleName : moduleIndices.keySet()) {
if (!isFirstTime) {
jsMasterIndexSetup.append(",\n");
}
isFirstTime = false;
// For each module we generate 4 javascript arrays containing the index entries
// for the 4 per-module indices. There arrays are assigned as fields to a javascript
// object representing the module.
List<IndexEntry> typeIndex = getPerModuleTypeIndex(moduleName);
String jsTypeIndexSetup = getMasterScopedEntitySearchPageJavascriptForPerModuleIndex(typeIndex, prefixes);
List<IndexEntry> typeClassIndex = getPerModuleTypeClassIndex(moduleName);
String jsTypeClassIndexSetup = getMasterScopedEntitySearchPageJavascriptForPerModuleIndex(typeClassIndex, prefixes);
// make a copy of the functional agent index, so we can sort it in the order we desire, which is case-insensitive lexicographical order
List<IndexEntry> functionalAgentIndex = new ArrayList<IndexEntry>(getPerModuleFunctionalAgentIndex(moduleName));
// sort the list of index entries
Collections.sort(functionalAgentIndex, new IndexEntryComparator());
String jsFunctionalAgentIndexSetup = getMasterScopedEntitySearchPageJavascriptForPerModuleIndex(functionalAgentIndex, prefixes);
jsMasterIndexSetup
.append("\nmoduleEntry('")
.append(moduleName)
.append("',\n")
.append(jsTypeIndexSetup)
.append(",\n")
.append(jsTypeClassIndexSetup)
.append(",\n")
.append(jsFunctionalAgentIndexSetup)
.append(")");
}
jsMasterIndexSetup.append(");\n\n");
String jsSortMasterIndexCall =
"modules.sort(\n" +
" function (a, b) {\n" +
" if (a.moduleName < b.moduleName) {\n" +
" return -1;\n" +
" } else if (a.moduleName > b.moduleName) {\n" +
" return 1;\n" +
" } else {\n" +
" return 0;\n" +
" }\n" +
" });\n";
jsMasterIndexSetup.append(jsSortMasterIndexCall);
////
/// Now that we have looped through the index entries, we can produce the list of prefixes (which actually needs to
/// come before the index data structures in the final javascript, because it is referenced by the pf() function).
//
StringBuilder jsPrefixesSetup = new StringBuilder();
jsPrefixesSetup.append("var prefixes = new Array(");
for (int i = 0, n = prefixes.size(); i < n; i++) {
if (i > 0) {
jsPrefixesSetup.append(",");
}
jsPrefixesSetup.append("'").append(prefixes.get(i)).append("'");
}
jsPrefixesSetup.append(");\n\n");
////
/// Build up the javascript helper functions that implement the search functionality
//
String jsMakeModuleEntryFunction = "\n" +
"function moduleEntry(moduleName, typeIndex, typeClassIndex, functionalAgentIndex) {\n" +
" var entry = new Object();\n" +
" entry.moduleName = moduleName;\n" +
" entry.indices = new Object();" +
" entry.indices.typeIndex = typeIndex;\n" +
" entry.indices.typeClassIndex = typeClassIndex;\n" +
" entry.indices.functionalAgentIndex = functionalAgentIndex;\n" +
" return entry;\n" +
"}\n";
String jsMakePairFunction = "\n" +
"function pair(name, label) {\n" +
" var item = new Object();\n" +
" item.name = name;\n" +
" item.label = label;\n" +
" return item;\n" +
"}\n" +
"\n" +
"function item(scope, name, label) {\n" +
" var item = new Object();\n" +
" item.scope = scope;\n" +
" item.name = name;\n" +
" item.label = label;\n" +
" return item;\n" +
"}\n";
String jsMakePfFunction = "\n" +
"function pf(scope, prefixIndex, name) {\n" +
" return item(scope, name, prefixes[prefixIndex] + name);\n" +
"}\n";
String jsFindKeyFunction = "\n" +
"function findKey(key, caseSensitive, useRegexp, includeModuleIndex, indices) {\n" +
" var scopeClass = new Array('" + StyleClassConstants.PRIVATE_SCOPE.toHTML() + "', '" + StyleClassConstants.PROTECTED_SCOPE.toHTML() + "', '" + StyleClassConstants.PUBLIC_SCOPE.toHTML() + "');\n" +
" var origKey = key;\n" +
" key = key.replace(/\\s+$/, '');\n" +
" if (key.length == 0) { return ''; }\n" +
" if (!useRegexp) { key = key.replace(/([^a-zA-Z0-9-_])/g, '\\\\$1').replace(/\\\\\\*/g, '.*').replace(/\\\\\\?/g, '.'); }\n" +
" var re = new RegExp('(' + key + ')', caseSensitive ? '' : 'i');\n" +
" var finalResults = '';\n" +
" var numResults = 0;\n" +
" var privateScope = 0;\n" +
" var protectedScope = 1;\n" +
" var publicScope = 2;\n" +
" var numResultsPerScope = new Array(0, 0, 0);\n" +
" if (includeModuleIndex) {\n" +
" var moduleResults = '';\n" +
" for (var i in modules) {\n" +
" var moduleName = modules[i].moduleName;\n" +
" if (moduleName.match(re)) {\n" +
" numResults++;\n" +
" numResultsPerScope[publicScope]++;\n" +
" var highlightedEntry = moduleName.replace(re, '<b>$1<\\/b>');\n" +
" moduleResults += \" <a href='" + MODULES_SUBDIRECTORY + "/\" + moduleName + \".html'>\" + highlightedEntry + \"<\\/a><br>\\n\";\n" +
" }\n" +
" }\n" +
" if (moduleResults.length > 0) {\n" +
" finalResults += '<div class=\"" + StyleClassConstants.INDEX_NAV_CURRENT_LINK.toHTML() + "\">" + LocalizableUserVisibleString.MODULES.toResourceString() + "<\\/div>\\n<div class=\\'" + StyleClassConstants.MAIN_CONTENT.toHTML() + "\\'>' + moduleResults + '<\\/div>';\n" +
" }\n" +
" }\n" +
" for (var k in indices) {\n" +
" var indexInfo = indices[k];\n" +
" var indexName = indexInfo.name;\n" +
" var indexDisplayName = indexInfo.label;\n" +
" var indexResults = '';\n" +
" var indexMaxScope = privateScope;\n" +
" for (var j in modules) {\n" +
" var moduleName = modules[j].moduleName;\n" +
" var results = '';\n" +
" var module = modules[j].indices;\n" +
" var index = module[indexName];\n" +
" var moduleHasMatches = false;\n" +
" var moduleMaxScope = privateScope;\n" +
" for (var i in index) {\n" +
" var item = index[i];\n" +
" var scope = item.scope;\n" +
" var entry = item.name;\n" +
" var label = item.label;\n" +
" if (entry.match(re)) {\n" +
" if (!moduleHasMatches) {\n" +
" results += moduleName.bold() + '<br>\\n';\n" +
" }\n" +
" moduleHasMatches = true;\n" +
" moduleMaxScope = Math.max(scope, moduleMaxScope);\n" +
" numResults++;\n" +
" numResultsPerScope[scope]++;\n" +
" var highlightedEntry = entry.replace(re, '<b>$1<\\/b>');\n" +
" results += \"<span class='\" + scopeClass[scope] + \"'> <a href='" + MODULES_SUBDIRECTORY + "/\" + moduleName + \".html#\" + label + \"'>\" + highlightedEntry +\"<\\/a><br><\\/span>\\n\";\n" +
" }\n" +
" }\n" +
" if (results.length > 0) {\n" +
" indexResults += \"<div class='\" + scopeClass[moduleMaxScope] + \"'>\" + results + \"<\\/div>\";\n" +
" }\n" +
" indexMaxScope = Math.max(moduleMaxScope, indexMaxScope);\n" +
" }\n" +
" if (indexResults.length > 0) {\n" +
" indexResults = '<div class=\"' + scopeClass[indexMaxScope] + '\"><div class=\"" + StyleClassConstants.INDEX_NAV_CURRENT_LINK.toHTML() + "\">' + indexDisplayName + '<\\/div>\\n<div class=\\'" + StyleClassConstants.MAIN_CONTENT.toHTML() + "\\'>' + indexResults + '<\\/div><\\/div>';\n" +
" }\n" +
" finalResults += indexResults;\n" +
" }\n" +
" if (numResults > 0) {\n" +
" finalResults = '<div class=\\'" + StyleClassConstants.MAIN_CONTENT.toHTML() + "\\'>' + '" + LocalizableUserVisibleString.SEARCH_RESULT_SUMMARY.toResourceString() + "'.replace('\\{0\\}', origKey.italics()).bold() +\n" +
" '<div class=\"' + scopeClass[publicScope] + '\"> ' + '" + LocalizableUserVisibleString.SEARCH_RESULT_SUMMARY_PUBLIC.toResourceString() + "'.replace('\\{0\\}', numResultsPerScope[publicScope]).bold() + '<\\/div>' +\n" +
" (numResultsPerScope[protectedScope] == 0 ? '' : '<div class=\"' + scopeClass[protectedScope] + '\"> ' + '" + LocalizableUserVisibleString.SEARCH_RESULT_SUMMARY_PROTECTED.toResourceString() + "'.replace('\\{0\\}', numResultsPerScope[protectedScope]).bold() + '<\\/div>') +\n" +
" (numResultsPerScope[privateScope] == 0 ? '' : '<div class=\"' + scopeClass[privateScope] + '\"> ' + '" + LocalizableUserVisibleString.SEARCH_RESULT_SUMMARY_PRIVATE.toResourceString() + "'.replace('\\{0\\}', numResultsPerScope[privateScope]).bold() + '<\\/div>') +\n" +
" '<\\/div>\\n' + finalResults;\n" +
" } else {\n" +
" finalResults = '<p class=\\'" + StyleClassConstants.MAIN_CONTENT.toHTML() + "\\'>' + '" + LocalizableUserVisibleString.NO_MATCHES.toResourceString() + "'.italics(); + '<\\/p>'\n" +
" }\n" +
" return finalResults;\n" +
"}\n";
String jsPerformSearchFunction = "\n" +
"function performSearch() {\n" +
" try {\n" +
" var key = document.getElementById('" + ElementID.KEY + "').value;\n" +
" var caseSensitive = false;\n" +
" var useRegexp = false;\n" +
" var includeModuleIndex = true;\n" +
" var indices = new Array(\n" +
" pair('typeIndex', '" + LocalizableUserVisibleString.TYPES.toResourceString() + "'),\n" +
" pair('functionalAgentIndex', '" + LocalizableUserVisibleString.FUNCTIONS_CLASS_METHODS_AND_DATA_CONSTRUCTORS.toResourceString() + "'),\n" +
" pair('typeClassIndex', '" + LocalizableUserVisibleString.TYPE_CLASSES.toResourceString() + "')\n" +
" );\n" +
" var results = findKey(key, caseSensitive, useRegexp, includeModuleIndex, indices);\n" +
" if (results.length > 0) {\n" +
" document.getElementById('" + ElementID.RESULTS + "').innerHTML = results;\n" +
" }\n" +
" } catch (e) {\n" +
" if (e.message != undefined) {\n" +
" alert(e.message);\n" +
" } else if (e.description != undefined) {\n" +
" alert(e.description);\n" +
" } else {\n" +
" alert(e);\n" +
" }\n" +
" }\n" +
"}\n";
String jsExpandFrameFunction = "\n" +
"function expandFrame() {\n" +
" if (parent.frames != undefined && parent.frames[3] != undefined) {\n" +
" parent.document.getElementById('" + ElementID.OUTER_FRAMESET + "').cols = '20%, 80%, 0%';\n" +
" parent.document.getElementById('" + ElementID.OUTER_FRAMESET + "').cols = '20%, 60%, 20%';\n" +
" }\n" +
"}\n";
String jsHideFrameFunction = "\n" +
"function hideFrame() {\n" +
" if (parent.frames != undefined && parent.frames[3] != undefined) {\n" +
" parent.document.getElementById('" + ElementID.OUTER_FRAMESET + "').cols = '20%, 80%, 0%';\n" +
" }\n" +
"}\n";
String javascript = "\n" +
getUpdateScopeDisplaySettingsJavascript() +
jsPrefixesSetup.toString() +
jsMasterIndexSetup.toString() +
jsMakeModuleEntryFunction +
jsMakePairFunction +
jsMakePfFunction +
jsFindKeyFunction +
jsPerformSearchFunction +
jsExpandFrameFunction +
jsHideFrameFunction;
////
/// With the javascript built, now build up the HTML.
//
currentPage.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "expandFrame()")));
currentPage.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"), javascript);
// the title and the 'hide' button
currentPage
.openTag(HTML.Tag.TABLE, classAttribute(StyleClassConstants.SEARCH_BOX_TITLE).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.WIDTH, StyleValueConstants.ONE_HUNDRED_PERCENT)))
.openTag(HTML.Tag.TR)
.addTaggedText(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.WIDTH, StyleValueConstants.ONE_HUNDRED_PERCENT), LocalizableUserVisibleString.SEARCH.toResourceString())
.openTag(HTML.Tag.TD)
.emptyTag(HTML.Tag.INPUT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "button", HTML.Attribute.VALUE, LocalizableUserVisibleString.HIDE.toResourceString()).concat(HTMLBuilder.AttributeList.make(HTML4.ONCLICK_ATTRIBUTE, "hideFrame()")))
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR)
.closeTag(HTML.Tag.TABLE);
// the search box
currentPage
.openTag(HTML.Tag.FORM, HTMLBuilder.AttributeList.make(HTML.Attribute.ACTION, "javascript:performSearch()", HTML.Attribute.TARGET, "_self"))
.openTag(HTML.Tag.TABLE, classAttribute(StyleClassConstants.SEARCH_BOX).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.WIDTH, StyleValueConstants.ONE_HUNDRED_PERCENT, HTML.Attribute.CELLSPACING, "0", HTML.Attribute.CELLPADDING, "0")))
.openTag(HTML4.TBODY_TAG)
.openTag(HTML.Tag.TR)
.addTaggedText(HTML.Tag.TD, LocalizableUserVisibleString.ENTER_SEARCH_TERM_COLON.toResourceString())
.closeTag(HTML.Tag.TR)
.openTag(HTML.Tag.TR)
.openTag(HTML.Tag.TD)
.emptyTag(HTML.Tag.INPUT, idAndClassAttributes(ElementID.KEY, StyleClassConstants.SEARCH_FIELD).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.SIZE, "8192")))
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR)
.openTag(HTML.Tag.TR)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.ALIGN, StyleValueConstants.RIGHT_ALIGN))
.emptyTag(HTML.Tag.INPUT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "submit", HTML.Attribute.VALUE, LocalizableUserVisibleString.SEARCH.toResourceString()))
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR)
.closeTag(HTML4.TBODY_TAG)
.closeTag(HTML.Tag.TABLE)
.closeTag(HTML.Tag.FORM);
// the results section
currentPage.addTaggedText(HTML.Tag.DIV, idAttribute(ElementID.RESULTS), "");
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
return DocTypeDecl.HTML_4_01_TRANSITIONAL + currentPage.toHTML();
}
/**
* Creates the javascript for initializing the an index array from a list of IndexEntry objects representing a per-module index.
* @param index the list of IndexEntry objects representing a per-module index.
* @param prefixes the list of label prefixes, to be appended when a new prefix is encountered.
* @return the required javascript for initializing the index array.
*/
private String getMasterScopedEntitySearchPageJavascriptForPerModuleIndex(List<IndexEntry> index, List<String> prefixes) {
StringBuilder jsIndexSetup = new StringBuilder("new Array(");
for (int i = 0, n = index.size(); i < n; i++) {
if (i > 0) {
jsIndexSetup.append(",");
}
IndexEntry entry = index.get(i);
String displayName = entry.getDisplayName();
String label = entry.getLabel();
int scopeNum;
Scope scope = entry.getScope();
if (scope.isPrivate()) {
scopeNum = 0;
} else if (scope.isProtected()) {
scopeNum = 1;
} else if (scope.isPublic()) {
scopeNum = 2;
} else {
throw new IllegalStateException("Invalid scope: " + scope);
}
if (label.endsWith(displayName)) {
// the label has the display name as its suffix, so extract the prefix and
// store it in the prefixes list if it's not already in there, and use the index into
// the list as a shorter representation of the prefix
String prefix = label.substring(0, label.length() - displayName.length());
int prefixIndex = prefixes.indexOf(prefix);
if (prefixIndex == -1) {
prefixes.add(prefix);
prefixIndex = prefixes.size() - 1;
}
jsIndexSetup.append("\n pf(").append(scopeNum).append(',').append(prefixIndex).append(",'").append(displayName).append("')");
} else {
jsIndexSetup.append("\n item(").append(scopeNum).append(",'").append(displayName).append("','").append(label).append("')");
}
}
jsIndexSetup.append(")");
return jsIndexSetup.toString();
}
/**
* Constructs the HTML contents of the type index for the current module.
* @param indexFileName the name of the index file.
* @return the contents of the file.
*/
private String getTypeIndexPageHTML(String indexFileName) {
return getIndexPageHTML(LocalizableUserVisibleString.TYPE_INDEX.toResourceString(), LocalizableUserVisibleString.TYPES.toResourceString(), getPerModuleTypeIndex(currentModuleName), indexFileName);
}
/**
* Constructs the HTML contents of the functional agent index for the current module.
* @param indexFileName the name of the index file.
* @return the contents of the file.
*/
private String getFunctionalAgentIndexPageHTML(String indexFileName) {
// make a copy of the index, so we can sort it in the order we desire, which is case-insensitive lexicographical order
List<IndexEntry> index = new ArrayList<IndexEntry>(getPerModuleFunctionalAgentIndex(currentModuleName));
// sort the list of index entries
Collections.sort(index, new IndexEntryComparator());
return getIndexPageHTML(LocalizableUserVisibleString.FUNCTIONAL_AGENT_INDEX.toResourceString(), LocalizableUserVisibleString.FUNCTIONS_CLASS_METHODS_AND_DATA_CONSTRUCTORS.toResourceString(), index, indexFileName);
}
/**
* Constructs the HTML contents of the type class index for the current module.
* @param indexFileName the name of the index file.
* @return the contents of the file.
*/
private String getTypeClassIndexPageHTML(String indexFileName) {
return getIndexPageHTML(LocalizableUserVisibleString.TYPE_CLASS_INDEX.toResourceString(), LocalizableUserVisibleString.TYPE_CLASSES.toResourceString(), getPerModuleTypeClassIndex(currentModuleName), indexFileName);
}
/**
* Constructs the HTML contents of the instance index for the current module.
* @param indexFileName the name of the index file.
* @return the contents of the file.
*/
private String getInstanceIndexPageHTML(String indexFileName) {
return getIndexPageHTML(LocalizableUserVisibleString.INSTANCE_INDEX.toResourceString(), LocalizableUserVisibleString.INSTANCES.toResourceString(), getPerModuleInstanceIndex(currentModuleName), indexFileName);
}
/**
* Constructs the HTML contents of one of the four per-module navigational indices for the current module.
* @param pageTitle the title of the page.
* @param heading the heading of the page.
* @param index the List of IndexEntry objects forming the index.
* @param indexFileName the name of the index file.
* @return the contents of the file.
*/
private String getIndexPageHTML(String pageTitle, String heading, List<IndexEntry> index, String indexFileName) {
startNewCurrentPage();
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = "../";
generateHeadSection(makePageTitle(pageTitle), relativePathToBaseDirectory, MAIN_FRAME_NAME, null);
////
/// Generate the heading and the intra-index links.
//
currentPage.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT));
generateUpdateScopeDisplaySettingsJavascript();
/// If the module name has more than one component, break it up into two pieces: the immediate prefix and the last component
//
final ModuleName immediatePrefix = currentModuleName.getImmediatePrefix();
if (immediatePrefix != null) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.SIDE_BAR_KHAKI_SUPERTITLE), immediatePrefix.toSourceText());
}
currentPage.addTaggedText(HTML.Tag.H2, classAttribute(StyleClassConstants.SIDE_BAR_KHAKI_TITLE), currentModuleName.getLastComponent());
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.INDEX_NAV));
generateIndexPageNavLink(getPerModuleTypeIndex(currentModuleName), getPerModuleTypeIndexFileName(currentModuleName), indexFileName, LocalizableUserVisibleString.TYPES.toResourceString());
generateIndexPageNavLink(getPerModuleFunctionalAgentIndex(currentModuleName), getPerModuleFunctionalAgentIndexFileName(currentModuleName), indexFileName, LocalizableUserVisibleString.FUNCTIONS_CLASS_METHODS_AND_DATA_CONSTRUCTORS.toResourceString());
generateIndexPageNavLink(getPerModuleTypeClassIndex(currentModuleName), getPerModuleTypeClassIndexFileName(currentModuleName), indexFileName, LocalizableUserVisibleString.TYPE_CLASSES.toResourceString());
generateIndexPageNavLink(getPerModuleInstanceIndex(currentModuleName), getPerModuleInstanceIndexFileName(currentModuleName), indexFileName, LocalizableUserVisibleString.INSTANCES.toResourceString());
currentPage
.closeTag(HTML.Tag.DIV)
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT))
.addTaggedText(HTML.Tag.H3, classAttribute(StyleClassConstants.NON_DISPLAYED_HEADER), heading);
////
/// Generate the index entries.
//
for (int i = 0, n = index.size(); i < n; i++) {
IndexEntry entry = index.get(i);
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(entry.getScope())));
if (config.shouldSeparateInstanceDoc && entry.getKind() == IndexEntry.Kind.INSTANCE) {
String filePath = relativePathToBaseDirectory + SEPARATE_INSTANCE_DOC_SUBDIRECTORY + "/" + getSeparateInstanceDocFileName(currentModuleName);
currentPage.addTaggedText(HTML.Tag.A, nonLocalHrefAttribute(filePath, entry.getLabel()), entry.getDisplayName());
} else {
generateNonLocalReference(currentPage, relativePathToBaseDirectory + MODULES_SUBDIRECTORY, currentModuleName, entry.getLabel(), entry.getDisplayName(), null);
}
currentPage.closeTag(HTML.Tag.DIV);
}
currentPage.closeTag(HTML.Tag.DIV).closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
return DocTypeDecl.HTML_4_01_TRANSITIONAL + currentPage.toHTML();
}
/////====================================================================================================
////
/// Generation of the navigation bar
//
/**
* Generates a navigational index for an intra-index link.
* @param linkedIndex the List of IndexEntry objects forming the index being linked to.
* @param linkedFileName the name of the index file being linked to.
* @param thisFileName the name of the index file being generated.
* @param displayName the display name for the link.
*/
private void generateIndexPageNavLink(List<IndexEntry> linkedIndex, String linkedFileName, String thisFileName, String displayName) {
if (linkedFileName.equals(thisFileName)) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.INDEX_NAV_CURRENT_LINK))
.addText(displayName)
.closeTag(HTML.Tag.DIV);
} else if (linkedIndex.size() > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.INDEX_NAV_LINK))
.addTaggedText(HTML.Tag.A, nonLocalHrefAttribute(linkedFileName, null).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TARGET, "_self")), displayName)
.closeTag(HTML.Tag.DIV);
}
}
/**
* Constructs the HTML attributes for the navigation bar at the top and bottom of each page.
* @return the list of attributes.
*/
private HTMLBuilder.AttributeList getNavBarAttributes() {
return classAttribute(StyleClassConstants.NAV_BAR);
}
/**
* Generates a generic navigation bar.
* @param isFooter true if this bar forms the footer; false if this bar forms the header.
* @param relativePathToBaseDirectory the relative path to the base directory for documentation generation.
*/
private void generateGenericNavBar(boolean isFooter, String relativePathToBaseDirectory) {
currentPage
.openTag(HTML.Tag.DIV, getNavBarAttributes());
if (isFooter) {
generateHorizontalNavBarHeaderFooterRow(isFooter);
generateHorizontalNavBarGlobalNavTableRow(relativePathToBaseDirectory);
} else {
generateHorizontalNavBarGlobalNavTableRow(relativePathToBaseDirectory);
generateHorizontalNavBarHeaderFooterRow(isFooter);
}
currentPage
.closeTag(HTML.Tag.DIV);
}
/**
* Generates a navigation bar for a module documentation page.
* @param isFooter true if this bar forms the footer; false if this bar forms the header.
*/
private void generateModulePageNavBar(boolean isFooter, int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances) {
String relativePathToBaseDirectory = "../";
generateModulePageNavBar(isFooter, relativePathToBaseDirectory, nTypeConstructors, nFunctions, nTypeClasses, nClassInstances);
}
/**
* Generates a navigation bar for a module documentation page.
* @param isFooter true if this bar forms the footer; false if this bar forms the header.
*/
private void generateModulePageNavBar(boolean isFooter, String relativePathToBaseDirectory, int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances) {
currentPage
.openTag(HTML.Tag.DIV, getNavBarAttributes());
if (isFooter) {
generateHorizontalNavBarHeaderFooterRow(isFooter);
generateHorizontalNavBarLocalNavTableRow(relativePathToBaseDirectory, nTypeConstructors, nFunctions, nTypeClasses, nClassInstances);
generateHorizontalNavBarGlobalNavTableRow(relativePathToBaseDirectory);
} else {
generateHorizontalNavBarGlobalNavTableRow(relativePathToBaseDirectory);
generateHorizontalNavBarLocalNavTableRow(relativePathToBaseDirectory, nTypeConstructors, nFunctions, nTypeClasses, nClassInstances);
generateHorizontalNavBarHeaderFooterRow(isFooter);
}
currentPage
.closeTag(HTML.Tag.DIV);
}
/**
* Generates the header/footer row in the navigation bar.
* @param isFooter true if this bar forms the footer; false if this bar forms the header.
*/
private void generateHorizontalNavBarHeaderFooterRow(boolean isFooter) {
currentPage
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.NAV_BAR_HEADER_FOOTER), isFooter ? config.footer : config.header);
}
/**
* Generates the global navigation portion of the navigation bar.
* @param relativePathToBaseDirectory the relative path to the base directory for documentation generation.
*/
private void generateHorizontalNavBarGlobalNavTableRow(String relativePathToBaseDirectory) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.NAV_BAR_GLOBAL_ROW))
.addTaggedText(HTML.Tag.A, nonLocalHrefAttribute(relativePathToBaseDirectory + OVERVIEW_PAGE_FILENAME), LocalizableUserVisibleString.OVERVIEW.toResourceString())
.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString())
.addTaggedText(HTML.Tag.A, nonLocalHrefAttribute(relativePathToBaseDirectory + MASTER_SCOPED_ENTITY_SEARCH_PAGE_FILENAME).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TARGET, SEARCH_FRAME_NAME)), LocalizableUserVisibleString.SEARCH.toResourceString())
.closeTag(HTML.Tag.DIV);
}
/**
* Generates the local navigation portion of the navigation bar.
*/
private void generateHorizontalNavBarLocalNavTableRow(String relativePathToBaseDirectory, int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.NAV_BAR_LOCAL_ROW));
if (nTypeConstructors > 0 || nFunctions > 0 || nTypeClasses > 0 || nClassInstances > 0) {
currentPage.addTaggedText(HTML.Tag.A, localHrefAttribute(ElementID.SUMMARY_SECTION), LocalizableUserVisibleString.MODULE_SUMMARY.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DISABLED_LINK), LocalizableUserVisibleString.MODULE_SUMMARY.toResourceString());
}
currentPage.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString());
if (nTypeConstructors > 0) {
HTMLBuilder.AttributeList hrefAttribute;
if (inSeparateInstanceDoc) {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + MODULES_SUBDIRECTORY + "/" + getModuleFileName(currentModuleName), ElementID.TYPES_SECTION);
} else {
hrefAttribute = localHrefAttribute(ElementID.TYPES_SECTION);
}
currentPage.addTaggedText(HTML.Tag.A, hrefAttribute, LocalizableUserVisibleString.TYPES.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DISABLED_LINK), LocalizableUserVisibleString.TYPES.toResourceString());
}
currentPage.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString());
if (nFunctions > 0) {
HTMLBuilder.AttributeList hrefAttribute;
if (inSeparateInstanceDoc) {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + MODULES_SUBDIRECTORY + "/" + getModuleFileName(currentModuleName), ElementID.FUNCTIONS_SECTION);
} else {
hrefAttribute = localHrefAttribute(ElementID.FUNCTIONS_SECTION);
}
currentPage.addTaggedText(HTML.Tag.A, hrefAttribute, LocalizableUserVisibleString.FUNCTIONS.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DISABLED_LINK), LocalizableUserVisibleString.FUNCTIONS.toResourceString());
}
currentPage.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString());
if (nTypeClasses > 0) {
HTMLBuilder.AttributeList hrefAttribute;
if (inSeparateInstanceDoc) {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + MODULES_SUBDIRECTORY + "/" + getModuleFileName(currentModuleName), ElementID.TYPE_CLASSES_SECTION);
} else {
hrefAttribute = localHrefAttribute(ElementID.TYPE_CLASSES_SECTION);
}
currentPage.addTaggedText(HTML.Tag.A, hrefAttribute, LocalizableUserVisibleString.TYPE_CLASSES.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DISABLED_LINK), LocalizableUserVisibleString.TYPE_CLASSES.toResourceString());
}
currentPage.addText(LocalizableUserVisibleString.NAV_BAR_ITEM_SEPARATOR.toResourceString());
if (nClassInstances > 0) {
HTMLBuilder.AttributeList hrefAttribute;
if (config.shouldSeparateInstanceDoc && !inSeparateInstanceDoc) {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + SEPARATE_INSTANCE_DOC_SUBDIRECTORY + "/" + getSeparateInstanceDocFileName(currentModuleName), ElementID.INSTANCES_SECTION);
} else {
hrefAttribute = localHrefAttribute(ElementID.INSTANCES_SECTION);
}
currentPage.addTaggedText(HTML.Tag.A, hrefAttribute, LocalizableUserVisibleString.INSTANCES.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DISABLED_LINK), LocalizableUserVisibleString.INSTANCES.toResourceString());
}
currentPage.closeTag(HTML.Tag.DIV);
}
/**
* Generates the fine print at the bottom of the page.
*/
private void generatePageBottom() {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.PAGE_BOTTOM), config.bottom);
}
/////====================================================================================================
////
/// File name builders
//
/**
* Constructs a file name for the main documentation page from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getModuleFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name prefix for a per-module index from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name prefix.
*/
private String getPerModuleIndexFileNamePrefix(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR;
}
/**
* Constructs a file name for the type index page from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getPerModuleTypeIndexFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR + TYPE_INDEX_FILENAME_POSTFIX + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the functional agent index page from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getPerModuleFunctionalAgentIndexFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR + FUNCTIONAL_AGENT_INDEX_FILENAME_POSTFIX + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the type class index page from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getPerModuleTypeClassIndexFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR + TYPE_CLASS_INDEX_FILENAME_POSTFIX + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the instance index page from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getPerModuleInstanceIndexFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR + INSTANCE_INDEX_FILENAME_POSTFIX + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the type usage indices page from a type constructor name, properly disambiguated.
* @param qualifiedName the qualified name of the type constructor.
* @return the corresponding file name.
*/
private String getTypeConsUsageIndexFileName(QualifiedName qualifiedName) {
ModuleName moduleName = qualifiedName.getModuleName();
return getDisambiguatedNameForModule(moduleName) + DOT + getDisambiguatedNameForTypeCons(moduleName, qualifiedName.getUnqualifiedName()) + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the type class usage indices page from a type class name, properly disambiguated.
* @param qualifiedName the qualified name of the type class.
* @return the corresponding file name.
*/
private String getTypeClassUsageIndexFileName(QualifiedName qualifiedName) {
ModuleName moduleName = qualifiedName.getModuleName();
return getDisambiguatedNameForModule(moduleName) + DOT + getDisambiguatedNameForTypeClass(moduleName, qualifiedName.getUnqualifiedName()) + DOT + HTML_FILE_EXTENSION;
}
/**
* Constructs a file name for the separate instance documentation from a module name, properly disambiguated.
* @param moduleName the module name.
* @return the corresponding file name.
*/
private String getSeparateInstanceDocFileName(ModuleName moduleName) {
return getDisambiguatedNameForModule(moduleName) + FILENAME_POSTFIX_SEPARATOR + SEPARATE_INSTANCE_DOC_FILENAME_POSTFIX + DOT + HTML_FILE_EXTENSION;
}
/////====================================================================================================
////
/// Helpers for building the module summary of a module documentation page, and the usage indices
//
/**
* Generates the start of an overview table.
* @param caption the caption for the table.
* @param nested whether the table is nested within another table.
*/
private void beginOverviewTable(String caption, boolean nested) {
currentPage.openTag(HTML.Tag.TABLE, nested ? overviewNestedTableAttributes() : overviewTableAttributes());
if (caption != null) {
currentPage.addTaggedText(HTML.Tag.CAPTION, classAttribute(StyleClassConstants.MINOR_SECTION), caption);
}
currentPage.openTag(HTML4.TBODY_TAG);
}
/**
* Generates the end of an overview table.
*/
private void endOverviewTable() {
currentPage.closeTag(HTML4.TBODY_TAG).closeTag(HTML.Tag.TABLE);
}
/**
* Generates the overview for a functional agent.
* @param entity the functional agent entity.
* @param metadata the metadata that may be generated.
* @param docComment the CALDoc comment to be generated.
* @param descriptionStyleClass the style class to use for the description.
*/
private void generateFunctionalAgentOverview(FunctionalAgent entity, String label, FunctionalAgentMetadata metadata, CALDocComment docComment, StyleClass descriptionStyleClass) {
TypeExpr typeExpr = entity.getTypeExpr();
/// Generate the cell for the scope
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(entity.getScope())))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), entity.getScope().toString())
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NAME_AND_TYPE))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
/// Generate the entity name, hyperlinked
//
generateLocalReference(label, entity.getName().getUnqualifiedName(), entity.getName().getQualifiedName());
/// Generate the type signature, hyperlinked
//
generateTypeSignature(typeExpr.toSourceModel(true, ScopedEntityNamingPolicy.FULLY_QUALIFIED));
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.SPAN);
maybeGenerateClassMethodIndicator(entity);
currentPage
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(descriptionStyleClass));
/// Generate the short description
//
generateShortDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
/**
* If the entity is a class method, then generate the required/optional indicator.
* @param entity the functional agent entity, which may or may not be a class method.
*/
private void maybeGenerateClassMethodIndicator(FunctionalAgent entity) {
if (entity instanceof ClassMethod) {
ClassMethod method = (ClassMethod)entity;
final String text;
if (method.getDefaultClassMethodName() == null) {
// no default - required
text = LocalizableUserVisibleString.REQUIRED_METHOD_INDICATOR.toResourceString();
} else {
// has default - optional
text = LocalizableUserVisibleString.OPTIONAL_METHOD_INDICATOR.toResourceString();
}
currentPage
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.CLASS_METHOD_INDICATOR), text);
}
}
/**
* Generates an entry for a usage index.
* @param entity the functional agent entity.
* @param metadata the metadata that may be generated.
* @param docComment the CALDoc comment to be generated.
* @param descriptionStyleClass the style class to use for the description.
*/
private void generateUsageIndexEntry(FunctionalAgent entity, String label, FunctionalAgentMetadata metadata, CALDocComment docComment, StyleClass descriptionStyleClass) {
TypeExpr typeExpr = entity.getTypeExpr();
/// Generate the cell for the scope
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(entity.getScope())))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), entity.getScope().toString())
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NAME_AND_TYPE))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
/// Generate the entity name, hyperlinked
//
String relativePathToModulesSubdirectory = "../" + MODULES_SUBDIRECTORY;
generateNonLocalReference(currentPage, relativePathToModulesSubdirectory, entity.getName().getModuleName(), label, entity.getName().getUnqualifiedName(), entity.getName().getQualifiedName());
/// Generate the type signature, hyperlinked
//
generateTypeSignature(typeExpr.toSourceModel(true, ScopedEntityNamingPolicy.FULLY_QUALIFIED), new TypeSignatureHTMLGeneratorUsingNonLocalReferences(relativePathToModulesSubdirectory));
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(descriptionStyleClass));
/// Generate the short description
//
generateShortDescription(metadata, docComment, new ReferenceGenerator(relativePathToModulesSubdirectory));
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
////
/// Generation of short descriptions
//
/**
* Generates the short description - the summary preceded by any deprecated block.
* @param metadata the metadata that may be generated.
* @param docComment the CALDoc comment to be generated.
* @param referenceGenerator the reference generator to use for generating cross references.
*/
private void generateShortDescription(CALFeatureMetadata metadata, CALDocComment docComment, ReferenceGenerator referenceGenerator) {
CALDocComment.TextBlock deprecatedBlock = null;
if (docComment != null) {
deprecatedBlock = docComment.getDeprecatedBlock();
}
// Deprecated block
generateHTMLForAttribute(StyleClassConstants.OVERVIEW_DEPRECATED_BLOCK, LocalizableUserVisibleString.DEPRECATED_COLON.toResourceString(), null, deprecatedBlock, referenceGenerator, deprecatedBlock != null);
// Main description summary
generateHTMLForAttribute(
StyleClassConstants.SHORT_DESCRIPTION_BLOCK,
null,
getBestShortDescriptionFromMetadata(metadata),
CALDocToHTMLUtilities.getSummaryFromCALDoc(docComment, referenceGenerator, getLocale(), LocalizableUserVisibleString.RETURNS_COLON.toResourceString(), StyleClassConstants.CODE_BLOCK, CODE_FORMATTING_TAG),
referenceGenerator,
false);
}
/**
* Obtains the first sentence from a piece of text.
* @param text the text from which the first sentence is to be extracted. Can be null.
* @return the first sentence, or null if none is available.
*/
private String getFirstSentence(String text) {
if (text == null) {
return null;
}
/// Use BreakIterator to parse the text and identify the first sentence.
//
Locale locale = getLocale();
BreakIterator breakIterator;
if (LocaleUtilities.isInvariantLocale(locale)) {
breakIterator = BreakIterator.getSentenceInstance();
} else {
breakIterator = BreakIterator.getSentenceInstance(locale);
}
breakIterator.setText(text);
/// The first sentence is from the start of the string to the first sentence boundary.
//
int firstSentenceBoundary = breakIterator.next();
if (firstSentenceBoundary == BreakIterator.DONE) {
return null;
} else {
return text.substring(0, firstSentenceBoundary).trim();
}
}
/////====================================================================================================
////
/// Helpers for generating the details section of a module documentation page
//
/**
* Generates the standard description - the main description preceded by any deprecated block.
* @param metadata the metadata that may be generated.
* @param docComment the CALDoc comment to be generated.
* @param referenceGenerator the reference generator to use for generating cross references.
*/
private void generateStandardDescription(CALFeatureMetadata metadata, CALDocComment docComment, ReferenceGenerator referenceGenerator) {
// Obtain the various blocks from the CALDoc comment, if docComment is not null
CALDocComment.TextBlock descriptionBlock = null;
CALDocComment.TextBlock deprecatedBlock = null;
if (docComment != null) {
descriptionBlock = docComment.getDescriptionBlock();
deprecatedBlock = docComment.getDeprecatedBlock();
}
// Deprecated block
generateHTMLForAttribute(StyleClassConstants.DEPRECATED_BLOCK, LocalizableUserVisibleString.DEPRECATED_COLON.toResourceString(), null, deprecatedBlock, referenceGenerator, deprecatedBlock != null);
// Main description
generateHTMLForAttribute(StyleClassConstants.DESCRIPTION_BLOCK, null, getBestDescriptionFromMetadata(metadata), descriptionBlock, referenceGenerator, false);
}
/**
* Generates the standard supplementary blocks - the author, version and see blocks.
* @param metadata the metadata that may be generated.
* @param docComment the CALDoc comment to be generated.
* @param referenceGenerator the reference generator to use for generating cross references.
*/
private void generateStandardSupplementaryBlocks(final CALFeatureMetadata metadata, final CALDocComment docComment, ReferenceGenerator referenceGenerator) {
/// Obtain the various blocks from the CALDoc comment, if docComment is not null
//
CALDocComment.TextBlock versionBlock = null;
ContentConvertibleToHTML valueFromAuthorBlocks = null;
ContentConvertibleToHTML valueFromSeeBlocks = null;
if (docComment != null) {
versionBlock = docComment.getVersionBlock();
/// Construct a ContentConvertibleToHTML instance to represent the contents of *all* the author blocks
//
valueFromAuthorBlocks = new ContentConvertibleToHTML() {
private final int nAuthorBlocks = docComment.getNAuthorBlocks();
/** {@inheritDoc} */
@Override
boolean isEmpty() {
return nAuthorBlocks == 0;
}
/** {@inheritDoc} */
@Override
void generateHTML(HTMLBuilder currentPage, CALDocToHTMLUtilities.CrossReferenceHTMLGenerator referenceGenerator) {
for (int i = 0; i < nAuthorBlocks; i++) {
if (i > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
CALDocToHTMLUtilities.generateHTMLForCALDocTextBlock(docComment.getNthAuthorBlock(i), currentPage, referenceGenerator, StyleClassConstants.CODE_BLOCK, CODE_FORMATTING_TAG);
}
}
};
/// Construct a ContentConvertibleToHTML instance to represent the contents of *all* the see blocks
//
valueFromSeeBlocks = new ContentConvertibleToHTML() {
private final int nModuleReferences = docComment.getNModuleReferences();
private final int nTypeClassModuleReferences = docComment.getNTypeClassReferences();
private final int nTypeConstructorReferences = docComment.getNTypeConstructorReferences();
private final int nDataConstructorReferences = docComment.getNDataConstructorReferences();
private final int nFunctionOrClassMethodReferences = docComment.getNFunctionOrClassMethodReferences();
/** {@inheritDoc} */
@Override
boolean isEmpty() {
return nModuleReferences + nTypeClassModuleReferences + nTypeConstructorReferences + nDataConstructorReferences + nFunctionOrClassMethodReferences == 0;
}
/** {@inheritDoc} */
@Override
void generateHTML(HTMLBuilder currentPage, CALDocToHTMLUtilities.CrossReferenceHTMLGenerator referenceGenerator) {
int masterCount = 0;
for (int i = 0; i < nModuleReferences; i++, masterCount++) {
if (masterCount > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateModuleReference(docComment.getNthModuleReference(i).getName());
currentPage.closeTag(HTML.Tag.CODE);
}
for (int i = 0; i < nTypeClassModuleReferences; i++, masterCount++) {
if (masterCount > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateTypeClassReference(docComment.getNthTypeClassReference(i).getName());
currentPage.closeTag(HTML.Tag.CODE);
}
for (int i = 0; i < nTypeConstructorReferences; i++, masterCount++) {
if (masterCount > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateTypeConsReference(docComment.getNthTypeConstructorReference(i).getName());
currentPage.closeTag(HTML.Tag.CODE);
}
for (int i = 0; i < nDataConstructorReferences; i++, masterCount++) {
if (masterCount > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateDataConsReference(docComment.getNthDataConstructorReference(i).getName());
currentPage.closeTag(HTML.Tag.CODE);
}
for (int i = 0; i < nFunctionOrClassMethodReferences; i++, masterCount++) {
if (masterCount > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateFunctionOrClassMethodReference(docComment.getNthFunctionOrClassMethodReference(i).getName());
currentPage.closeTag(HTML.Tag.CODE);
}
}
};
}
/// Author block
//
if (shouldGenerateAuthorInfo()) {
generateHTMLForAttribute(StyleClassConstants.AUTHOR_BLOCK, LocalizableUserVisibleString.AUTHOR_COLON.toResourceString(), metadata.getAuthor(), valueFromAuthorBlocks, referenceGenerator, false);
}
/// Version block
//
if (shouldGenerateVersionInfo()) {
generateHTMLForAttribute(StyleClassConstants.VERSION_BLOCK, LocalizableUserVisibleString.VERSION_COLON.toResourceString(), metadata.getVersion(), versionBlock, referenceGenerator, false);
}
/// See blocks
//
ContentConvertibleToHTML relatedReferencesFromMetadata = new ContentConvertibleToHTML() {
private final int nRelatedFeatures = metadata.getNRelatedFeatures();
/** {@inheritDoc} */
@Override
boolean isEmpty() {
return nRelatedFeatures == 0;
}
/** {@inheritDoc} */
@Override
void generateHTML(HTMLBuilder currentPage, CALDocToHTMLUtilities.CrossReferenceHTMLGenerator referenceGenerator) {
for (int i = 0; i < nRelatedFeatures; i++) {
if (i > 0) {
currentPage.addText(LocalizableUserVisibleString.COMMA_AND_SPACE.toResourceString());
}
currentPage.openTag(HTML.Tag.CODE);
generateCALFeatureReference(metadata.getNthRelatedFeature(i));
currentPage.closeTag(HTML.Tag.CODE);
}
}
};
generateHTMLForAttribute(StyleClassConstants.SEE_BLOCK, LocalizableUserVisibleString.SEE_ALSO_COLON.toResourceString(), relatedReferencesFromMetadata, valueFromSeeBlocks, referenceGenerator, false);
}
/**
* Get the "best" short description from metadata. If the short description is available, that is taken.
* Otherwise the first sentence of the long description is taken.
*
* @param metadata the metadata from which a short description is to be extracted. Can be null.
* @return the short description, or null if none is available.
*/
private String getBestShortDescriptionFromMetadata(CALFeatureMetadata metadata) {
if (metadata == null) {
return null;
}
String shortDesc = metadata.getShortDescription();
if (shortDesc != null && shortDesc.length() > 0) {
return shortDesc;
}
String longDesc = metadata.getLongDescription();
if (longDesc != null && longDesc.length() > 0) {
return getFirstSentence(longDesc);
}
return null;
}
/**
* Get the "best" description from metadata. If the long description is available, that is taken.
* Otherwise the short description is taken.
*
* @param metadata the metadata from which a description is to be extracted. Can be null.
* @return the description, or null if none is available.
*/
private String getBestDescriptionFromMetadata(CALFeatureMetadata metadata) {
if (metadata == null) {
return null;
}
String longDesc = metadata.getLongDescription();
if (longDesc != null && longDesc.length() > 0) {
return longDesc;
}
String shortDesc = metadata.getShortDescription();
if (shortDesc != null && shortDesc.length() > 0) {
return shortDesc;
}
return null;
}
/**
* Generates the HTML for an "attribute block" - a block that starts with an emphasized header followed by the body.
* @param styleClass the style class to use for the block.
* @param header the header text. Can be null.
* @param metadataValue the value obtained from metadata for the attribute block. Can be null.
* @param textBlock the CALDoc text block for the attribute block. Can be null
* @param referenceGenerator the reference generator to use for generating cross references.
* @param generateEvenIfEmpty to generate the attribute block even when it is empty.
*/
private void generateHTMLForAttribute(StyleClass styleClass, String header, String metadataValue, CALDocComment.TextBlock textBlock, ReferenceGenerator referenceGenerator, boolean generateEvenIfEmpty) {
generateHTMLForAttribute(styleClass, header, metadataValue, new SingleTextBlockContent(textBlock, StyleClassConstants.CODE_BLOCK, CODE_FORMATTING_TAG), referenceGenerator, generateEvenIfEmpty);
}
/**
* Generates the HTML for an "attribute block" - a block that starts with an emphasized header followed by the body.
* @param styleClass the style class to use for the block.
* @param header the header text. Can be null.
* @param metadataValue the value obtained from metadata for the attribute block. Can be null.
* @param valueFromCALDoc the value obtained from CALDoc for the attribute block. Can be null
* @param referenceGenerator the reference generator to use for generating cross references.
* @param generateEvenIfEmpty to generate the attribute block even when it is empty.
*/
private void generateHTMLForAttribute(StyleClass styleClass, String header, String metadataValue, ContentConvertibleToHTML valueFromCALDoc, ReferenceGenerator referenceGenerator, boolean generateEvenIfEmpty) {
generateHTMLForAttribute(styleClass, header, new SimpleStringContent(metadataValue), valueFromCALDoc, referenceGenerator, generateEvenIfEmpty);
}
/**
* Generates the HTML for an "attribute block" - a block that starts with an emphasized header followed by the body.
* @param styleClass the style class to use for the block.
* @param header the header text. Can be null.
* @param metadataValue the value obtained from metadata for the attribute block. Can be null.
* @param valueFromCALDoc the value obtained from CALDoc for the attribute block. Can be null
* @param referenceGenerator the reference generator to use for generating cross references.
* @param generateEvenIfEmpty to generate the attribute block even when it is empty.
*/
private void generateHTMLForAttribute(StyleClass styleClass, String header, ContentConvertibleToHTML metadataValue, ContentConvertibleToHTML valueFromCALDoc, ReferenceGenerator referenceGenerator, boolean generateEvenIfEmpty) {
////
/// Figure out whether we need to generate a) metadata and b) CALDoc
//
boolean genMetadata = (shouldGenerateFromMetadata() && metadataValue != null && !metadataValue.isEmpty());
boolean genCALDoc = ((shouldAlwaysGenerateFromCALDoc() || !genMetadata) && valueFromCALDoc != null && !valueFromCALDoc.isEmpty());
if (generateEvenIfEmpty || genMetadata || genCALDoc) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(styleClass));
/// If the header is not null, generate a new definition list and use it as the definition term.
//
if (header != null) {
currentPage.openTag(HTML.Tag.DL).addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), header).openTag(HTML.Tag.DD);
}
/// Generate the metadata, if required.
//
if (genMetadata) {
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateMetadataIndicator();
metadataValue.generateHTML(currentPage, referenceGenerator);
currentPage.closeTag(HTML.Tag.DIV);
}
/// Generate the CALDoc, if required.
//
if (genCALDoc) {
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateCALDocIndicator();
valueFromCALDoc.generateHTML(currentPage, referenceGenerator);
currentPage.closeTag(HTML.Tag.DIV);
}
/// Close the definition list if one was opened.
//
if (header != null) {
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* Generates an indicator denoting that the following block came from CALDoc if and only if metadata is to be included with the documentation.
*/
private void maybeGenerateCALDocIndicator() {
if (shouldGenerateFromMetadata()) {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.CALDOC_INDICATOR), LocalizableUserVisibleString.CALDOC_INDICATOR.toResourceString()).newline();
}
}
/**
* Generates an indicator denoting that the following block came from metadata if and only if metadata is to be included with the documentation.
*/
private void maybeGenerateMetadataIndicator() {
if (shouldGenerateFromMetadata()) {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.METADATA_INDICATOR), LocalizableUserVisibleString.METADATA_INDICATOR.toResourceString()).newline();
}
}
/////====================================================================================================
////
/// Helpers for generating type signatures, appropriately hyperlinked
//
/**
* Generates a type signature with the type classes and type constructors contained therein appropriately hyperlinked.
* @param typeSignature the type signature.
*/
private void generateTypeSignature(SourceModel.TypeSignature typeSignature) {
generateTypeSignature(typeSignature, new TypeSignatureHTMLGenerator(true));
}
/**
* Generates a type signature with the specified type signature HTML generator.
* @param typeSignature the type signature.
* @param typeSigHTMLGenerator the type signature HTML generator to use for the generation.
*/
private void generateTypeSignature(SourceModel.TypeSignature typeSignature, TypeSignatureHTMLGenerator typeSigHTMLGenerator) {
currentPage.addTaggedText(HTML.Tag.CODE, " " + CALFragments.COLON_COLON + " ");
currentPage.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TYPE_SIGNATURE)).openTag(HTML.Tag.CODE);
typeSignature.accept(typeSigHTMLGenerator, null);
currentPage.closeTag(HTML.Tag.CODE).closeTag(HTML.Tag.SPAN);
}
/////====================================================================================================
////
/// Helpers for constructing commonly used HTML attributes
//
/**
* Constructs an HTML 'id' attribute.
* @param id the id value. Can be null (an empty attribute list is returned).
* @return a singleton attribute list.
*/
private HTMLBuilder.AttributeList idAttribute(String id) {
if (id == null) {
return HTMLBuilder.AttributeList.make();
} else {
return HTMLBuilder.AttributeList.make(HTML.Attribute.ID, id);
}
}
/**
* Constructs an HTML 'class' attribute.
* @param styleClass the style class value. Can be null (an empty attribute list is returned).
* @return a singleton attribute list.
*/
private HTMLBuilder.AttributeList classAttribute(StyleClass styleClass) {
if (styleClass == null) {
return HTMLBuilder.AttributeList.make();
} else {
return HTMLBuilder.AttributeList.make(HTML.Attribute.CLASS, styleClass.toHTML());
}
}
/**
* Constructs an HTML attribute list from the 'id' and 'class' attributes.
* @param id the id value.
* @param styleClass the style class value.
* @return an attribute list with the two attributes.
*/
private HTMLBuilder.AttributeList idAndClassAttributes(String id, StyleClass styleClass) {
return idAttribute(id).concat(classAttribute(styleClass));
}
/**
* Constructs an HTML 'href' attribute referring to an anchor on the same page.
* @param id the name of the anchor.
* @return a singleton attribute list.
*/
private HTMLBuilder.AttributeList localHrefAttribute(String id) {
if (disableAllHyperlinks) {
return HTMLBuilder.AttributeList.make();
} else {
return HTMLBuilder.AttributeList.make(HTML.Attribute.HREF, "#" + id);
}
}
/**
* Constructs an HTML 'href' attribute referring to another file.
* @param filePath the path to the file being linked to.
* @return a singleton attribute list.
*/
private HTMLBuilder.AttributeList nonLocalHrefAttribute(String filePath) {
return nonLocalHrefAttribute(filePath, null);
}
/**
* Constructs an HTML 'href' attribute referring to another file, or an anchor in another file.
* @param filePath the path to the file being linked to.
* @param id the name of the anchor in the other file. Can be null.
* @return a singleton attribute list.
*/
private HTMLBuilder.AttributeList nonLocalHrefAttribute(String filePath, String id) {
if (disableAllHyperlinks) {
return HTMLBuilder.AttributeList.make();
} else {
if (id != null) {
return HTMLBuilder.AttributeList.make(HTML.Attribute.HREF, filePath + "#" + id);
} else {
return HTMLBuilder.AttributeList.make(HTML.Attribute.HREF, filePath);
}
}
}
/**
* Constructs an HTML attribute list for an overview table with the specified style class.
* @param styleClass the style class to use for the table.
* @return the appropriate attribute list.
*/
private HTMLBuilder.AttributeList overviewTableAttributesWithStyleClass(StyleClass styleClass) {
return classAttribute(styleClass)
.concat(HTMLBuilder.AttributeList.make(HTML4.RULES_ATTRIBUTE, "rows"))
.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.CELLPADDING, "5"))
.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.CELLSPACING, "0"))
.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.BORDER, "1"))
.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.WIDTH, "100%"));
}
/**
* Constructs an HTML attribute list for an outer overview table.
* @return the appropriate attribute list.
*/
private HTMLBuilder.AttributeList overviewTableAttributes() {
return overviewTableAttributesWithStyleClass(StyleClassConstants.OVERVIEW_TABLE);
}
/**
* Constructs an HTML attribute list for a nested overview table.
* @return the appropriate attribute list.
*/
private HTMLBuilder.AttributeList overviewNestedTableAttributes() {
return overviewTableAttributesWithStyleClass(StyleClassConstants.OVERVIEW_NESTED_TABLE);
}
/**
* Generates a link to the usages page if usage indices are to be generated.
* @param usageSubdirectory the subdirectory for the usage page to link to.
* @param usageIndexFileName the usage page file name to link to.
*/
private void maybeGenerateUsageLink(String usageSubdirectory, String usageIndexFileName) {
if (shouldGenerateUsageIndices) {
currentPage
.addText(" [")
.addTaggedText(HTML.Tag.A, nonLocalHrefAttribute("../" + usageSubdirectory + "/" + usageIndexFileName), LocalizableUserVisibleString.USAGE_INDEX_ENTRY.toResourceString())
.addText("]");
}
}
/////====================================================================================================
////
/// Helpers for generating argument names and hyperlinked references
//
/**
* Generates an argument name of an FunctionalAgent. If metadata is to be included in documentation, this gives
* preference to the name coming from the metadata. Otherwise, it gives preference to the name given in
* CALDoc, if it is different from the name appearing in the entity itself.
*
* @param entity the FunctionalAgent whose argument name is being generated.
* @param index the position of the argument in the argument list.
* @param argMetadata the argument's metadata. Can be null.
* @param docComment the CALDoc comment of the entity. Can be null.
* @param setOfArgumentNames the (Set of Strings) of argument names already used (for disambiguation purposes).
*/
private void generateArgumentName(FunctionalAgent entity, int index, ArgumentMetadata argMetadata, CALDocComment docComment, Set<String> setOfArgumentNames) {
////
/// First fetch the name from the entity. This will mostly be the same name as the one appearing in code, except for
/// foreign functions, which may have their names extracted from the Java classes' debug info.
//
String nameFromEntity = null;
if (index < entity.getNArgumentNames()) {
nameFromEntity = entity.getArgumentName(index);
}
if (shouldGenerateFromMetadata() && argMetadata != null && argMetadata.getDisplayName() != null && argMetadata.getDisplayName().trim().length() > 0) {
////
/// If metadata is to be included, and the metadata yields a non-empty display name for the argument, use it.
//
String nameFromMetadata = argMetadata.getDisplayName().trim();
currentPage.addTaggedText(HTML.Tag.CODE, classAttribute(StyleClassConstants.ARG_NAME_FROM_METADATA), nameFromMetadata);
setOfArgumentNames.add(nameFromMetadata);
} else if (docComment != null && index < docComment.getNArgBlocks()) {
////
/// Since either metadata is not to be included, or it is not available, we fallback to the CALDoc.
//
String nameFromCALDoc = docComment.getNthArgBlock(index).getArgName().getCalSourceForm();
/// We decorate the argument name with the appropriate style class depending on whether the CALDoc argument name
/// matches the one found in the entity (in which case the name came from code).
//
if (nameFromCALDoc.equals(nameFromEntity)) {
currentPage.addTaggedText(HTML.Tag.CODE, classAttribute(StyleClassConstants.ARG_NAME_FROM_CODE), nameFromEntity);
setOfArgumentNames.add(nameFromEntity);
} else {
currentPage.addTaggedText(HTML.Tag.CODE, classAttribute(StyleClassConstants.ARG_NAME_FROM_CALDOC), nameFromCALDoc);
setOfArgumentNames.add(nameFromCALDoc);
}
} else if (nameFromEntity != null) {
////
/// If the entity yielded a name, use it.
//
currentPage.addTaggedText(HTML.Tag.CODE, classAttribute(StyleClassConstants.ARG_NAME_FROM_CODE), nameFromEntity);
setOfArgumentNames.add(nameFromEntity);
} else {
////
/// Since not even the entity yielded a name, construct an artificial one of the form arg_x, where x is the
/// 1-based index of the argument in the argument list, or of the form arg_x_y if arg_x, arg_x_1, ...
/// arg_x_(y-1) have all appeared previously in the argument list.
//
// the base artificial name we'll attempt to use is arg_x, where x is the 1-based index of this argument
String baseArtificialName = "arg_" + (index + 1);
String artificialName = baseArtificialName;
// if the base artificial name already appears in previous arguments, then
// make the argument name arg_x_y, where y is a supplementary disambiguating number
// chosen so that the resulting name will not collide with any of the previous argument names
int supplementaryDisambiguator = 1;
while (setOfArgumentNames.contains(artificialName)) {
artificialName = baseArtificialName + "_" + supplementaryDisambiguator;
supplementaryDisambiguator++;
}
currentPage.addTaggedText(HTML.Tag.CODE, classAttribute(StyleClassConstants.ARG_NAME_ARTIFICIAL), artificialName);
setOfArgumentNames.add(artificialName);
}
}
/**
* Generates a reference to another module, appropriately hyperlinked.
* @param moduleName the name of the module to link to.
*/
private void generateModuleReference(ModuleName moduleName) {
generateModuleReference(currentPage, moduleName);
}
/**
* Generates a reference to another module, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param moduleName the name of the module to link to.
*/
private void generateModuleReference(HTMLBuilder builder, ModuleName moduleName) {
generateModuleReference(builder, null, moduleName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Generates a reference to another module, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param reference the name of the module to link to.
*/
private void generateModuleReference(HTMLBuilder builder, String relativeDirectory, CALDocComment.ModuleReference reference) {
ModuleName moduleName = reference.getName();
String displayName = reference.getModuleNameInSource();
if (displayName.length() == 0) {
displayName = getMinimallyQualifiedNameForModule(moduleName);
}
generateModuleReference(builder, relativeDirectory, moduleName, displayName);
}
/**
* Generates a reference to another module, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the module to link to.
* @param moduleDisplayName the name to be displayed for the module.
*/
private void generateModuleReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String moduleDisplayName) {
if (isDocForModuleGenerated(moduleName)) {
generateNonLocalReference(builder, relativeDirectory, moduleName, labelMaker.getModuleLabel(moduleName), moduleDisplayName, getFullyQualifiedNameForModule(moduleName));
} else {
builder.addText(moduleDisplayName);
}
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.
* @param qualifiedName the name of the type constructor to link to.
*/
private void generateTypeConsReference(QualifiedName qualifiedName) {
generateTypeConsReference(qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName());
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param qualifiedName the name of the type constructor to link to.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeConsReference(HTMLBuilder builder, String relativeDirectory, QualifiedName qualifiedName, String moduleNameInSource) {
generateTypeConsReference(builder, relativeDirectory, qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName(), moduleNameInSource);
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.
* @param moduleName the name of the type constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the type constructor.
*/
private void generateTypeConsReference(ModuleName moduleName, String unqualifiedName) {
generateTypeConsReference(currentPage, moduleName, unqualifiedName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param moduleName the name of the type constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the type constructor.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeConsReference(HTMLBuilder builder, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
generateTypeConsReference(builder, null, moduleName, unqualifiedName, moduleNameInSource);
}
/**
* Generates a reference to a type constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the type constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the type constructor.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeConsReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
String typeConsLabel = labelMaker.getTypeConsLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName, moduleNameInSource);
if (!isDocForTypeConsGenerated(moduleName, unqualifiedName)) {
builder.addText(appropriatelyQualifiedName);
} else if ((moduleName == null || moduleName.equals(currentModuleName)) && !inSeparateInstanceDoc) {
generateLocalReference(builder, typeConsLabel, unqualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
} else {
generateNonLocalReference(builder, relativeDirectory, moduleName, typeConsLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
/**
* Generates a reference to a data constructor, appropriately hyperlinked.
* @param qualifiedName the name of the data constructor to link to.
*/
private void generateDataConsReference(QualifiedName qualifiedName) {
generateDataConsReference(qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName());
}
/**
* Generates a reference to a data constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param qualifiedName the name of the data constructor to link to.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateDataConsReference(HTMLBuilder builder, String relativeDirectory, QualifiedName qualifiedName, String moduleNameInSource) {
generateDataConsReference(builder, relativeDirectory, qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName(), moduleNameInSource);
}
/**
* Generates a reference to a data constructor, appropriately hyperlinked.
* @param moduleName the name of the data constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the data constructor.
*/
private void generateDataConsReference(ModuleName moduleName, String unqualifiedName) {
generateDataConsReference(currentPage, moduleName, unqualifiedName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Generates a reference to a data constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param moduleName the name of the data constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the data constructor.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateDataConsReference(HTMLBuilder builder, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
generateDataConsReference(builder, null, moduleName, unqualifiedName, moduleNameInSource);
}
/**
* Generates a reference to a data constructor, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the data constructor's module. Can be null.
* @param unqualifiedName the unqualified name of the data constructor.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateDataConsReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
String dataConsLabel = labelMaker.getDataConsLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName, moduleNameInSource);
if (!isDocForDataConsGenerated(moduleName, unqualifiedName)) {
builder.addText(appropriatelyQualifiedName);
} else if ((moduleName == null || moduleName.equals(currentModuleName)) && !inSeparateInstanceDoc) {
generateLocalReference(builder, dataConsLabel, unqualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
} else {
generateNonLocalReference(builder, relativeDirectory, moduleName, dataConsLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
/**
* Generates a reference to a function or class method, appropriately hyperlinked.
* @param qualifiedName the name of the function or class method to link to.
*/
private void generateFunctionOrClassMethodReference(QualifiedName qualifiedName) {
generateFunctionOrClassMethodReference(qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName());
}
/**
* Generates a reference to a function or class method, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param qualifiedName the name of the function or class method to link to.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateFunctionOrClassMethodReference(HTMLBuilder builder, String relativeDirectory, QualifiedName qualifiedName, String moduleNameInSource) {
generateFunctionOrClassMethodReference(builder, relativeDirectory, qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName(), moduleNameInSource);
}
/**
* Generates a reference to a function or class method, appropriately hyperlinked.
* @param moduleName the name of the function or class method's module. Can be null.
* @param unqualifiedName the unqualified name of the function or class method.
*/
private void generateFunctionOrClassMethodReference(ModuleName moduleName, String unqualifiedName) {
generateFunctionOrClassMethodReference(currentPage, moduleName, unqualifiedName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Generates a reference to a function or class method, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param moduleName the name of the function or class method's module. Can be null.
* @param unqualifiedName the unqualified name of the function or class method.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateFunctionOrClassMethodReference(HTMLBuilder builder, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
generateFunctionOrClassMethodReference(builder, null, moduleName, unqualifiedName, moduleNameInSource);
}
/**
* Generates a reference to a function or class method, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the function or class method's module. Can be null.
* @param unqualifiedName the unqualified name of the function or class method.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateFunctionOrClassMethodReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
String functionOrClassMethodLabel = labelMaker.getFunctionOrClassMethodLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName, moduleNameInSource);
if (!isDocForFunctionOrClassMethodGenerated(moduleName, unqualifiedName)) {
builder.addText(appropriatelyQualifiedName);
} else if ((moduleName == null || moduleName.equals(currentModuleName)) && !inSeparateInstanceDoc) {
generateLocalReference(builder, functionOrClassMethodLabel, unqualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
} else {
generateNonLocalReference(builder, relativeDirectory, moduleName, functionOrClassMethodLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
/**
* Generates a reference to a type class, appropriately hyperlinked.
* @param qualifiedName the name of the type class to link to.
*/
private void generateTypeClassReference(QualifiedName qualifiedName) {
generateTypeClassReference(qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName());
}
/**
* Generates a reference to a type class, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param qualifiedName the name of the type class to link to.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeClassReference(HTMLBuilder builder, String relativeDirectory, QualifiedName qualifiedName, String moduleNameInSource) {
generateTypeClassReference(builder, relativeDirectory, qualifiedName.getModuleName(), qualifiedName.getUnqualifiedName(), moduleNameInSource);
}
/**
* Generates a reference to a type class, appropriately hyperlinked.
* @param moduleName the name of the type class's module. Can be null.
* @param unqualifiedName the unqualified name of the type class.
*/
private void generateTypeClassReference(ModuleName moduleName, String unqualifiedName) {
generateTypeClassReference(currentPage, moduleName, unqualifiedName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Generates a reference to a type class, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param moduleName the name of the type class's module. Can be null.
* @param unqualifiedName the unqualified name of the type class.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeClassReference(HTMLBuilder builder, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
generateTypeClassReference(builder, null, moduleName, unqualifiedName, moduleNameInSource);
}
/**
* Generates a reference to a type class, appropriately hyperlinked.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the type class's module. Can be null.
* @param unqualifiedName the unqualified name of the type class.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
*/
private void generateTypeClassReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
String typeClassLabel = labelMaker.getTypeClassLabel(unqualifiedName);
String appropriatelyQualifiedName = getAppropriatelyQualifiedName(moduleName, unqualifiedName, moduleNameInSource);
if (!isDocForTypeClassGenerated(moduleName, unqualifiedName)) {
builder.addText(appropriatelyQualifiedName);
} else if ((moduleName == null || moduleName.equals(currentModuleName)) && !inSeparateInstanceDoc) {
generateLocalReference(builder, typeClassLabel, unqualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
} else {
generateNonLocalReference(builder, relativeDirectory, moduleName, typeClassLabel, appropriatelyQualifiedName, getFullyQualifiedNameString(moduleName, unqualifiedName));
}
}
/**
* Generates a reference to a class instance, appropriately hyperlinked.
* @param classInstance the class instance to link to.
*/
private void generateClassInstanceReference(ClassInstance classInstance) {
ModuleName definingModuleName = classInstance.getModuleName();
ClassInstanceIdentifier identifier = classInstance.getIdentifier();
String classInstanceLabel = labelMaker.getClassInstanceLabel(identifier);
if (!isDocForClassInstanceGenerated(classInstance)) {
// if the class instance is not documented, no hyperlink can be made.
generateClassInstanceDeclarationName(classInstance, false);
} else {
// the instance is indeed documented, so create a hyperlinked reference to it
HTMLBuilder.AttributeList hrefAttribute;
if (config.shouldSeparateInstanceDoc) {
if (inSeparateInstanceDoc) {
if (definingModuleName == null || definingModuleName.equals(currentModuleName)) {
hrefAttribute = localHrefAttribute(classInstanceLabel);
} else {
hrefAttribute = nonLocalHrefAttribute(getSeparateInstanceDocFileName(definingModuleName), classInstanceLabel);
}
} else {
hrefAttribute = nonLocalHrefAttribute("../" + SEPARATE_INSTANCE_DOC_SUBDIRECTORY + "/" + getSeparateInstanceDocFileName(definingModuleName), classInstanceLabel);
}
} else {
if (definingModuleName == null || definingModuleName.equals(currentModuleName)) {
hrefAttribute = localHrefAttribute(classInstanceLabel);
} else {
hrefAttribute = nonLocalHrefAttribute(getModuleFileName(definingModuleName), classInstanceLabel);
}
}
currentPage.openTag(HTML.Tag.A, hrefAttribute);
generateClassInstanceDeclarationName(classInstance, false);
currentPage.closeTag(HTML.Tag.A);
}
}
/**
* Returns an href attribute for a non local reference to a class instance.
* @param classInstance the class instance to link to.
* @param relativePathToBaseDirectory the relative path to the base directory for documentation generation.
* @return the href attribute.
*/
private HTMLBuilder.AttributeList getHrefAttributeForNonLocalClassInstanceReference(ClassInstance classInstance, String relativePathToBaseDirectory) {
ModuleName definingModuleName = classInstance.getModuleName();
ClassInstanceIdentifier identifier = classInstance.getIdentifier();
String classInstanceLabel = labelMaker.getClassInstanceLabel(identifier);
HTMLBuilder.AttributeList hrefAttribute;
if (config.shouldSeparateInstanceDoc) {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + SEPARATE_INSTANCE_DOC_SUBDIRECTORY + "/" + getSeparateInstanceDocFileName(definingModuleName), classInstanceLabel);
} else {
hrefAttribute = nonLocalHrefAttribute(relativePathToBaseDirectory + MODULES_SUBDIRECTORY + "/" + getModuleFileName(definingModuleName), classInstanceLabel);
}
return hrefAttribute;
}
/**
* Generates a reference to a class instance, appropriately hyperlinked.
* @param identifier the class instance identifier.
* @param definingModuleName the name of the module in which the instance is defined.
*/
private void generateClassInstanceReference(ClassInstanceIdentifier identifier, ModuleName definingModuleName) {
ClassInstance classInstance = programModelManager.getModuleTypeInfo(definingModuleName).getClassInstance(identifier);
generateClassInstanceReference(classInstance);
}
/**
* Generates a reference to an instance method, appropriately hyperlinked.
* @param classInstance the class instance of the instance method.
* @param methodName the name of the instance method.
*/
private void generateInstanceMethodReference(ClassInstance classInstance, String methodName) {
ModuleName definingModuleName = classInstance.getModuleName();
ClassInstanceIdentifier identifier = classInstance.getIdentifier();
String instanceMethodLabel = labelMaker.getInstanceMethodLabel(identifier, methodName);
if (!isDocForClassInstanceGenerated(classInstance)) {
// if the class instance is not documented, no hyperlink can be made.
generateClassInstanceDeclarationName(classInstance, false);
currentPage.addText(" ").addText(methodName);
} else {
// the instance is indeed documented, so create a hyperlinked reference to the instance method
HTMLBuilder.AttributeList hrefAttribute;
if (config.shouldSeparateInstanceDoc) {
if (inSeparateInstanceDoc) {
if (definingModuleName == null || definingModuleName.equals(currentModuleName)) {
hrefAttribute = localHrefAttribute(instanceMethodLabel);
} else {
hrefAttribute = nonLocalHrefAttribute(getSeparateInstanceDocFileName(definingModuleName), instanceMethodLabel);
}
} else {
hrefAttribute = nonLocalHrefAttribute("../" + SEPARATE_INSTANCE_DOC_SUBDIRECTORY + "/" + getSeparateInstanceDocFileName(definingModuleName), instanceMethodLabel);
}
} else {
if (definingModuleName == null || definingModuleName.equals(currentModuleName)) {
hrefAttribute = localHrefAttribute(instanceMethodLabel);
} else {
hrefAttribute = nonLocalHrefAttribute(getModuleFileName(definingModuleName), instanceMethodLabel);
}
}
currentPage.openTag(HTML.Tag.A, hrefAttribute);
generateClassInstanceDeclarationName(classInstance, false);
currentPage.addText(" ").addText(methodName).closeTag(HTML.Tag.A);
}
}
/**
* Generates a reference to an instance method, appropriately hyperlinked.
* @param identifier the class instance identifier.
* @param definingModuleName the name of the module in which the instance is defined.
* @param methodName the name of the instance method.
*/
private void generateInstanceMethodReference(ClassInstanceIdentifier identifier, ModuleName definingModuleName, String methodName) {
ClassInstance classInstance = programModelManager.getModuleTypeInfo(definingModuleName).getClassInstance(identifier);
generateInstanceMethodReference(classInstance, methodName);
}
/**
* Returns a qualified name constructed from a <em>fully qualified</em> module name and an unqualified name.
* @param moduleName the name of the module.
* @param unqualifiedName the unqualified name of the entity.
* @return the fully qualified name as a string.
*/
private String getFullyQualifiedNameString(ModuleName moduleName, String unqualifiedName) {
return getQualifiedNameString(getFullyQualifiedNameForModule(moduleName), unqualifiedName);
}
/**
* Returns a qualified name constructed from a module name and an unqualified name.
* @param moduleNameString the name of the module.
* @param unqualifiedName the unqualified name of the entity.
* @return the qualified name as a string.
*/
private String getQualifiedNameString(String moduleNameString, String unqualifiedName) {
return moduleNameString + CALFragments.DOT + unqualifiedName;
}
/**
* Constructs an appropriately qualified version of the given entity name. For the purpose of documentation generation,
* all references to entities outside the current module are to be fully qualified. The exception is with Prelude
* names, which may optionally remain unqualified depending on the configuration of this generator.
*
* @param moduleName the name of the entity's module.
* @param unqualifiedName the unqualified name of the entity.
* @return an appropriately qualified version of the given name.
*/
private String getAppropriatelyQualifiedName(ModuleName moduleName, String unqualifiedName) {
return getAppropriatelyQualifiedName(moduleName, unqualifiedName, getMinimallyQualifiedNameForModule(moduleName));
}
/**
* Constructs an appropriately qualified version of the given entity name. For the purpose of documentation generation,
* all references to entities outside the current module are to be fully qualified. The exception is with Prelude
* names, which may optionally remain unqualified depending on the configuration of this generator.
*
* @param moduleName the name of the entity's module.
* @param unqualifiedName the unqualified name of the entity.
* @param moduleNameInSource how the module name portion of the reference appears in source. Could be the empty string if the reference is unqualified in source.
* @return an appropriately qualified version of the given name.
*/
private String getAppropriatelyQualifiedName(ModuleName moduleName, String unqualifiedName, String moduleNameInSource) {
if (moduleName == null || moduleName.equals(currentModuleName)) {
return unqualifiedName;
} else if (shouldDisplayPreludeNamesAsUnqualified() && moduleName.equals(CAL_Prelude.MODULE_NAME)) {
return unqualifiedName;
} else if (moduleNameInSource == null || moduleNameInSource.length() == 0) {
return unqualifiedName;
} else {
return getQualifiedNameString(moduleNameInSource, unqualifiedName);
}
}
/**
* Returns the minimally-qualified name for a module (with respect to the names of all the documented modules).
* @param moduleName the name of the module.
* @return the minimally-qualified form of the name.
*/
private String getMinimallyQualifiedNameForModule(ModuleName moduleName) {
return getModuleNameResolverForDocumentedModules().getMinimallyQualifiedModuleName(moduleName).toSourceText();
}
/**
* Returns the fully-qualified name for a module.
* @param moduleName the name of the module.
* @return the fully-qualified form of the name.
*/
private String getFullyQualifiedNameForModule(ModuleName moduleName) {
return moduleName.toSourceText();
}
/**
* Generates the full name of a type class (i.e. including its parent classes), appropriately hyperlinked if requested.
* @param typeClass the type class whose name is to be generated.
* @param shouldGenerateHyperlinks whether hyperlinks should be generated.
* @param styleClassForTypeClassName the style class to use for the type class name.
*/
private void generateTypeClassFullName(TypeClass typeClass, boolean shouldGenerateHyperlinks, StyleClass styleClassForTypeClassName) {
int nParentClasses = typeClass.getNParentClasses();
if (nParentClasses > 0) {
////
/// Loop through each parent class and generate its name, appropriately hyperlinked.
//
currentPage.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TYPE_CONSTRAINT)).addText(CALFragments.OPEN_PAREN);
for (int i = 0; i < nParentClasses; i++) {
if (i > 0) {
currentPage.addText(CALFragments.COMMA_AND_SPACE);
}
QualifiedName parentClassName = typeClass.getNthParentClass(i).getName();
if (shouldGenerateHyperlinks) {
generateTypeClassReference(parentClassName);
} else {
currentPage.addText(getAppropriatelyQualifiedName(parentClassName.getModuleName(), parentClassName.getUnqualifiedName()));
}
currentPage.addText(" " + CALFragments.STANDARD_TYPE_VAR);
}
currentPage.addText(CALFragments.CLOSE_PAREN).addText(" ").addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.CAL_SYMBOL), CALFragments.IMPLIES).closeTag(HTML.Tag.SPAN).addText(" ");
}
/// Finally generate the name of the type class itself.
//
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(styleClassForTypeClassName), typeClass.getName().getUnqualifiedName() + " " + CALFragments.STANDARD_TYPE_VAR);
}
/**
* Generates the declaration name for a class instance, appropriately hyperlinked if requested.
* @param classInstance the class instance whose name is to be generated.
* @param shouldGenerateHyperlinks whether hyperlinks should be generated.
*/
private void generateClassInstanceDeclarationName(ClassInstance classInstance, boolean shouldGenerateHyperlinks) {
TypeClass typeClass = classInstance.getTypeClass();
TypeExpr instanceType = classInstance.getType();
QualifiedName typeClassName = typeClass.getName();
SourceModel.TypeSignature typeSig = instanceType.toSourceModel(true, ScopedEntityNamingPolicy.FULLY_QUALIFIED);
SourceModel.TypeExprDefn typeExprDefn = typeSig.getTypeExprDefn();
TypeSignatureHTMLGenerator visitor = new TypeSignatureHTMLGenerator(shouldGenerateHyperlinks);
/// First generate the constraints from the instance type signature - they form the constraints on the instance.
//
visitor.generateConstraintsFromSignature(typeSig, null);
/// Then generate the instance type class name.
//
if (shouldGenerateHyperlinks) {
generateTypeClassReference(typeClassName);
} else {
currentPage.addText(getAppropriatelyQualifiedName(typeClassName.getModuleName(), typeClassName.getUnqualifiedName()));
}
currentPage.addText(" ");
/// Finally, generate the remaining type expression portion of the instance type, parenthesized as needed
// (e.g. 'Eq (Maybe a)' or 'Show (a -> b)', but simply 'Ord Int')
//
if (typeExprDefn instanceof SourceModel.TypeExprDefn.Application || typeExprDefn instanceof SourceModel.TypeExprDefn.Function) {
currentPage.addText(CALFragments.OPEN_PAREN);
typeExprDefn.accept(visitor, null);
currentPage.addText(CALFragments.CLOSE_PAREN);
} else {
typeExprDefn.accept(visitor, null);
}
}
/**
* Generates a reference to a local label with the given display name for the link.
* @param label the label for the reference. Must not be null.
* @param displayName the display name.
* @param tooltipText text for the tooltip. Can be null.
*/
private void generateLocalReference(String label, String displayName, String tooltipText) {
generateLocalReference(currentPage, label, displayName, tooltipText);
}
/**
* Generates a reference to a local label with the given display name for the link.
* @param builder the HTMLBuilder for generating the reference.
* @param label the label for the reference. Must not be null.
* @param displayName the display name.
* @param tooltipText text for the tooltip. Can be null.
*/
private void generateLocalReference(HTMLBuilder builder, String label, String displayName, String tooltipText) {
HTMLBuilder.AttributeList attribute = localHrefAttribute(label);
if (tooltipText != null) {
attribute = attribute.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TITLE, tooltipText));
}
builder.addTaggedText(HTML.Tag.A, attribute, displayName);
}
/**
* Generates a reference to another module, or to a label in another module, with the given display name for the link.
* @param builder the HTMLBuilder for generating the reference.
* @param relativeDirectory the relative directory path to get to the modules subdirectory. Can be null if the current directory is the modules subdirectory.
* @param moduleName the name of the other module.
* @param label the label for the reference. Can be null if the reference is simple to the module's page.
* @param displayName the display name.
* @param tooltipText text for the tooltip. Can be null.
*/
private void generateNonLocalReference(HTMLBuilder builder, String relativeDirectory, ModuleName moduleName, String label, String displayName, String tooltipText) {
String filePath;
if (inSeparateInstanceDoc) {
// fix up the relative directory if we are in separate instance documentation.. we are in the right module,
// but the wrong subdirectory
if (relativeDirectory == null) {
relativeDirectory = "../" + MODULES_SUBDIRECTORY;
}
}
if (relativeDirectory != null) {
filePath = relativeDirectory + "/" + getModuleFileName(moduleName);
} else {
filePath = getModuleFileName(moduleName);
}
HTMLBuilder.AttributeList attribute = nonLocalHrefAttribute(filePath, label);
if (tooltipText != null) {
attribute = attribute.concat(HTMLBuilder.AttributeList.make(HTML.Attribute.TITLE, tooltipText));
}
builder.addTaggedText(HTML.Tag.A, attribute, displayName);
}
/**
* Generates a reference to a CAL feature, appropriately hyperlinked.
* @param featureName the name of the CAL feature.
*/
private void generateCALFeatureReference(CALFeatureName featureName) {
FeatureName.FeatureType type = featureName.getType();
if (type == CALFeatureName.FUNCTION) {
generateFunctionOrClassMethodReference(QualifiedName.makeFromCompoundName(featureName.getName()));
} else if (type == CALFeatureName.TYPE_CONSTRUCTOR) {
generateTypeConsReference(QualifiedName.makeFromCompoundName(featureName.getName()));
} else if (type == CALFeatureName.TYPE_CLASS) {
generateTypeClassReference(QualifiedName.makeFromCompoundName(featureName.getName()));
} else if (type == CALFeatureName.DATA_CONSTRUCTOR) {
generateDataConsReference(QualifiedName.makeFromCompoundName(featureName.getName()));
} else if (type == CALFeatureName.CLASS_METHOD) {
generateFunctionOrClassMethodReference(QualifiedName.makeFromCompoundName(featureName.getName()));
} else if (type == CALFeatureName.MODULE) {
generateModuleReference(featureName.toModuleName());
} else if (type == CALFeatureName.CLASS_INSTANCE) {
ClassInstanceIdentifier identifier = featureName.toInstanceIdentifier();
ModuleName definingModuleName = featureName.toModuleName();
generateClassInstanceReference(identifier, definingModuleName);
} else if (type == CALFeatureName.INSTANCE_METHOD) {
ClassInstanceIdentifier identifier = featureName.toInstanceIdentifier();
ModuleName definingModuleName = featureName.toModuleName();
String methodName = featureName.toInstanceMethodName();
generateInstanceMethodReference(identifier, definingModuleName, methodName);
} else {
throw new IllegalArgumentException("feature type not supported: " + type);
}
}
/////====================================================================================================
////
/// Helpers for generating the details documentation for a functional agent
//
/**
* Generates the detailed documentation for a functional agent (function, class method, or data constructor).
* @param entity the FunctionalAgent of the functional agent.
* @param label the label to be used to label the generated documentation block.
* @param metadata the entity's metadata. Can be null if not available.
* @param docComment the entity's CALDoc comment. Can be null if not available.
* @param indexInList the position of the generated documentation in its enclosing list.
* @param shouldDisplayReturnBlock whether the return block should be displayed.
*/
private void generateFunctionalAgentDoc(FunctionalAgent entity, String label, FunctionalAgentMetadata metadata, CALDocComment docComment, int indexInList, boolean shouldDisplayReturnBlock) {
generateFunctionalAgentDoc(entity.getName().getUnqualifiedName(), entity, label, metadata, docComment, indexInList, shouldDisplayReturnBlock);
}
/**
* Generates the detailed documentation for a functional agent (function, class method, or data constructor).
* @param unqualifiedName the unqualified name for the functional agent.
* @param entity the FunctionalAgent of the functional agent.
* @param label the label to be used to label the generated documentation block.
* @param metadata the entity's metadata. Can be null if not available.
* @param docComment the entity's CALDoc comment. Can be null if not available.
* @param indexInList the position of the generated documentation in its enclosing list.
* @param shouldDisplayReturnBlock whether the return block should be displayed.
*/
/*
* @implementation this method is exposed via package scope to allow reuse by the CALDocToTooltipHTMLUtilities
*/
void generateFunctionalAgentDoc(String unqualifiedName, FunctionalAgent entity, String label, FunctionalAgentMetadata metadata, CALDocComment docComment, int indexInList, boolean shouldDisplayReturnBlock) {
Scope scope = entity.getScope();
TypeExpr typeExpr = entity.getTypeExpr();
ArgumentMetadata[] argMetadataArray = metadata.getArguments();
generateFunctionalAgentOrInstanceMethodDocHeading(scope, unqualifiedName, entity, typeExpr, label, argMetadataArray, docComment, indexInList, false);
generateFunctionalAgentOrInstanceMethodDocBody(scope, entity, typeExpr, metadata, argMetadataArray, docComment, docComment, docComment, shouldDisplayReturnBlock);
}
/**
* Generates the heading portion of the detailed documentation for a functional agent or an instance method.
* @param scope the scope of the documented functional agent. Can be null in the case of an instance method.
* @param unqualifiedName the unqualified name of the documented functional agent or instance method.
* @param entityWithArgumentNames the FunctionalAgent object from which argument names are to be extracted.
* @param typeExpr the type expression of the functional agent or instance method.
* @param label the label to be used to label the generated block.
* @param argMetadataArray the array of argument metadata containing argument names.
* @param docCommentForArguments the CALDoc comment potentially containing argument names.
* @param indexInList the position of the generated documentation in its enclosing list.
* @param isInstanceMethod whether the documentation is for an instance method.
*/
private void generateFunctionalAgentOrInstanceMethodDocHeading(Scope scope, String unqualifiedName, FunctionalAgent entityWithArgumentNames, TypeExpr typeExpr, String label, ArgumentMetadata[] argMetadataArray, CALDocComment docCommentForArguments, int indexInList, boolean isInstanceMethod) {
int nArgs = typeExpr.getArity();
////
/// Generate the name and type of the functional agent/instance method
//
currentPage
.openTag(HTML.Tag.DT, idAndClassAttributes(label, getDefinitionStartStyleClass(indexInList)))
.openTag(HTML.Tag.SPAN, classAttribute(getScopeStyleClass(scope)))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER_FIRST_LINE))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NAME_AND_TYPE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER), unqualifiedName);
generateTypeSignature(typeExpr.toSourceModel(true, ScopedEntityNamingPolicy.FULLY_QUALIFIED));
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.SPAN);
if (!isInstanceMethod) {
maybeGenerateClassMethodIndicator(entityWithArgumentNames);
}
currentPage
.openTag(HTML.Tag.CODE, classAttribute(StyleClassConstants.DECLARATION));
////
/// Generate the declaration containing the name and the arguments
//
if (scope != null) {
currentPage.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), scope.toString()).addText(" ");
}
currentPage
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DECLARED_NAME), unqualifiedName);
Set<String> setOfArgumentNames = new HashSet<String>();
for (int i = 0 ; i < nArgs; i++) {
currentPage.addText(" ");
ArgumentMetadata argMetadata = (i < argMetadataArray.length) ? argMetadataArray[i] : null;
generateArgumentName(entityWithArgumentNames, i, argMetadata, docCommentForArguments, setOfArgumentNames);
}
currentPage.closeTag(HTML.Tag.CODE);
currentPage.closeTag(HTML.Tag.SPAN).closeTag(HTML.Tag.DT);
}
/**
* Generates the body portion of the detailed documentation for a functional agent or an instance method.
* @param scope the scope of the documented functional agent. Can be null in the case of an instance method.
* @param entityWithArgumentNames the FunctionalAgent object from which argument names are to be extracted.
* @param typeExpr the type expression of the functional agent or instance method.
* @param metadata the metadata from which attributes and their values are to be extracted.
* @param argMetadataArray the array of argument metadata containing argument names.
* @param docComment the CALDoc comment from which documentation blocks are to be extracted.
* @param docCommentForArguments the CALDoc comment potentially containing argument names.
* @param docCommentForReturnValue the CALDoc comment from which the return value description is to be extracted.
* @param shouldDisplayReturnBlock whether the return block should be displayed.
*/
private void generateFunctionalAgentOrInstanceMethodDocBody(Scope scope, FunctionalAgent entityWithArgumentNames, TypeExpr typeExpr, CALFeatureMetadata metadata, ArgumentMetadata[] argMetadataArray, CALDocComment docComment, CALDocComment docCommentForArguments, CALDocComment docCommentForReturnValue, boolean shouldDisplayReturnBlock) {
int nArgs = typeExpr.getArity();
currentPage.openTag(HTML.Tag.DD, classAttribute(getScopeStyleClass(scope)));
////
/// First, generate the description
//
generateStandardDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
////
/// Then generate the arguments
//
if (nArgs > 0) {
currentPage
.openTag(HTML.Tag.DL)
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), LocalizableUserVisibleString.ARGUMENTS_COLON.toResourceString())
.openTag(HTML.Tag.DD);
}
TypeExpr[] typePieces = typeExpr.getTypePieces();
SourceModel.TypeSignature[] typePieceSignatures = TypeExpr.toSourceModelArray(typePieces, true, ScopedEntityNamingPolicy.FULLY_QUALIFIED);
Set<String> setOfArgumentNames = new HashSet<String>();
for (int i = 0; i < nArgs; i++) {
ArgumentMetadata argMetadata = (i < argMetadataArray.length) ? argMetadataArray[i] : null;
CALDocComment.TextBlock argTextBlock = (docCommentForArguments != null && i < docCommentForArguments.getNArgBlocks()) ? docCommentForArguments.getNthArgBlock(i).getTextBlock() : null;
String metadataValue = getBestDescriptionFromMetadata(argMetadata);
////
/// For each argument we independently determine whether to generate the metadata, the CALDoc, or both
/// depending on the configuration and the availability of argument metadata.
//
boolean genMetadata = (shouldGenerateFromMetadata() && metadataValue != null && metadataValue.length() > 0);
boolean genCALDoc = ((shouldAlwaysGenerateFromCALDoc() || !genMetadata) && argTextBlock != null);
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.ARG_BLOCK));
currentPage.openTag(HTML.Tag.DL).openTag(HTML.Tag.DT).openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NAME_AND_TYPE));
/// Generate the argument name and type signature
//
generateArgumentName(entityWithArgumentNames, i, argMetadata, docCommentForArguments, setOfArgumentNames);
generateTypeSignature(typePieceSignatures[i]);
currentPage.closeTag(HTML.Tag.SPAN).closeTag(HTML.Tag.DT).openTag(HTML.Tag.DD);
/// Generate the metadata, if required.
//
if (genMetadata) {
// trim the metadata of leading and trailing whitespace
metadataValue = metadataValue.trim();
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateMetadataIndicator();
currentPage.addText(metadataValue);
currentPage.closeTag(HTML.Tag.DIV);
}
/// Generate the CALDoc, if required.
//
if (genCALDoc) {
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateCALDocIndicator();
CALDocToHTMLUtilities.generateHTMLForCALDocTextBlock(argTextBlock, currentPage, inModulesSubdirectoryReferenceGenerator, StyleClassConstants.CODE_BLOCK, CODE_FORMATTING_TAG);
currentPage.closeTag(HTML.Tag.DIV);
}
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DIV);
}
if (nArgs > 0) {
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
////
/// Then generate the return value, if requested.
//
if (shouldDisplayReturnBlock) {
/// Generate the return value indicator and the return type
//
currentPage
.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.RETURN_BLOCK))
.openTag(HTML.Tag.DL)
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), LocalizableUserVisibleString.RETURNS_COLON.toResourceString())
.openTag(HTML.Tag.DD)
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.NAME_AND_TYPE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.RETURN_VALUE_INDICIATOR), LocalizableUserVisibleString.RETURN_VALUE_INDICATOR.toResourceString());
generateTypeSignature(typePieceSignatures[nArgs]);
currentPage.closeTag(HTML.Tag.SPAN).closeTag(HTML.Tag.DT).openTag(HTML.Tag.DD);
/// Generate the return value description
//
String metadataValue;
if (metadata instanceof FunctionMetadata) {
metadataValue = ((FunctionMetadata)metadata).getReturnValueDescription();
} else if (metadata instanceof ClassMethodMetadata) {
metadataValue = ((ClassMethodMetadata)metadata).getReturnValueDescription();
} else if (metadata instanceof InstanceMethodMetadata) {
metadataValue = ((InstanceMethodMetadata)metadata).getReturnValueDescription();
} else {
metadataValue = null;
}
CALDocComment.TextBlock returnBlock = (docCommentForReturnValue != null) ? docCommentForReturnValue.getReturnBlock() : null;
boolean genMetadata = (shouldGenerateFromMetadata() && metadataValue != null && metadataValue.length() > 0);
boolean genCALDoc = ((shouldAlwaysGenerateFromCALDoc() || !genMetadata) && returnBlock != null);
if (genMetadata) {
// trim the metadata of leading and trailing whitespace
metadataValue = metadataValue.trim();
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateMetadataIndicator();
currentPage.addText(metadataValue);
currentPage.closeTag(HTML.Tag.DIV);
}
if (genCALDoc) {
currentPage.openTag(HTML.Tag.DIV);
maybeGenerateCALDocIndicator();
CALDocToHTMLUtilities.generateHTMLForCALDocTextBlock(returnBlock, currentPage, inModulesSubdirectoryReferenceGenerator, StyleClassConstants.CODE_BLOCK, CODE_FORMATTING_TAG);
currentPage.closeTag(HTML.Tag.DIV);
}
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.DIV);
}
////
/// Finally, generate the supplementary blocks
//
generateStandardSupplementaryBlocks(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
currentPage.closeTag(HTML.Tag.DD).newline();
}
/**
* Returns the appropriate style class for the start of a definition section, depending on the position
* of the definition in its enclosing list.
* @param index the position of the definition in its enclosing list.
* @return the appropriate style class.
*/
private StyleClass getDefinitionStartStyleClass(int index) {
return (index == 0) ? StyleClassConstants.FIRST_DEFINITION_SECTION_START : StyleClassConstants.DEFINITION_SECTION_START;
}
/**
* Adds a name to a generic disambiguation map of the form
* <p>
* (lowercased name -> name -> disambiguated name).
*
* A disambiguation map works like this: Given a name (with mixed upper and
* lower case)
* <ol>
* <li>get the lowercase version of the name - names that conflict because
* of case-insensitivity would map to the same lowercased name.
*
* <li>using the lowercased name, get a map mapping the original names to
* disambiguated names.
*
* <li>if the map is empty, insert the pair (name, name) (the first-comer
* gets to keep its name without disambiguation).
*
* <li>if the map already has entries, the name needs to be mangled to
* create a disambiguated version. Then the pair (name, disambiguated name)
* is added to the map.
* </ol>
*
* For retrieval, simply repeat the same process as above, except instead of
* adding an entry to the inner map, the inner map is simply accessed to
* retrieve the mapping for the name.
*
* @param outerMap
* a Map<String, Map<String, String>> mapping lowercased name
* to a map mapping a name to its disambiguated name.
* @param name
* the name to add to the map.
*/
private void addNameToGenericDisambiguationMap(Map<String, Map<String, String>> outerMap, String name) {
/// Get the map from name to disambiguated name by keying the outerMap on the lowercase version of the name
//
String lowercaseName = name.toLowerCase(Locale.ENGLISH);
Map<String, String> nameToDisambiguatedNameMap = outerMap.get(lowercaseName);
boolean noPreviousEntriesWithSameLowercaseName = false;
if (nameToDisambiguatedNameMap == null) {
nameToDisambiguatedNameMap = new HashMap<String, String>();
outerMap.put(lowercaseName, nameToDisambiguatedNameMap);
noPreviousEntriesWithSameLowercaseName = true;
}
/// Add the name and its disambiguated form to the inner map.
//
String disambiguatedName = nameToDisambiguatedNameMap.get(name);
if (disambiguatedName == null) {
if (noPreviousEntriesWithSameLowercaseName) {
// the first entry gets to keep its own name
nameToDisambiguatedNameMap.put(name, name);
} else {
// the remaining entries have to use disambiguated names
String newlyDisambiguatedName = disambiguateName(name);
// make sure that the disambiguated name itself does not collide with other previously
// disambiguated names
while (nameToDisambiguatedNameMap.values().contains(newlyDisambiguatedName)) {
newlyDisambiguatedName += '-';
}
nameToDisambiguatedNameMap.put(name, newlyDisambiguatedName);
}
}
}
/**
* Adds a module name to the module name disambiguation map.
* @param moduleName the module name to be added.
*/
private void addModuleNameToDisambiguationMap(ModuleName moduleName) {
addNameToGenericDisambiguationMap(disambiguationMapForModuleNames, moduleName.toSourceText());
}
/**
* Adds a type constructor name to the type constructor name disambiguation map.
* @param moduleName the name of the type constructor's module.
* @param unqualifiedName the unqualified name of the type constructor.
*/
private void addTypeConsNameToDisambiguationMap(ModuleName moduleName, String unqualifiedName) {
Map<String, Map<String, String>> outerMap = disambiguationMapForTypeConsNames.get(moduleName);
if (outerMap == null) {
outerMap = new HashMap<String, Map<String, String>>();
disambiguationMapForTypeConsNames.put(moduleName, outerMap);
}
addNameToGenericDisambiguationMap(outerMap, unqualifiedName);
}
/**
* Adds a type class name to the type class name disambiguation map.
* @param moduleName the name of the type class's module.
* @param unqualifiedName the unqualified name of the type class.
*/
private void addTypeClassNameToDisambiguationMap(ModuleName moduleName, String unqualifiedName) {
Map<String, Map<String, String>> outerMap = disambiguationMapForTypeClassNames.get(moduleName);
if (outerMap == null) {
outerMap = new HashMap<String, Map<String, String>>();
disambiguationMapForTypeClassNames.put(moduleName, outerMap);
}
addNameToGenericDisambiguationMap(outerMap, unqualifiedName);
}
/**
* Constructs a disambiguated version of the given name, by prefixing each character in the range [A-Z] with a '-'.
* @param name the name to be whose disambiguated version is to be constructed.
* @return the disambiguated version of the name.
*/
private String disambiguateName(String name) {
return name.replaceAll("[A-Z]", "-$0");
}
/**
* Fetches an unambiguous version of the given name from a generic disambiguation map of the form (lowercased name -> name -> disambiguated name).
* @param disambiguationMap a Map<String, Map<String, String>> mapping lowercased name to a map mapping a name to its disambiguated name.
* @param name the name whose unambiguous version is requested.
* @return the unambiguous version of the given name.
*/
private String getDisambiguatedName(Map<String, Map<String, String>> disambiguationMap, String name) {
String lowercaseName = name.toLowerCase(Locale.ENGLISH);
Map<String, String> nameToDisambiguatedName = disambiguationMap.get(lowercaseName);
if (nameToDisambiguatedName == null) {
return name;
}
String disambiguatedName = nameToDisambiguatedName.get(name);
if (disambiguatedName == null) {
return name;
} else {
return disambiguatedName;
}
}
/**
* Fetches an unambiguous version of the given module name.
* @param moduleName the module name whose unambiguous version is requested.
* @return the unambiguous version of the given name.
*/
private String getDisambiguatedNameForModule(ModuleName moduleName) {
return getDisambiguatedName(disambiguationMapForModuleNames, moduleName.toSourceText());
}
/**
* Fetches an unambiguous version of the given type constructor name.
* @param moduleName the name of the type constructor's module.
* @param unqualifiedName the type constructor name whose unambiguous version is requested.
* @return the unambiguous version of the given name.
*/
private String getDisambiguatedNameForTypeCons(ModuleName moduleName, String unqualifiedName) {
Map<String, Map<String, String>> outerMap = disambiguationMapForTypeConsNames.get(moduleName);
if (outerMap == null) {
return unqualifiedName;
}
return getDisambiguatedName(outerMap, unqualifiedName);
}
/**
* Fetches an unambiguous version of the given type class name.
* @param moduleName the name of the type class's module.
* @param unqualifiedName the type class name whose unambiguous version is requested.
* @return the unambiguous version of the given name.
*/
private String getDisambiguatedNameForTypeClass(ModuleName moduleName, String unqualifiedName) {
Map<String, Map<String, String>> outerMap = disambiguationMapForTypeClassNames.get(moduleName);
if (outerMap == null) {
return unqualifiedName;
}
return getDisambiguatedName(outerMap, unqualifiedName);
}
/////====================================================================================================
////
/// Helpers for scope-related smarts
//
/**
* Returns the style class corresponding to the given CAL scope.
* @param scope the CAL scope. Can be null in the case of an instance method (which defaults to public).
* @return the corresponding style class.
*/
private StyleClass getScopeStyleClass(Scope scope) {
if (scope == null || scope == Scope.PUBLIC) {
return StyleClassConstants.PUBLIC_SCOPE;
} else if (scope == Scope.PROTECTED) {
return StyleClassConstants.PROTECTED_SCOPE;
} else if (scope == Scope.PRIVATE) {
return StyleClassConstants.PRIVATE_SCOPE;
} else {
throw new IllegalArgumentException();
}
}
/////====================================================================================================
////
/// Helpers for tooltips
//
/**
* Generates the header and entry heading for a module in a tooltip.
* @param moduleName the name of the module.
*/
void tooltip_generateModuleEntryHeader(final ModuleName moduleName) {
currentPage
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.MODULE.toResourceString())
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.DEFINITION_HEADER), moduleName.toSourceText());
}
/**
* Generates the header for a scoped entity in a tooltip.
* @param moduleName the module name to be displayed.
*/
void tooltip_generateScopedEntityHeader(final ModuleName moduleName) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), moduleName.toSourceText());
}
/**
* Generates the header for a data cons field name in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateDataConsFieldNameHeader(final IdentifierInfo.DataConsFieldName identifierInfo) {
if (identifierInfo.getAssociatedDataConstructors().size() > 1) {
currentPage
.openTag(HTML.Tag.DIV)
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.FIELD_OF_DATA_CONSTRUCTORS.toResourceString())
.closeTag(HTML.Tag.DT);
for (final IdentifierInfo.TopLevel.DataCons dataCons : identifierInfo.getAssociatedDataConstructors()) {
currentPage
.openTag(HTML.Tag.DD)
.addTaggedText(HTML.Tag.TT, dataCons.getResolvedName().toSourceText())
.closeTag(HTML.Tag.DD);
}
currentPage.closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DIV);
} else if (identifierInfo.getAssociatedDataConstructors().size() == 1) {
currentPage
.openTag(HTML.Tag.DIV)
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.FIELD_OF_DATA_CONSTRUCTOR_AND_SPACE.toResourceString())
.addTaggedText(HTML.Tag.TT, identifierInfo.getFirstAssociatedDataConstructor().getResolvedName().toSourceText())
.closeTag(HTML.Tag.DIV);
} else {
throw new IllegalArgumentException("must have at least one associated data constructor");
}
}
/**
* Generates the header for a local name in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateLocalNameHeader(final IdentifierInfo.Local identifierInfo) {
if (identifierInfo instanceof IdentifierInfo.Local.Function) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.LOCAL_FUNCTION.toResourceString());
} else if (identifierInfo instanceof IdentifierInfo.Local.PatternMatchVariable) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.LOCAL_PATTERN_MATCH_VARIABLE.toResourceString());
} else if (identifierInfo instanceof IdentifierInfo.Local.CasePatternVariable) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.CASE_PATTERN_VARIABLE.toResourceString());
} else if (identifierInfo instanceof IdentifierInfo.Local.Parameter.TopLevelFunctionOrClassMethod) {
final IdentifierInfo.Local.Parameter.TopLevelFunctionOrClassMethod info =
(IdentifierInfo.Local.Parameter.TopLevelFunctionOrClassMethod)identifierInfo;
currentPage
.openTag(HTML.Tag.DIV)
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.PARAMETER_OF_AND_SPACE.toResourceString())
.addTaggedText(HTML.Tag.TT, info.getAssociatedFunction().getResolvedName().toSourceText())
.closeTag(HTML.Tag.DIV);
} else if (identifierInfo instanceof IdentifierInfo.Local.Parameter.LocalFunction) {
final IdentifierInfo.Local.Parameter.LocalFunction info =
(IdentifierInfo.Local.Parameter.LocalFunction)identifierInfo;
currentPage
.openTag(HTML.Tag.DIV)
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.PARAMETER_OF_LOCAL_FUNCTION_AND_SPACE.toResourceString())
.addTaggedText(HTML.Tag.TT, info.getAssociatedFunction().getVarName())
.closeTag(HTML.Tag.DIV);
} else if (identifierInfo instanceof IdentifierInfo.Local.Parameter.Lambda) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.PARAMETER_OF_LAMBDA_EXPRESSION.toResourceString());
} else if (identifierInfo instanceof IdentifierInfo.Local.Parameter.InstanceMethodCALDoc) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.PARAMETER_OF_INSTANCE_METHOD.toResourceString());
} else {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.LOCAL_VARIABLE.toResourceString());
}
}
/**
* Generates the header and entry for a type variable in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateTypeVariableHeaderAndEntry(final IdentifierInfo.TypeVariable identifierInfo) {
currentPage
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.TYPE_VARIABLE.toResourceString())
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.DEFINITION_HEADER), identifierInfo.getTypeVarName());
}
/**
* Generates the header and entry for a record field name in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateRecordFieldNameHeaderAndEntry(final IdentifierInfo.RecordFieldName identifierInfo) {
currentPage
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.TOOLTIP_HEADER), LocalizableUserVisibleString.RECORD_FIELD_NAME.toResourceString())
.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.DEFINITION_HEADER), identifierInfo.getFieldName().getCalSourceForm());
}
/**
* Generates a horizontal separator in a tooltip.
*/
void tooltip_generateHorizontalRule() {
currentPage.emptyTag(HTML.Tag.HR);
}
/**
* Generates the entry for a local name (without associated documentation) in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateSimpleLocalNameEntry(final IdentifierInfo.Local identifierInfo) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.DEFINITION_HEADER), identifierInfo.getVarName());
}
/**
* Generates the entry for a data cons field name in a tooltip.
* @param identifierInfo the identifier info.
*/
void tooltip_generateDataConsFieldNameEntry(final IdentifierInfo.DataConsFieldName identifierInfo) {
currentPage.addTaggedText(HTML.Tag.DIV, classAttribute(StyleClassConstants.DEFINITION_HEADER), identifierInfo.getFieldName().getCalSourceForm());
}
/**
* Generates the start tag for a definition list in a tooltip.
*/
void tooltip_generateDefListOpen() {
currentPage.openTag(HTML.Tag.DL);
}
/**
* Generates the end tag for a definition list in a tooltip.
*/
void tooltip_generateDefListClose() {
currentPage.closeTag(HTML.Tag.DL);
}
/////====================================================================================================
////
/// Implementation of the abstract visitation methods in the superclass
//
/**
* {@inheritDoc}
*/
@Override
void prepareGenerationForModule(ModuleTypeInfo moduleTypeInfo) {
addModuleNameToDisambiguationMap(moduleTypeInfo.getModuleName());
}
/**
* {@inheritDoc}
*/
@Override
void beginDoc() {
////
/// Generate the CSS files and the main frameset.
//
generateTextFile(DEFAULT_CSS_FILENAME, getDefaultCSS());
generateTextFile(PRINTED_VERSION_CSS_FILENAME, getPrintedVersionCSS());
generateTextFile(MAIN_PAGE_FILENAME, getMainPageHTML());
}
/**
* {@inheritDoc}
*/
@Override
void endDoc() {
////
/// Now that all module and usage documentation has been generated, generate the module list, the overview page, and the master search page.
//
generateTextFile(MODULE_LIST_FILENAME, getModuleListPageHTML());
generateTextFile(OVERVIEW_PAGE_FILENAME, getOverviewPageHTML());
generateTextFile(MASTER_SCOPED_ENTITY_SEARCH_PAGE_FILENAME, getMasterScopedEntitySearchPageHTML());
}
/**
* {@inheritDoc}
*/
@Override
void beginModuleDoc(ModuleTypeInfo moduleTypeInfo, int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances) {
/// Start a new page
//
startNewCurrentPageWithModule(moduleTypeInfo.getModuleName());
/// Generate the head section
//
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = "../"; // all module docs are in a subdirectory of the base directory
String pageTitle = makePageTitle(getFullyQualifiedNameForModule(currentModuleName));
generateHeadSection(pageTitle, relativePathToBaseDirectory, null, null);
/// Start the body section with a javascript which changes the navigation index in the nav frame,
/// and which changes the window title (needed if inside a frame).
//
currentPage
.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "showNavChangeTitle()")))
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"function showNavChangeTitle() {\n" +
" if (parent.frames != undefined && parent.frames[1] != undefined && parent.frames[1].location != undefined) {\n" +
" var urlPieces = new String(parent.frames[1].location).split('/');\n" +
" var filePortion = urlPieces[urlPieces.length - 1];\n" +
" if (filePortion.indexOf('" + getPerModuleIndexFileNamePrefix(currentModuleName) + "') != 0) {\n" +
" parent.frames[1].location.replace('" + relativePathToBaseDirectory + NAV_SUBDIRECTORY + "/" + getPerModuleFunctionalAgentIndexFileName(currentModuleName) + "');\n" +
" }\n" +
" }\n" +
" parent.document.title='" + pageTitle + "';\n" +
"}\n" +
"\n" +
"showNavChangeTitle(); // run it immediately\n");
generateUpdateScopeDisplaySettingsJavascript();
/// Cache the statistics of this module
//
nTypeConstructorsInModule = nTypeConstructors;
nFunctionsInModule = nFunctions;
nTypeClassesInModule = nTypeClasses;
nClassInstancesInModule = nClassInstances;
/// Generate the navigation bar
//
generateModulePageNavBar(false, nTypeConstructors, nFunctions, nTypeClasses, nClassInstances);
/// Wrap the main content with a div tag
//
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
/// Generate the heading of the page using the module name
//
currentPage.addTaggedText(HTML.Tag.H1, getFullyQualifiedNameForModule(currentModuleName));
}
/**
* {@inheritDoc}
*/
@Override
void endModuleDoc(int nTypeConstructors, int nFunctions, int nTypeClasses, int nClassInstances) {
/// Close the main content div tag
//
currentPage.closeTag(HTML.Tag.DIV);
/// Generate the navigation bar and the fine print
//
generateModulePageNavBar(true, nTypeConstructors, nFunctions, nTypeClasses, nClassInstances);
generatePageBottom();
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
/// Write the completed module documentation out.
//
generateTextFile(MODULES_SUBDIRECTORY, getModuleFileName(currentModuleName), getHTMLFileContentsWithDocTypeForMainFramePage(currentPage));
////
/// Generate the four per-module indices: types, functional agents, type classes and instances
//
String typeIndexFileName = getPerModuleTypeIndexFileName(currentModuleName);
generateTextFile(NAV_SUBDIRECTORY, typeIndexFileName, getTypeIndexPageHTML(typeIndexFileName));
String functionalAgentIndexFileName = getPerModuleFunctionalAgentIndexFileName(currentModuleName);
generateTextFile(NAV_SUBDIRECTORY, functionalAgentIndexFileName, getFunctionalAgentIndexPageHTML(functionalAgentIndexFileName));
String typeClassIndexFileName = getPerModuleTypeClassIndexFileName(currentModuleName);
generateTextFile(NAV_SUBDIRECTORY, typeClassIndexFileName, getTypeClassIndexPageHTML(typeClassIndexFileName));
String instanceIndexFileName = getPerModuleInstanceIndexFileName(currentModuleName);
generateTextFile(NAV_SUBDIRECTORY, instanceIndexFileName, getInstanceIndexPageHTML(instanceIndexFileName));
}
/**
* {@inheritDoc}
*/
@Override
void beginImportedModulesList(int nImportedModules) {
importedModules = new HashSet<ModuleName>();
}
/**
* {@inheritDoc}
*/
@Override
void generateImportedModule(ModuleTypeInfo moduleTypeInfo, int index, int nImportedModules) {
importedModules.add(moduleTypeInfo.getModuleName());
}
/**
* {@inheritDoc}
*/
@Override
void endImportedModulesList(int nImportedModules) {
generateRelatedModulesList(LocalizableUserVisibleString.IMPORTED_MODULES_COLON.toResourceString(), importedModules);
}
/**
* {@inheritDoc}
*/
@Override
void beginFriendModulesList(int nFriendModules) {
friendModules = new HashSet<ModuleName>();
}
/**
* {@inheritDoc}
*/
@Override
void generateFriendModule(ModuleName moduleName, int index, int nFriendModules) {
friendModules.add(moduleName);
}
/**
* {@inheritDoc}
*/
@Override
void endFriendModulesList(int nFriendModules) {
generateRelatedModulesList(LocalizableUserVisibleString.FRIEND_MODULES_COLON.toResourceString(), friendModules);
}
/**
* {@inheritDoc}
*/
@Override
void beginDirectlyDependentModulesList(int nDependentModules) {
directlyDependentModules = new HashSet<ModuleName>();
}
/**
* {@inheritDoc}
*/
@Override
void generateDirectlyDependentModule(ModuleName moduleName, int index, int nDependentModules) {
directlyDependentModules.add(moduleName);
}
/**
* {@inheritDoc}
*/
@Override
void endDirectlyDependentModulesList(int nDependentModules) {
generateRelatedModulesList(LocalizableUserVisibleString.DIRECTLY_DEPENDENT_MODULES_COLON.toResourceString(), directlyDependentModules);
}
/**
* {@inheritDoc}
*/
@Override
void beginIndirectlyDependentModulesList(int nDependentModules) {
indirectlyDependentModules = new HashSet<ModuleName>();
}
/**
* {@inheritDoc}
*/
@Override
void generateIndirectlyDependentModule(ModuleName moduleName, int index, int nDependentModules) {
indirectlyDependentModules.add(moduleName);
}
/**
* {@inheritDoc}
*/
@Override
void endIndirectlyDependentModulesList(int nDependentModules) {
generateRelatedModulesList(LocalizableUserVisibleString.INDIRECTLY_DEPENDENT_MODULES_COLON.toResourceString(), indirectlyDependentModules);
}
/**
* {@inheritDoc}
*/
@Override
void generateModuleDescription(ModuleTypeInfo moduleTypeInfo) {
ModuleName moduleName = moduleTypeInfo.getModuleName();
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getModuleFeatureName(moduleName), getLocale());
CALDocComment docComment = moduleTypeInfo.getCALDocComment();
/// For a module, just generate its description and supplementary blocks
//
generateStandardDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
generateStandardSupplementaryBlocks(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginModuleOverviewSection(boolean isOverviewSectionEmpty) {
/// Generate a heading for the module overview section only if the section is non-empty
//
if (!isOverviewSectionEmpty) {
currentPage.addTaggedText(HTML.Tag.H2, idAndClassAttributes(ElementID.SUMMARY_SECTION, StyleClassConstants.MAJOR_SECTION), LocalizableUserVisibleString.MODULE_SUMMARY.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void endModuleOverviewSection(boolean isOverviewSectionEmpty) {
// nothing to do
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeConsOverviewSection(int nTypeConstructors, Scope maxScopeOfTypeConstructors) {
/// Generate the start for the types overview section only if the section is non-empty
//
if (nTypeConstructors > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfTypeConstructors)));
beginOverviewTable(LocalizableUserVisibleString.TYPES.toResourceString(), false);
}
}
/**
* {@inheritDoc}
*/
@Override
void endTypeConsOverviewSection(int nTypeConstructors) {
/// Generate the end for the types overview section only if the section is non-empty
//
if (nTypeConstructors > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginFunctionsOverviewSection(int nFunctions, Scope maxScopeOfFunctions) {
/// Generate the start for the functions overview section only if the section is non-empty
//
if (nFunctions > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfFunctions)));
beginOverviewTable(LocalizableUserVisibleString.FUNCTIONS.toResourceString(), false);
}
}
/**
* {@inheritDoc}
*/
@Override
void endFunctionsOverviewSection(int nFunctions) {
/// Generate the end for the functions overview section only if the section is non-empty
//
if (nFunctions > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeClassOverviewSection(int nTypeClasses, Scope maxScopeOfTypeClasses) {
/// Generate the start for the type class overview section only if the section is non-empty
//
if (nTypeClasses > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfTypeClasses)));
beginOverviewTable(LocalizableUserVisibleString.TYPE_CLASSES.toResourceString(), false);
}
}
/**
* {@inheritDoc}
*/
@Override
void endTypeClassOverviewSection(int nTypeClasses) {
/// Generate the end for the type class overview section only if the section is non-empty
//
if (nTypeClasses > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginClassInstancesOverviewSection(int nClassInstances, Scope maxScopeOfClassInstances) {
/// Generate the start for the class instance overview section only if the section is non-empty
//
if (nClassInstances > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfClassInstances)));
beginOverviewTable(LocalizableUserVisibleString.INSTANCES.toResourceString(), false);
}
}
/**
* {@inheritDoc}
*/
@Override
void endClassInstancesOverviewSection(int nClassInstances) {
/// Generate the end for the class instance overview section only if the section is non-empty
//
if (nClassInstances > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeConsOverviewHeader(TypeConstructor typeConstructor) {
///
// First, add the type constructor's name to the disambiguation map.
// By the time the details section is generated, all the colliding type constructors
// would have had their overview generated and thus the disambiguation map properly
// populated and ready to serve out disambiguated names.
//
addTypeConsNameToDisambiguationMap(typeConstructor.getName().getModuleName(), typeConstructor.getName().getUnqualifiedName());
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeConstructorFeatureName(typeConstructor.getName()), getLocale());
CALDocComment docComment = typeConstructor.getCALDocComment();
/// Generate the scope and name of the type constructor
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(typeConstructor.getScope())))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeConstructor.getScope().toString())
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
generateTypeConsReference(typeConstructor.getName());
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION));
/// Then generate the short description for the entry
//
generateShortDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginDataConsOverviewList(int nDataConstructors, Scope maxScopeOfDataConstructors) {
/// Generate the start for the data constructor overview list only if the list is non-empty
//
if (nDataConstructors > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfDataConstructors)));
beginOverviewTable(null, true);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateDataConsOverview(DataConstructor dataConstructor) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getDataConstructorFeatureName(dataConstructor.getName()), getLocale());
CALDocComment docComment = dataConstructor.getCALDocComment();
// We delegate the generation to the helper that handles all function agents
generateFunctionalAgentOverview(dataConstructor, labelMaker.getLabel(dataConstructor), metadata, docComment, StyleClassConstants.OVERVIEW_TABLE_NESTED_DESCRIPTION);
}
/**
* {@inheritDoc}
*/
@Override
void endDataConsOverviewList(int nDataConstructors) {
/// Generate the end for the data constructor overview list only if the list is non-empty
//
if (nDataConstructors > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeConsOverviewFooter() {
// Just close off the table row
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
/**
* {@inheritDoc}
*/
@Override
void generateFunctionOverview(Function function) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getFunctionFeatureName(function.getName()), getLocale());
CALDocComment docComment = function.getCALDocComment();
// We delegate the generation to the helper that handles all function agents
generateFunctionalAgentOverview(function, labelMaker.getLabel(function), metadata, docComment, StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION);
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeClassOverviewHeader(TypeClass typeClass) {
///
// First, add the type class's name to the disambiguation map.
// By the time the details section is generated, all the colliding type classes
// would have had their overview generated and thus the disambiguation map properly
// populated and ready to serve out disambiguated names.
//
addTypeClassNameToDisambiguationMap(typeClass.getName().getModuleName(), typeClass.getName().getUnqualifiedName());
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeClassFeatureName(typeClass.getName()), getLocale());
CALDocComment docComment = typeClass.getCALDocComment();
/// Generate the scope and name of the type class
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(typeClass.getScope())))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeClass.getScope().toString())
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
generateTypeClassReference(typeClass.getName());
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION));
/// Then generate the short description for the entry
//
generateShortDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginClassMethodOverviewList(int nClassMethods) {
/// Generate the start for the class method overview list only if the list is non-empty
//
if (nClassMethods > 0) {
beginOverviewTable(null, true);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateClassMethodOverview(ClassMethod classMethod) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getClassMethodFeatureName(classMethod.getName()), getLocale());
CALDocComment docComment = classMethod.getCALDocComment();
// We delegate the generation to the helper that handles all function agents
generateFunctionalAgentOverview(classMethod, labelMaker.getLabel(classMethod), metadata, docComment, StyleClassConstants.OVERVIEW_TABLE_NESTED_DESCRIPTION);
}
/**
* {@inheritDoc}
*/
@Override
void endClassMethodOverviewList(int nClassMethods) {
/// Generate the end for the class method overview list only if the list is non-empty
//
if (nClassMethods > 0) {
endOverviewTable();
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeClassOverviewFooter() {
// Just close off the table row
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
/**
* {@inheritDoc}
*/
@Override
void generateClassInstanceOverviewHeader(ClassInstance classInstance) {
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getClassInstanceFeatureName(classInstance), getLocale());
CALDocComment docComment = classInstance.getCALDocComment();
/// Generate the name of the class instance
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(minScopeForInstanceClassAndInstanceType(classInstance))))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
generateClassInstanceReference(classInstance);
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION));
/// Then generate the short description for the entry
//
generateShortDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginInstanceMethodOverviewList(int nInstanceMethods) {
// nothing to do - we omit the instance method listing in the overview
}
/**
* {@inheritDoc}
*/
@Override
void generateInstanceMethodOverview(ClassInstance classInstance, String methodName) {
// nothing to do - we omit the instance method listing in the overview
}
/**
* {@inheritDoc}
*/
@Override
void endInstanceMethodOverviewList(int nInstanceMethods) {
// nothing to do - we omit the instance method listing in the overview
}
/**
* {@inheritDoc}
*/
@Override
void generateClassInstanceOverviewFooter() {
// Just close off the table row
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeConsDocSection(int nTypeConstructors, Scope maxScopeOfTypeConstructors) {
/// Generate a major section heading only if there are type constructors to be documented
//
if (nTypeConstructors > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfTypeConstructors)))
.addTaggedText(HTML.Tag.H2, idAndClassAttributes(ElementID.TYPES_SECTION, StyleClassConstants.MAJOR_SECTION), LocalizableUserVisibleString.TYPES.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeConsDocHeader(TypeConstructor typeConstructor, int index) {
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeConstructorFeatureName(typeConstructor.getName()), getLocale());
CALDocComment docComment = typeConstructor.getCALDocComment();
/// Generate the name of the type constructor as the header, followed by a link to the usages if necessary
//
String unqualifiedName = typeConstructor.getName().getUnqualifiedName();
currentPage
.openTag(HTML.Tag.DL, classAttribute(getScopeStyleClass(typeConstructor.getScope())))
.openTag(HTML.Tag.DT, idAndClassAttributes(labelMaker.getLabel(typeConstructor), getDefinitionStartStyleClass(index)))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER_FIRST_LINE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER), unqualifiedName);
maybeGenerateUsageLink(TYPE_CONS_USAGE_SUBDIRECTORY, getTypeConsUsageIndexFileName(typeConstructor.getName()));
/// Generate the declaration for the type constructor including its scope
//
currentPage
.closeTag(HTML.Tag.SPAN)
.openTag(HTML.Tag.CODE, classAttribute(StyleClassConstants.DECLARATION))
.addText(CALFragments.DATA)
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeConstructor.getScope().toString())
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DECLARED_NAME), unqualifiedName)
.closeTag(HTML.Tag.CODE)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD);
/// Then generate its description, implementation info (if any), and supplementary blocks
//
generateStandardDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
generateForeignTypeInfo(typeConstructor);
generateStandardSupplementaryBlocks(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* Generate implementation info for foreign type (if the implementation type is visible).
* @param typeConstructor the type constructor, which may or may not correspond to a foreign type.
*/
private void generateForeignTypeInfo(TypeConstructor typeConstructor) {
ForeignTypeInfo foreignTypeInfo = typeConstructor.getForeignTypeInfo();
if (foreignTypeInfo != null) {
Scope implScope = foreignTypeInfo.getImplementationVisibility();
if (filter.shouldAcceptBasedOnScopeOnly(implScope)) {
try {
String className = JavaTypeName.getFullJavaSourceName(foreignTypeInfo.getForeignType());
currentPage
.openTag(HTML.Tag.DL, classAttribute(getScopeStyleClass(implScope)))
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), LocalizableUserVisibleString.IMPLEMENTATION_VISIBILITY_COLON.toResourceString())
.addTaggedText(HTML.Tag.DD, implScope.toString())
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.ATTRIBUTE_HEADER), LocalizableUserVisibleString.FOREIGN_TYPE_COLON.toResourceString())
.addTaggedText(HTML.Tag.DD, className)
.closeTag(HTML.Tag.DL);
} catch (UnableToResolveForeignEntityException e) {
logger.severe(CALDocMessages.getString("STATUS.cannotResolveForeignTypeInfo", e.getCompilerMessage().toString()));
}
}
}
}
/**
* {@inheritDoc}
*/
@Override
void beginDataConsDocList(int nDataConstructors, Scope maxScopeOfDataConstructors) {
/// Generate the start for the data constructor list only if the list is non-empty
//
if (nDataConstructors > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfDataConstructors)))
.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.DATA_CONSTRUCTOR_LIST))
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.DATA_CONSTRUCTOR_LIST_HEADER), LocalizableUserVisibleString.DATA_CONSTRUCTORS.toResourceString())
.openTag(HTML.Tag.DD)
.openTag(HTML.Tag.DL);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateDataConsDoc(DataConstructor dataConstructor, int index) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getDataConstructorFeatureName(dataConstructor.getName()), getLocale());
CALDocComment docComment = dataConstructor.getCALDocComment();
// We delegate the generation to the helper that handles all function agents
generateFunctionalAgentDoc(dataConstructor, labelMaker.getLabel(dataConstructor), metadata, docComment, index, false);
}
/**
* {@inheritDoc}
*/
@Override
void endDataConsDocList(int nDataConstructors) {
/// Generate the end for the data constructor list only if the list is non-empty
//
if (nDataConstructors > 0) {
currentPage.closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeConsDocFooter(TypeConstructor typeConstructor, int index) {
// Just close the definition list
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
/**
* {@inheritDoc}
*/
@Override
void endTypeConsDocSection(int nTypeConstructors) {
if (nTypeConstructors > 0) {
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginFunctionsDocSection(int nFunctions, Scope maxScopeOfFunctions) {
/// Generate a major section heading only if there are functions to be documented
//
if (nFunctions > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfFunctions)))
.addTaggedText(HTML.Tag.H2, idAndClassAttributes(ElementID.FUNCTIONS_SECTION, StyleClassConstants.MAJOR_SECTION), LocalizableUserVisibleString.FUNCTIONS.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void generateFunctionDoc(Function function, int index) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getFunctionFeatureName(function.getName()), getLocale());
CALDocComment docComment = function.getCALDocComment();
// We delegate the generation to the helper that handles all function agents.
// The helper expects to work in the context of a definition list, so we create one.
currentPage.openTag(HTML.Tag.DL, classAttribute(getScopeStyleClass(function.getScope())));
generateFunctionalAgentDoc(function, labelMaker.getLabel(function), metadata, docComment, index, true);
currentPage.closeTag(HTML.Tag.DL);
}
/**
* {@inheritDoc}
*/
@Override
void endFunctionsDocSection(int nFunctions) {
if (nFunctions > 0) {
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeClassesDocSection(int nTypeClasses, Scope maxScopeOfTypeClasses) {
/// Generate a major section heading only if there are type classes to be documented
//
if (nTypeClasses > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfTypeClasses)))
.addTaggedText(HTML.Tag.H2, idAndClassAttributes(ElementID.TYPE_CLASSES_SECTION, StyleClassConstants.MAJOR_SECTION), LocalizableUserVisibleString.TYPE_CLASSES.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeClassDocHeader(TypeClass typeClass, int index) {
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeClassFeatureName(typeClass.getName()), getLocale());
CALDocComment docComment = typeClass.getCALDocComment();
/// Generate the name of the type class as the header, followed by a link to the usages if necessary
//
String unqualifiedName = typeClass.getName().getUnqualifiedName();
currentPage
.openTag(HTML.Tag.DL, classAttribute(getScopeStyleClass(typeClass.getScope())))
.openTag(HTML.Tag.DT, idAndClassAttributes(labelMaker.getLabel(typeClass), getDefinitionStartStyleClass(index)))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER_FIRST_LINE))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER), unqualifiedName);
maybeGenerateUsageLink(TYPE_CLASS_USAGE_SUBDIRECTORY, getTypeClassUsageIndexFileName(typeClass.getName()));
/// Generate the full name for the type c
//
currentPage
.closeTag(HTML.Tag.SPAN)
.openTag(HTML.Tag.CODE, classAttribute(StyleClassConstants.DECLARATION))
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeClass.getScope().toString())
.addText(" ")
.addText(CALFragments.CLASS)
.addText(" ");
generateTypeClassFullName(typeClass, true, StyleClassConstants.DECLARED_NAME);
currentPage
.closeTag(HTML.Tag.CODE)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD);
/// Then generate its description and supplementary blocks
//
generateStandardDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
generateStandardSupplementaryBlocks(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginClassMethodDocList(int nClassMethods) {
/// Generate the start for the class method list only if the list is non-empty
//
if (nClassMethods > 0) {
currentPage
.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.CLASS_METHOD_LIST))
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.CLASS_METHOD_LIST_HEADER), LocalizableUserVisibleString.CLASS_METHODS.toResourceString())
.openTag(HTML.Tag.DD)
.openTag(HTML.Tag.DL);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateClassMethodDoc(ClassMethod classMethod, int index) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(CALFeatureName.getClassMethodFeatureName(classMethod.getName()), getLocale());
CALDocComment docComment = classMethod.getCALDocComment();
// We delegate the generation to the helper that handles all function agents
generateFunctionalAgentDoc(classMethod, labelMaker.getLabel(classMethod), metadata, docComment, index, true);
}
/**
* {@inheritDoc}
*/
@Override
void endClassMethodDocList(int nClassMethods) {
/// Generate the start for the class method list only if the list is non-empty
//
if (nClassMethods > 0) {
currentPage.closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
}
/**
* {@inheritDoc}
*/
@Override
void beginKnownInstancesList(int nKnownInstances, Scope maxScopeOfKnownInstances) {
/// Generate the start for the known instances list only if the list is non-empty
//
if (nKnownInstances > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfKnownInstances)))
.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.KNOWN_INSTANCE_LIST))
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.KNOWN_INSTANCE_LIST_HEADER), LocalizableUserVisibleString.KNOWN_INSTANCES.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void generateKnownInstance(ClassInstance classInstance, int index) {
/// For a known instance we generate a reference to the instance in its own item in the definition list
//
currentPage.openTag(HTML.Tag.DD, classAttribute(getScopeStyleClass(minScopeForInstanceClassAndInstanceType(classInstance))));
generateClassInstanceReference(classInstance);
currentPage.closeTag(HTML.Tag.DD);
}
/**
* {@inheritDoc}
*/
@Override
void endKnownInstancesList(int nKnownInstances) {
/// Generate the end for the known instances list only if the list is non-empty
//
if (nKnownInstances > 0) {
currentPage.closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateTypeClassDocFooter(TypeClass typeClass, int index) {
// Just close the definition list
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
/**
* {@inheritDoc}
*/
@Override
void endTypeClassesDocSection(int nTypeClasses) {
if (nTypeClasses > 0) {
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* Overrides the implementation in the superclass to obtain the name of a class instance,
* appropriately qualified according to the configuration options.
*
* @param classInstance the class instance.
* @return the display name for the class instance.
*/
@Override
String getClassInstanceDisplayName(ClassInstance classInstance) {
// Temporarily swap out the current HTML builder with a new one,
// and use it to generate a class instance name (with no hyperlinks).
// Then swap the original builder back in, and return the text in the new builder, trimmed.
HTMLBuilder origCurrentPage = currentPage;
try {
startNewCurrentPage();
generateClassInstanceDeclarationName(classInstance, false);
return currentPage.toHTML().trim();
} finally {
currentPage = origCurrentPage;
}
}
/**
* {@inheritDoc}
*/
@Override
void beginClassInstancesDocSection(int nClassInstances, ClassInstance[] classInstances, Scope maxScopeOfClassInstances) {
if (config.shouldSeparateInstanceDoc) {
/// Switch the current page to a separate instance documentation page
//
mainPageContext = currentPage;
inSeparateInstanceDoc = true;
startNewCurrentPage();
String pageName = LocalizableUserVisibleString.INSTANCE_DOC_TITLE.toResourceString(getFullyQualifiedNameForModule(currentModuleName));
/// Generate the head section
//
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = "../"; // all instance docs are in a subdirectory of the base directory
String pageTitle = makePageTitle(pageName);
generateHeadSection(pageTitle, relativePathToBaseDirectory, null, null);
/// Start the body section with a javascript which changes the navigation index in the nav frame,
/// and which changes the window title (needed if inside a frame).
//
currentPage
.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "showNavChangeTitle()")))
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"),
"\n" +
"function showNavChangeTitle() {\n" +
" if (parent.frames != undefined && parent.frames[1] != undefined && parent.frames[1].location != undefined) {\n" +
" var urlPieces = new String(parent.frames[1].location).split('/');\n" +
" var filePortion = urlPieces[urlPieces.length - 1];\n" +
" if (filePortion.indexOf('" + getPerModuleIndexFileNamePrefix(currentModuleName) + "') != 0) {\n" +
" parent.frames[1].location.replace('" + relativePathToBaseDirectory + NAV_SUBDIRECTORY + "/" + getPerModuleInstanceIndexFileName(currentModuleName) + "');\n" +
" }\n" +
" }\n" +
" parent.document.title='" + pageTitle + "';\n" +
"}\n" +
"\n" +
"showNavChangeTitle(); // run it immediately\n");
generateUpdateScopeDisplaySettingsJavascript();
/// Generate the navigation bar
//
generateModulePageNavBar(false, relativePathToBaseDirectory, nTypeConstructorsInModule, nFunctionsInModule, nTypeClassesInModule, nClassInstancesInModule);
/// Wrap the main content with a div tag
//
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
/// Generate the heading of the page using the qualified name
//
currentPage.addTaggedText(HTML.Tag.H1, pageName);
/// Generate a dedicated overview section
//
boolean isOverviewSectionEmpty = (nClassInstances == 0);
beginModuleOverviewSection(isOverviewSectionEmpty);
beginClassInstancesOverviewSection(nClassInstances, maxScopeOfClassInstances);
for (int i = 0; i < nClassInstances; i++) {
generateClassInstanceOverview(classInstances[i]);
}
endClassInstancesOverviewSection(nClassInstances);
endModuleOverviewSection(isOverviewSectionEmpty);
}
/// Generate a major section heading only if there are class instances to be documented
//
if (nClassInstances > 0) {
currentPage
.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfClassInstances)))
.addTaggedText(HTML.Tag.H2, idAndClassAttributes(ElementID.INSTANCES_SECTION, StyleClassConstants.MAJOR_SECTION), LocalizableUserVisibleString.INSTANCES.toResourceString());
}
}
/**
* {@inheritDoc}
*/
@Override
void generateClassInstanceDocHeader(ClassInstance classInstance, int index) {
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getClassInstanceFeatureName(classInstance), getLocale());
CALDocComment docComment = classInstance.getCALDocComment();
/// Generate the name of the class instance as the header, followed by a link to the usages if necessary
//
currentPage
.openTag(HTML.Tag.DL, classAttribute(getScopeStyleClass(minScopeForInstanceClassAndInstanceType(classInstance))))
.openTag(HTML.Tag.DT, idAndClassAttributes(labelMaker.getLabel(classInstance), getDefinitionStartStyleClass(index)))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER_FIRST_LINE))
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DEFINITION_HEADER));
generateClassInstanceDeclarationName(classInstance, false);
/// Generate the declaration for the class instance, with its contents appropriately hyperlinked
//
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.SPAN)
.openTag(HTML.Tag.CODE, classAttribute(StyleClassConstants.DECLARATION))
.addText("instance ")
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DECLARED_NAME));
generateClassInstanceDeclarationName(classInstance, true);
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.CODE)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD);
/// Then generate its description and supplementary blocks
//
generateStandardDescription(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
generateStandardSupplementaryBlocks(metadata, docComment, inModulesSubdirectoryReferenceGenerator);
}
/**
* {@inheritDoc}
*/
@Override
void beginInstanceMethodDocList(int nInstanceMethods) {
/// Generate the start for the instance method list only if the list is non-empty
//
if (nInstanceMethods > 0) {
currentPage
.openTag(HTML.Tag.DL, classAttribute(StyleClassConstants.INSTANCE_METHOD_LIST))
.addTaggedText(HTML.Tag.DT, classAttribute(StyleClassConstants.INSTANCE_METHOD_LIST_HEADER), LocalizableUserVisibleString.INSTANCE_METHODS.toResourceString())
.openTag(HTML.Tag.DD)
.openTag(HTML.Tag.DL);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateInstanceMethodDoc(ClassInstance classInstance, String methodName, ClassMethod classMethod, int index) {
InstanceMethodMetadata metadata = (InstanceMethodMetadata)getMetadata(CALFeatureName.getInstanceMethodFeatureName(classInstance, methodName), getLocale());
CALDocComment docComment = classInstance.getMethodCALDocComment(methodName);
////
/// With an instance method, we attempt to figure out which CALDoc comment to refer to for documentation.
/// Often it is the case that the instance method, or even the class instance, would be undocumented. In such situations,
/// it would be beneficial to present the documentation on the class method, since after all it is a class method that
/// ultimately ends up being used in expressions, not the instance method backing it.
//
Scope scope = null;
String unqualifiedName = methodName;
FunctionalAgent entityWithArgumentNames = classMethod;
CALDocComment classMethodCALDocComment = classMethod.getCALDocComment();
TypeExpr typeExpr = classInstance.getInstanceMethodType(methodName);
ArgumentMetadata[] argMetadataArray = metadata.getArguments();
String label = labelMaker.getLabel(classInstance, methodName);
/// If there are no @arg blocks for the instance method's CALDoc comment, or there is no CALDoc comment for the method at
/// all, use the CALDoc comment for the class method
//
final CALDocComment docCommentForArguments;
if (docComment != null && docComment.getNArgBlocks() > 0) {
docCommentForArguments = docComment;
} else {
docCommentForArguments = classMethodCALDocComment;
}
/// If there is no @return block for the instance method's CALDoc comment, or there is no CALDoc comment for the method at
/// all, use the CALDoc comment for the class method - but only if the class method's arity matches the instance method's arity.
//
final CALDocComment docCommentForReturnValue;
if (docComment != null && docComment.getReturnBlock() != null) {
docCommentForReturnValue = docComment;
} else if (classMethod.getTypeExpr().getArity() == typeExpr.getArity()) {
// we only default to the class method's comment if the arities match
// for example: the QuickCheck.Arbitrary instance for the function type a->b has an instance method:
// generateInstance :: (Arbitrary a, Arbitrary b) => GenParams -> a -> b
// but the class method has the type:
// generateInstance :: (Arbitrary a) => GenParams -> a
// so we cannot use the return value description in the class method's comment (it would be describing the wrong thing)
docCommentForReturnValue = classMethodCALDocComment;
} else {
docCommentForReturnValue = null;
}
if (docComment == null) {
docComment = classMethodCALDocComment;
}
generateFunctionalAgentOrInstanceMethodDocHeading(scope, unqualifiedName, entityWithArgumentNames, typeExpr, label, argMetadataArray, docCommentForArguments, index, true);
generateFunctionalAgentOrInstanceMethodDocBody(scope, entityWithArgumentNames, typeExpr, metadata, argMetadataArray, docComment, docCommentForArguments, docCommentForReturnValue, true);
}
/**
* {@inheritDoc}
*/
@Override
void endInstanceMethodDocList(int nInstanceMethods) {
/// Generate the end for the instance method list only if the list is non-empty
//
if (nInstanceMethods > 0) {
currentPage.closeTag(HTML.Tag.DL).closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
}
/**
* {@inheritDoc}
*/
@Override
void generateClassInstanceDocFooter(ClassInstance classInstance, int index) {
// Just close the definition list
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
/**
* {@inheritDoc}
*/
@Override
void endClassInstancesDocSection(int nClassInstances) {
if (nClassInstances > 0) {
currentPage.closeTag(HTML.Tag.DIV);
}
if (config.shouldSeparateInstanceDoc) {
/// Close the main content div tag
//
currentPage.closeTag(HTML.Tag.DIV);
/// Generate the navigation bar and the fine print
//
String relativePathToBaseDirectory = "../"; // all instance docs are in a subdirectory of the base directory
generateModulePageNavBar(true, relativePathToBaseDirectory, nTypeConstructorsInModule, nFunctionsInModule, nTypeClassesInModule, nClassInstancesInModule);
generatePageBottom();
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
/// Write the completed usage documentation out.
//
generateTextFile(SEPARATE_INSTANCE_DOC_SUBDIRECTORY, getSeparateInstanceDocFileName(currentModuleName), getHTMLFileContentsWithDocTypeForMainFramePage(currentPage));
/// Switch from the separate instance documentation page back to the main page
//
inSeparateInstanceDoc = false;
currentPage = mainPageContext;
}
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeConsUsageDoc(TypeConstructor typeConstructor) {
ModuleName moduleName = typeConstructor.getName().getModuleName();
String typeName = typeConstructor.getName().getUnqualifiedName();
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeConstructorFeatureName(typeConstructor.getName()), getLocale());
CALDocComment docComment = typeConstructor.getCALDocComment();
String label = labelMaker.getLabel(typeConstructor);
// We delegate the generation of everything before the declaration to a helper method.
generateUsageDocStartBeforeDeclaration(typeConstructor.getName(), label);
// Just generate the declaration for the type constructor
currentPage
.addText(CALFragments.DATA)
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeConstructor.getScope().toString())
.addText(" ")
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.DECLARED_NAME), typeName);
// We delegate the generation of everything after the declaration to a helper method.
generateUsageDocStartAfterDeclaration(typeConstructor, moduleName, metadata, docComment, label);
}
/**
* Generates the first half of the start of the usage documentation, before the declaration of the entity.
* @param qualifiedName the qualified name of the entity whose usage is being documented.
* @param label the label for the entity.
*/
private void generateUsageDocStartBeforeDeclaration(QualifiedName qualifiedName, String label) {
/// Start a new HTML page for the usage documentation
//
startNewCurrentPageWithModule(qualifiedName.getModuleName());
/// Generate the head section
//
currentPage.openTag(HTML.Tag.HTML);
String relativePathToBaseDirectory = "../"; // all usage docs are in a subdirectory of the base directory
String pageTitle = makePageTitle(qualifiedName.getQualifiedName());
generateHeadSection(pageTitle, relativePathToBaseDirectory, null, null);
/// Start the body section with a javascript which changes the window title (needed if inside a frame)
//
currentPage
.openTag(HTML.Tag.BODY, classAttribute(StyleClassConstants.WITH_MAIN_CONTENT).concat(HTMLBuilder.AttributeList.make(HTML4.ONLOAD_ATTRIBUTE, "changeTitle()")))
.addTaggedText(HTML.Tag.SCRIPT, HTMLBuilder.AttributeList.make(HTML.Attribute.TYPE, "text/javascript"), "function changeTitle() { parent.document.title='" + pageTitle + "'; }");
generateUpdateScopeDisplaySettingsJavascript();
/// Generate the navigation bar
//
generateGenericNavBar(false, relativePathToBaseDirectory);
/// Wrap the main content with a div tag
//
currentPage.openTag(HTML.Tag.DIV, classAttribute(StyleClassConstants.MAIN_CONTENT));
/// Generate the heading of the page using the qualified name
//
currentPage.addTaggedText(HTML.Tag.H1, qualifiedName.getQualifiedName());
/// Prepare for the generation of the declaration
//
currentPage
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT, idAndClassAttributes(label, StyleClassConstants.FIRST_DEFINITION_SECTION_START))
.openTag(HTML.Tag.CODE, classAttribute(StyleClassConstants.DECLARATION));
}
/**
* Generates the second half of the start of the usage documentation, after the declaration of the entity.
* @param moduleName the name of the entity's module.
* @param metadata the metadata of the entity. Can be null if not available.
* @param docComment the CALDoc comment of the entity. Can be null if not available.
* @param label the label for the entity.
*/
private void generateUsageDocStartAfterDeclaration(ScopedEntity documentedEntity, ModuleName moduleName, CALFeatureMetadata metadata, CALDocComment docComment, String label) {
/// Generate a link to the main documentation entry
//
currentPage
.closeTag(HTML.Tag.CODE)
.addText(" [");
String relativePathToModulesSubdirectory = "../" + MODULES_SUBDIRECTORY;
generateNonLocalReference(currentPage, relativePathToModulesSubdirectory, moduleName, label, LocalizableUserVisibleString.MAIN_ENTRY.toResourceString(), null);
currentPage
.addText("]")
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD);
/// Then generate the description and supplementary blocks
//
ReferenceGenerator referenceGenerator = new ReferenceGenerator(relativePathToModulesSubdirectory);
generateStandardDescription(metadata, docComment, referenceGenerator);
if (documentedEntity instanceof TypeConstructor) {
generateForeignTypeInfo((TypeConstructor)documentedEntity);
}
generateStandardSupplementaryBlocks(metadata, docComment, referenceGenerator);
currentPage.closeTag(HTML.Tag.DD).closeTag(HTML.Tag.DL);
}
/**
* {@inheritDoc}
*/
@Override
void beginTypeClassUsageDoc(TypeClass typeClass) {
ModuleName moduleName = typeClass.getName().getModuleName();
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getTypeClassFeatureName(typeClass.getName()), getLocale());
CALDocComment docComment = typeClass.getCALDocComment();
String label = labelMaker.getLabel(typeClass);
// We delegate the generation of everything before the declaration to a helper method.
generateUsageDocStartBeforeDeclaration(typeClass.getName(), label);
// Just generate the declaration for the type class
currentPage
.addTaggedText(HTML.Tag.SPAN, classAttribute(StyleClassConstants.SCOPE), typeClass.getScope().toString())
.addText(" ")
.addText(CALFragments.CLASS)
.addText(" ");
generateTypeClassFullName(typeClass, false, StyleClassConstants.DECLARED_NAME);
// We delegate the generation of everything after the declaration to a helper method.
generateUsageDocStartAfterDeclaration(typeClass, moduleName, metadata, docComment, label);
}
/**
* {@inheritDoc}
*/
void beginUsageDocGroupForDependentModule(ScopedEntity documentedEntity, ModuleName dependentModuleName) {
ModuleName moduleName = documentedEntity.getName().getModuleName();
////
/// Generate a major section heading for the dependent module
//
currentPage.openTag(HTML.Tag.H2, classAttribute(StyleClassConstants.MAJOR_SECTION));
// We either display "Defining module:" or "Dependent module:" depending on whether the dependent module
// is really the defining module of the entity being documented
if (moduleName.equals(dependentModuleName)) {
currentPage.addText(LocalizableUserVisibleString.DEFINING_MODULE_COLON.toResourceString()).addText(" ");
} else {
currentPage.addText(LocalizableUserVisibleString.DEPENDENT_MODULE_COLON.toResourceString()).addText(" ");
}
// Generate a hyperlink to the dependent module if its documentation its generated, or otherwise simply generate its name
if (isDocForModuleGenerated(dependentModuleName)) {
generateNonLocalReference(currentPage, "../" + MODULES_SUBDIRECTORY, dependentModuleName, labelMaker.getModuleLabel(dependentModuleName), getFullyQualifiedNameForModule(dependentModuleName), getFullyQualifiedNameForModule(dependentModuleName));
} else {
currentPage.addText(getFullyQualifiedNameForModule(dependentModuleName));
}
currentPage.closeTag(HTML.Tag.H2);
}
/**
* {@inheritDoc}
*/
void beginUsageDocArgTypeIndex(ScopedEntity documentedEntity, int nArgTypeIndexEntries, Scope maxScopeOfArgTypeIndexEntries) {
/// Generate the start of the argument type index list only if the list is non-empty
//
if (nArgTypeIndexEntries > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfArgTypeIndexEntries)));
beginOverviewTable(LocalizableUserVisibleString.USAGE_DOC_ARGUMENT_TYPE_INDEX.toResourceString(documentedEntity.getName().getQualifiedName()), false);
}
}
/**
* {@inheritDoc}
*/
void generateUsageDocArgTypeIndexEntry(ScopedEntity documentedEntity, FunctionalAgent entity) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(entity, getLocale());
CALDocComment docComment = entity.getCALDocComment();
// We delegate to a helper method to generate a usage index entry
generateUsageIndexEntry(entity, labelMaker.getLabel(entity), metadata, docComment, StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION);
}
/**
* {@inheritDoc}
*/
void endUsageDocArgTypeIndex(ScopedEntity documentedEntity, int nArgTypeIndexEntries) {
/// Generate the end of the argument type index list only if the list is non-empty
//
if (nArgTypeIndexEntries > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
void beginUsageDocReturnTypeIndex(ScopedEntity documentedEntity, int nReturnTypeIndexEntries, Scope maxScopeOfReturnTypeIndexEntries) {
/// Generate the start of the return type index list only if the list is non-empty
//
if (nReturnTypeIndexEntries > 0) {
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfReturnTypeIndexEntries)));
beginOverviewTable(LocalizableUserVisibleString.USAGE_DOC_RETURN_TYPE_INDEX.toResourceString(documentedEntity.getName().getQualifiedName()), false);
}
}
/**
* {@inheritDoc}
*/
void generateUsageDocReturnTypeIndexEntry(ScopedEntity documentedEntity, FunctionalAgent entity) {
FunctionalAgentMetadata metadata = (FunctionalAgentMetadata)getMetadata(entity, getLocale());
CALDocComment docComment = entity.getCALDocComment();
// We delegate to a helper method to generate a usage index entry
generateUsageIndexEntry(entity, labelMaker.getLabel(entity), metadata, docComment, StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION);
}
/**
* {@inheritDoc}
*/
void endUsageDocReturnTypeIndex(ScopedEntity documentedEntity, int nReturnTypeIndexEntries) {
/// Generate the end of the return type index list only if the list is non-empty
//
if (nReturnTypeIndexEntries > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
void beginUsageDocInstanceIndex(ScopedEntity documentedEntity, int nInstances, Scope maxScopeOfInstanceIndexEntries) {
/// Generate the start of the instance index list only if the list is non-empty
//
if (nInstances > 0) {
/// If the entity is a type class, we want to display "Instances of <class>", otherwise
/// we want to display (for a type) "Instances for <type>".
//
LocalizableUserVisibleString stringTemplate;
if (documentedEntity instanceof TypeClass) {
stringTemplate = LocalizableUserVisibleString.USAGE_DOC_INSTANCE_INDEX_INSTANCES_OF;
} else {
stringTemplate = LocalizableUserVisibleString.USAGE_DOC_INSTANCE_INDEX_INSTANCES_FOR;
}
currentPage.openTag(HTML.Tag.DIV, classAttribute(getScopeStyleClass(maxScopeOfInstanceIndexEntries)));
beginOverviewTable(stringTemplate.toResourceString(documentedEntity.getName().getQualifiedName()), false);
}
}
/**
* {@inheritDoc}
*/
void generateUsageDocInstanceIndexEntry(ScopedEntity documentedEntity, ClassInstance classInstance) {
CALFeatureMetadata metadata = getMetadata(CALFeatureName.getClassInstanceFeatureName(classInstance), getLocale());
CALDocComment docComment = classInstance.getCALDocComment();
/// Generate the name of the class instance
//
currentPage
.openTag(HTML.Tag.TR, classAttribute(getScopeStyleClass(minScopeForInstanceClassAndInstanceType(classInstance))))
.openTag(HTML.Tag.TD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_SCOPE_COLUMN).concat(HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline")))
.closeTag(HTML.Tag.TD)
.openTag(HTML.Tag.TD, HTMLBuilder.AttributeList.make(HTML.Attribute.VALIGN, "baseline"))
.openTag(HTML.Tag.DL)
.openTag(HTML.Tag.DT)
.openTag(HTML.Tag.SPAN, classAttribute(StyleClassConstants.OVERVIEW_REFERENCE));
/// Generate a reference to the class instance, appropriately hyperlinked.
//
String relativePathToBaseDirectory = "../";
String relativePathToModulesSubdirectory = "../" + MODULES_SUBDIRECTORY;
if (!isDocForClassInstanceGenerated(classInstance)) {
// if the class instance is not documented, no hyperlink can be made.
generateClassInstanceDeclarationName(classInstance, false);
} else {
// the instance is indeed documented, so create a hyperlinked reference to it
HTMLBuilder.AttributeList hrefAttribute = getHrefAttributeForNonLocalClassInstanceReference(classInstance, relativePathToBaseDirectory);
currentPage.openTag(HTML.Tag.A, hrefAttribute);
generateClassInstanceDeclarationName(classInstance, false);
currentPage.closeTag(HTML.Tag.A);
}
currentPage
.closeTag(HTML.Tag.SPAN)
.closeTag(HTML.Tag.DT)
.openTag(HTML.Tag.DD, classAttribute(StyleClassConstants.OVERVIEW_TABLE_OUTER_DESCRIPTION));
/// Then generate the short description for the entry
//
generateShortDescription(metadata, docComment, new ReferenceGenerator(relativePathToModulesSubdirectory));
// Close off the table row
currentPage
.closeTag(HTML.Tag.DD)
.closeTag(HTML.Tag.DL)
.closeTag(HTML.Tag.TD)
.closeTag(HTML.Tag.TR);
}
/**
* {@inheritDoc}
*/
void endUsageDocInstanceIndex(ScopedEntity documentedEntity, int nInstances) {
/// Generate the end of the instance index list only if the list is non-empty
//
if (nInstances > 0) {
endOverviewTable();
currentPage.closeTag(HTML.Tag.DIV);
}
}
/**
* {@inheritDoc}
*/
void endUsageDocGroupForDependentModule(ScopedEntity documentedEntity, ModuleName dependentModuleName) {
// nothing to do
}
/**
* {@inheritDoc}
*/
void endTypeConsUsageDoc(TypeConstructor documentedEntity) {
// Delegate to a helper method
generateUsageDocEnd(TYPE_CONS_USAGE_SUBDIRECTORY, getTypeConsUsageIndexFileName(documentedEntity.getName()));
}
/**
* Generates the end of the usage documentation, and writes out the file.
* @param usageSubdirectory the usage subdirectory to contain the generated file.
* @param indexFileName the name of the index file to be written.
*/
private void generateUsageDocEnd(String usageSubdirectory, String indexFileName) {
/// Close the main content div tag
//
currentPage.closeTag(HTML.Tag.DIV);
/// Generate the navigation bar and the fine print
//
String relativePathToBaseDirectory = "../"; // all usage docs are in a subdirectory of the base directory
generateGenericNavBar(true, relativePathToBaseDirectory);
generatePageBottom();
currentPage.closeTag(HTML.Tag.BODY).closeTag(HTML.Tag.HTML);
/// Write the completed usage documentation out.
//
generateTextFile(usageSubdirectory, indexFileName, getHTMLFileContentsWithDocTypeForMainFramePage(currentPage));
}
/**
* {@inheritDoc}
*/
void endTypeClassUsageDoc(TypeClass documentedEntity) {
// Delegate to a helper method
generateUsageDocEnd(TYPE_CLASS_USAGE_SUBDIRECTORY, getTypeClassUsageIndexFileName(documentedEntity.getName()));
}
}