/* * Copyright (C) 2010 Google Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.google.doclava; import com.google.clearsilver.jsilver.data.Data; import java.util.ArrayList; import java.util.Collection; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; public class NavTree { /* @deprecated This method was used for an older version of DAC, circa 2012, retired May 2018 */ public static void writeNavTree(String dir, String refPrefix) { List children = new ArrayList(); for (PackageInfo pkg : Doclava.choosePackages()) { children.add(makePackageNode(pkg)); } Node node = new Node("Reference", dir + refPrefix + "packages.html", children, null); StringBuilder buf = new StringBuilder(); if (false) { // if you want a root node buf.append("["); node.render(buf); buf.append("]"); } else { // if you don't want a root node node.renderChildren(buf); } Data data = Doclava.makeHDF(); data.setValue("reference_tree", buf.toString()); if (refPrefix == "gms-"){ ClearPage.write(data, "gms_navtree_data.cs", "gms_navtree_data.js"); } else if (refPrefix == "gcm-"){ ClearPage.write(data, "gcm_navtree_data.cs", "gcm_navtree_data.js"); } else if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { ClearPage.write(data, "navtree_data.cs", dir + Doclava.libraryRoot + "navtree_data.js"); } else { ClearPage.write(data, "navtree_data.cs", "navtree_data.js"); } } /** * Write the YAML formatted navigation tree. * This is intended to replace writeYamlTree(), but for now requires an explicit opt-in via * the yamlV2 flag in the doclava command. This version creates a yaml file with all classes, * interface, exceptions, etc. separated into collapsible groups. */ public static void writeYamlTree2(String dir, String fileName){ List children = new ArrayList(); for (PackageInfo pkg : Doclava.choosePackages()) { children.add(makePackageNode(pkg)); } Node node = new Node("Reference", Doclava.ensureSlash(dir) + "packages.html", children, null); StringBuilder buf = new StringBuilder(); node.renderChildrenYaml(buf, 0); Data data = Doclava.makeHDF(); data.setValue("reference_tree", buf.toString()); if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { dir = Doclava.ensureSlash(dir) + Doclava.libraryRoot; } data.setValue("docs.classes.link", Doclava.ensureSlash(dir) + "classes.html"); data.setValue("docs.packages.link", Doclava.ensureSlash(dir) + "packages.html"); ClearPage.write(data, "yaml_navtree2.cs", Doclava.ensureSlash(dir) + fileName); } /** * Write the YAML formatted navigation tree (legacy version). * This creates a yaml file with package names followed by all * classes, interfaces, exceptions, etc. But they are not separated by classes, interfaces, etc. * It also nests any nested classes under the parent class, instead of listing them as siblings. * @see "http://yaml.org/" */ public static void writeYamlTree(String dir, String fileName){ Data data = Doclava.makeHDF(); Collection classes = Converter.rootClasses(); SortedMap sorted = new TreeMap(); for (ClassInfo cl : classes) { if (cl.isHiddenOrRemoved()) { continue; } sorted.put(cl.qualifiedName(), cl); PackageInfo pkg = cl.containingPackage(); String name; if (pkg == null) { name = ""; } else { name = pkg.name(); } sorted.put(name, pkg); } data = makeYamlHDF(sorted, "docs.pages", data); if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { dir = Doclava.ensureSlash(dir) + Doclava.libraryRoot; } data.setValue("docs.classes.link", Doclava.ensureSlash(dir) + "classes.html"); data.setValue("docs.packages.link", Doclava.ensureSlash(dir) + "packages.html"); ClearPage.write(data, "yaml_navtree.cs", Doclava.ensureSlash(dir) + fileName); } public static Data makeYamlHDF(SortedMap sorted, String base, Data data) { String key = "docs.pages."; int i = 0; for (String s : sorted.keySet()) { Object o = sorted.get(s); if (o instanceof PackageInfo) { PackageInfo pkg = (PackageInfo) o; data.setValue("docs.pages." + i + ".id", "" + i); data.setValue("docs.pages." + i + ".label", pkg.name()); data.setValue("docs.pages." + i + ".shortname", "API"); data.setValue("docs.pages." + i + ".apilevel", pkg.getSince()); data.setValue("docs.pages." + i + ".link", pkg.htmlPage()); data.setValue("docs.pages." + i + ".type", "package"); } else if (o instanceof ClassInfo) { ClassInfo cl = (ClassInfo) o; // skip classes that are the child of another class, recursion will handle those. if (cl.containingClass() == null) { data.setValue("docs.pages." + i + ".id", "" + i); data = makeYamlHDF(cl, "docs.pages."+i, data); } } i++; } return data; } public static Data makeYamlHDF(ClassInfo cl, String base, Data data) { data.setValue(base + ".label", cl.name()); data.setValue(base + ".shortname", cl.name().substring(cl.name().lastIndexOf(".")+1)); data.setValue(base + ".link", cl.htmlPage()); data.setValue(base + ".type", cl.kind()); if (cl.innerClasses().size() > 0) { int j = 0; for (ClassInfo cl2 : cl.innerClasses()) { if (cl2.isHiddenOrRemoved()) { continue; } data = makeYamlHDF(cl2, base + ".children." + j, data); j++; } } return data; } private static Node makePackageNode(PackageInfo pkg) { List children = new ArrayList(); addClassNodes(children, "Annotations", pkg.annotations()); addClassNodes(children, "Interfaces", pkg.interfaces()); addClassNodes(children, "Classes", pkg.ordinaryClasses()); addClassNodes(children, "Enums", pkg.enums()); addClassNodes(children, "Exceptions", pkg.exceptions()); addClassNodes(children, "Errors", pkg.errors()); return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince()); } private static void addClassNodes(List parent, String label, ClassInfo[] classes) { List children = new ArrayList(); for (ClassInfo cl : classes) { if (cl.checkLevel()) { children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince(), cl.getArtifact())); } } if (children.size() > 0) { parent.add(new Node(label, null, children, null)); } } private static class Node { private String mLabel; private String mLink; List mChildren; private String mSince; private String mArtifact; Node(String label, String link, List children, String since) { this(label, link, children, since, null); } Node(String label, String link, List children, String since, String artifact) { mLabel = label; mLink = link; mChildren = children; mSince = since; mArtifact = artifact; } static void renderString(StringBuilder buf, String s) { if (s == null) { buf.append("null"); } else { buf.append('"'); final int N = s.length(); for (int i = 0; i < N; i++) { char c = s.charAt(i); if (c >= ' ' && c <= '~' && c != '"' && c != '\\') { buf.append(c); } else { buf.append("\\u"); for (int j = 0; i < 4; i++) { char x = (char) (c & 0x000f); if (x >= 10) { x = (char) (x - 10 + 'a'); } else { x = (char) (x + '0'); } buf.append(x); c >>= 4; } } } buf.append('"'); } } void renderChildren(StringBuilder buf) { List list = mChildren; if (list == null || list.size() == 0) { // We output null for no children. That way empty lists here can just // be a byproduct of how we generate the lists. buf.append("null"); } else { buf.append("[ "); final int N = list.size(); for (int i = 0; i < N; i++) { list.get(i).render(buf); if (i != N - 1) { buf.append(", "); } } buf.append(" ]\n"); } } void render(StringBuilder buf) { buf.append("[ "); renderString(buf, mLabel); buf.append(", "); renderString(buf, mLink); buf.append(", "); renderChildren(buf); buf.append(", "); renderString(buf, mSince); buf.append(", "); renderString(buf, mArtifact); buf.append(" ]"); } // YAML VERSION static void renderStringYaml(StringBuilder buf, String s) { if (s != null) { final int N = s.length(); for (int i = 0; i < N; i++) { char c = s.charAt(i); if (c >= ' ' && c <= '~' && c != '"' && c != '\\') { buf.append(c); } else { buf.append("\\u"); for (int j = 0; i < 4; i++) { char x = (char) (c & 0x000f); if (x >= 10) { x = (char) (x - 10 + 'a'); } else { x = (char) (x + '0'); } buf.append(x); c >>= 4; } } } } } void renderChildrenYaml(StringBuilder buf, int depth) { List list = mChildren; if (list != null && list.size() > 0) { if (depth > 0) { buf.append("\n\n" + getIndent(depth)); buf.append("section:"); } final int N = list.size(); for (int i = 0; i < N; i++) { // get each child Node and render it list.get(i).renderYaml(buf, depth); } // Extra line break after each "section" buf.append("\n"); } } void renderYaml(StringBuilder buf, int depth) { buf.append("\n" + getIndent(depth)); buf.append("- title: \""); renderStringYaml(buf, mLabel); buf.append("\""); // Add link path, if it exists (the class/interface toggles don't have links) if (mLink != null) { buf.append("\n" + getIndent(depth)); buf.append(" path: "); renderStringYaml(buf, "/" + mLink); // add the API level info only if we have it if (mSince != null) { buf.append("\n" + getIndent(depth)); buf.append(" version_added: "); renderStringYaml(buf, "'" + mSince + "'"); } } // try rendering child Nodes renderChildrenYaml(buf, depth + 1); } String getIndent(int depth) { String spaces = ""; for (int i = 0; i < depth; i++) { spaces += " "; } return spaces; } } }