1 /* 2 * Copyright (C) 2010 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.google.doclava; 18 19 import com.google.clearsilver.jsilver.data.Data; 20 21 import java.util.ArrayList; 22 import java.util.List; 23 import java.util.SortedMap; 24 import java.util.TreeMap; 25 26 public class NavTree { 27 writeNavTree(String dir, String refPrefix)28 public static void writeNavTree(String dir, String refPrefix) { 29 List<Node> children = new ArrayList<Node>(); 30 for (PackageInfo pkg : Doclava.choosePackages()) { 31 children.add(makePackageNode(pkg)); 32 } 33 Node node = new Node("Reference", dir + refPrefix + "packages.html", children, null); 34 35 StringBuilder buf = new StringBuilder(); 36 if (false) { 37 // if you want a root node 38 buf.append("["); 39 node.render(buf); 40 buf.append("]"); 41 } else { 42 // if you don't want a root node 43 node.renderChildren(buf); 44 } 45 46 Data data = Doclava.makeHDF(); 47 data.setValue("reference_tree", buf.toString()); 48 if (refPrefix == "gms-"){ 49 ClearPage.write(data, "gms_navtree_data.cs", "gms_navtree_data.js"); 50 } else if (refPrefix == "gcm-"){ 51 ClearPage.write(data, "gcm_navtree_data.cs", "gcm_navtree_data.js"); 52 } else if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { 53 ClearPage.write(data, "navtree_data.cs", dir + Doclava.libraryRoot 54 + "navtree_data.js"); 55 } else { 56 ClearPage.write(data, "navtree_data.cs", "navtree_data.js"); 57 } 58 } 59 60 /** 61 * Write the YAML formatted navigation tree. 62 * @see "http://yaml.org/" 63 */ writeYamlTree(String dir, String fileName)64 public static void writeYamlTree(String dir, String fileName){ 65 Data data = Doclava.makeHDF(); 66 ClassInfo[] classes = Converter.rootClasses(); 67 68 SortedMap<String, Object> sorted = new TreeMap<String, Object>(); 69 for (ClassInfo cl : classes) { 70 if (cl.isHiddenOrRemoved()) { 71 continue; 72 } 73 sorted.put(cl.qualifiedName(), cl); 74 75 PackageInfo pkg = cl.containingPackage(); 76 String name; 77 if (pkg == null) { 78 name = ""; 79 } else { 80 name = pkg.name(); 81 } 82 sorted.put(name, pkg); 83 } 84 85 data = makeYamlHDF(sorted, "docs.pages", data); 86 87 if (Doclava.USE_DEVSITE_LOCALE_OUTPUT_PATHS && (Doclava.libraryRoot != null)) { 88 dir = Doclava.ensureSlash(dir) + Doclava.libraryRoot; 89 } 90 91 data.setValue("docs.classes.link", Doclava.ensureSlash(dir) + "classes.html"); 92 data.setValue("docs.packages.link", Doclava.ensureSlash(dir) + "packages.html"); 93 94 ClearPage.write(data, "yaml_navtree.cs", Doclava.ensureSlash(dir) + fileName); 95 } 96 makeYamlHDF(SortedMap<String, Object> sorted, String base, Data data)97 public static Data makeYamlHDF(SortedMap<String, Object> sorted, String base, Data data) { 98 99 String key = "docs.pages."; 100 int i = 0; 101 for (String s : sorted.keySet()) { 102 Object o = sorted.get(s); 103 104 if (o instanceof PackageInfo) { 105 PackageInfo pkg = (PackageInfo) o; 106 107 data.setValue("docs.pages." + i + ".id", "" + i); 108 data.setValue("docs.pages." + i + ".label", pkg.name()); 109 data.setValue("docs.pages." + i + ".shortname", "API"); 110 data.setValue("docs.pages." + i + ".apilevel", pkg.getSince()); 111 data.setValue("docs.pages." + i + ".link", pkg.htmlPage()); 112 data.setValue("docs.pages." + i + ".type", "package"); 113 } else if (o instanceof ClassInfo) { 114 ClassInfo cl = (ClassInfo) o; 115 116 // skip classes that are the child of another class, recursion will handle those. 117 if (cl.containingClass() == null) { 118 119 data.setValue("docs.pages." + i + ".id", "" + i); 120 data = makeYamlHDF(cl, "docs.pages."+i, data); 121 } 122 } 123 124 i++; 125 } 126 127 return data; 128 } 129 makeYamlHDF(ClassInfo cl, String base, Data data)130 public static Data makeYamlHDF(ClassInfo cl, String base, Data data) { 131 data.setValue(base + ".label", cl.name()); 132 data.setValue(base + ".shortname", cl.name().substring(cl.name().lastIndexOf(".")+1)); 133 data.setValue(base + ".link", cl.htmlPage()); 134 data.setValue(base + ".type", cl.kind()); 135 136 if (cl.innerClasses().size() > 0) { 137 int j = 0; 138 for (ClassInfo cl2 : cl.innerClasses()) { 139 if (cl2.isHiddenOrRemoved()) { 140 continue; 141 } 142 data = makeYamlHDF(cl2, base + ".children." + j, data); 143 j++; 144 } 145 } 146 147 return data; 148 } 149 makePackageNode(PackageInfo pkg)150 private static Node makePackageNode(PackageInfo pkg) { 151 List<Node> children = new ArrayList<Node>(); 152 153 addClassNodes(children, "Annotations", pkg.annotations()); 154 addClassNodes(children, "Interfaces", pkg.interfaces()); 155 addClassNodes(children, "Classes", pkg.ordinaryClasses()); 156 addClassNodes(children, "Enums", pkg.enums()); 157 addClassNodes(children, "Exceptions", pkg.exceptions()); 158 addClassNodes(children, "Errors", pkg.errors()); 159 160 return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince()); 161 } 162 addClassNodes(List<Node> parent, String label, ClassInfo[] classes)163 private static void addClassNodes(List<Node> parent, String label, ClassInfo[] classes) { 164 List<Node> children = new ArrayList<Node>(); 165 166 for (ClassInfo cl : classes) { 167 if (cl.checkLevel()) { 168 children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince(), cl.getArtifact())); 169 } 170 } 171 172 if (children.size() > 0) { 173 parent.add(new Node(label, null, children, null)); 174 } 175 } 176 177 private static class Node { 178 private String mLabel; 179 private String mLink; 180 List<Node> mChildren; 181 private String mSince; 182 private String mArtifact; 183 Node(String label, String link, List<Node> children, String since)184 Node(String label, String link, List<Node> children, String since) { 185 this(label, link, children, since, null); 186 } 187 Node(String label, String link, List<Node> children, String since, String artifact)188 Node(String label, String link, List<Node> children, String since, String artifact) { 189 mLabel = label; 190 mLink = link; 191 mChildren = children; 192 mSince = since; 193 mArtifact = artifact; 194 } 195 renderString(StringBuilder buf, String s)196 static void renderString(StringBuilder buf, String s) { 197 if (s == null) { 198 buf.append("null"); 199 } else { 200 buf.append('"'); 201 final int N = s.length(); 202 for (int i = 0; i < N; i++) { 203 char c = s.charAt(i); 204 if (c >= ' ' && c <= '~' && c != '"' && c != '\\') { 205 buf.append(c); 206 } else { 207 buf.append("\\u"); 208 for (int j = 0; i < 4; i++) { 209 char x = (char) (c & 0x000f); 210 if (x >= 10) { 211 x = (char) (x - 10 + 'a'); 212 } else { 213 x = (char) (x + '0'); 214 } 215 buf.append(x); 216 c >>= 4; 217 } 218 } 219 } 220 buf.append('"'); 221 } 222 } 223 renderChildren(StringBuilder buf)224 void renderChildren(StringBuilder buf) { 225 List<Node> list = mChildren; 226 if (list == null || list.size() == 0) { 227 // We output null for no children. That way empty lists here can just 228 // be a byproduct of how we generate the lists. 229 buf.append("null"); 230 } else { 231 buf.append("[ "); 232 final int N = list.size(); 233 for (int i = 0; i < N; i++) { 234 list.get(i).render(buf); 235 if (i != N - 1) { 236 buf.append(", "); 237 } 238 } 239 buf.append(" ]\n"); 240 } 241 } 242 render(StringBuilder buf)243 void render(StringBuilder buf) { 244 buf.append("[ "); 245 renderString(buf, mLabel); 246 buf.append(", "); 247 renderString(buf, mLink); 248 buf.append(", "); 249 renderChildren(buf); 250 buf.append(", "); 251 renderString(buf, mSince); 252 buf.append(", "); 253 renderString(buf, mArtifact); 254 buf.append(" ]"); 255 } 256 } 257 } 258