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 {
53       ClearPage.write(data, "navtree_data.cs", "navtree_data.js");
54     }
55   }
56 
57   /**
58    * Write the YAML formatted navigation tree.
59    * @see "http://yaml.org/"
60    */
writeYamlTree(String dir, String fileName)61   public static void writeYamlTree(String dir, String fileName){
62     Data data = Doclava.makeHDF();
63     ClassInfo[] classes = Converter.rootClasses();
64 
65     SortedMap<String, Object> sorted = new TreeMap<String, Object>();
66     for (ClassInfo cl : classes) {
67       if (cl.isHiddenOrRemoved()) {
68         continue;
69       }
70       sorted.put(cl.qualifiedName(), cl);
71 
72       PackageInfo pkg = cl.containingPackage();
73       String name;
74       if (pkg == null) {
75         name = "";
76       } else {
77         name = pkg.name();
78       }
79       sorted.put(name, pkg);
80     }
81 
82     data = makeYamlHDF(sorted, "docs.pages", data);
83     ClearPage.write(data, "yaml_navtree.cs", Doclava.ensureSlash(dir) + fileName);
84   }
85 
makeYamlHDF(SortedMap<String, Object> sorted, String base, Data data)86   public static Data makeYamlHDF(SortedMap<String, Object> sorted, String base, Data data) {
87 
88     String key = "docs.pages.";
89     int i = 0;
90     for (String s : sorted.keySet()) {
91       Object o = sorted.get(s);
92 
93       if (o instanceof PackageInfo) {
94         PackageInfo pkg = (PackageInfo) o;
95 
96         data.setValue("docs.pages." + i + ".id", "" + i);
97         data.setValue("docs.pages." + i + ".label", pkg.name());
98         data.setValue("docs.pages." + i + ".shortname", "API");
99         data.setValue("docs.pages." + i + ".link", pkg.htmlPage());
100         data.setValue("docs.pages." + i + ".type", "package");
101       } else if (o instanceof ClassInfo) {
102         ClassInfo cl = (ClassInfo) o;
103 
104        // skip classes that are the child of another class, recursion will handle those.
105        if (cl.containingClass() == null){
106 
107          data.setValue("docs.pages." + i + ".id", "" + i);
108          data = makeYamlHDF(cl, "docs.pages."+i, data);
109        }
110      }
111 
112      i++;
113    }
114    return data;
115  }
116 
makeYamlHDF(ClassInfo cl, String base, Data data)117  public static Data makeYamlHDF(ClassInfo cl, String base, Data data) {
118    data.setValue(base + ".label", cl.name());
119    data.setValue(base + ".shortname", cl.name().substring(cl.name().lastIndexOf(".")+1));
120    data.setValue(base + ".link", cl.htmlPage());
121    data.setValue(base + ".type", cl.kind());
122 
123    if (cl.innerClasses().size() > 0){
124      int j = 0;
125      for (ClassInfo cl2 : cl.innerClasses()){
126        data = makeYamlHDF(cl2, base + ".children." + j, data);
127        j++;
128      }
129    }
130 
131     return data;
132   }
makePackageNode(PackageInfo pkg)133   private static Node makePackageNode(PackageInfo pkg) {
134     List<Node> children = new ArrayList<Node>();
135 
136     addClassNodes(children, "Annotations", pkg.annotations());
137     addClassNodes(children, "Interfaces", pkg.interfaces());
138     addClassNodes(children, "Classes", pkg.ordinaryClasses());
139     addClassNodes(children, "Enums", pkg.enums());
140     addClassNodes(children, "Exceptions", pkg.exceptions());
141     addClassNodes(children, "Errors", pkg.errors());
142 
143     return new Node(pkg.name(), pkg.htmlPage(), children, pkg.getSince());
144   }
145 
addClassNodes(List<Node> parent, String label, ClassInfo[] classes)146   private static void addClassNodes(List<Node> parent, String label, ClassInfo[] classes) {
147     List<Node> children = new ArrayList<Node>();
148 
149     for (ClassInfo cl : classes) {
150       if (cl.checkLevel()) {
151         children.add(new Node(cl.name(), cl.htmlPage(), null, cl.getSince()));
152       }
153     }
154 
155     if (children.size() > 0) {
156       parent.add(new Node(label, null, children, null));
157     }
158   }
159 
160   private static class Node {
161     private String mLabel;
162     private String mLink;
163     List<Node> mChildren;
164     private String mSince;
165 
Node(String label, String link, List<Node> children, String since)166     Node(String label, String link, List<Node> children, String since) {
167       mLabel = label;
168       mLink = link;
169       mChildren = children;
170       mSince = since;
171     }
172 
renderString(StringBuilder buf, String s)173     static void renderString(StringBuilder buf, String s) {
174       if (s == null) {
175         buf.append("null");
176       } else {
177         buf.append('"');
178         final int N = s.length();
179         for (int i = 0; i < N; i++) {
180           char c = s.charAt(i);
181           if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
182             buf.append(c);
183           } else {
184             buf.append("\\u");
185             for (int j = 0; i < 4; i++) {
186               char x = (char) (c & 0x000f);
187               if (x >= 10) {
188                 x = (char) (x - 10 + 'a');
189               } else {
190                 x = (char) (x + '0');
191               }
192               buf.append(x);
193               c >>= 4;
194             }
195           }
196         }
197         buf.append('"');
198       }
199     }
200 
renderChildren(StringBuilder buf)201     void renderChildren(StringBuilder buf) {
202       List<Node> list = mChildren;
203       if (list == null || list.size() == 0) {
204         // We output null for no children. That way empty lists here can just
205         // be a byproduct of how we generate the lists.
206         buf.append("null");
207       } else {
208         buf.append("[ ");
209         final int N = list.size();
210         for (int i = 0; i < N; i++) {
211           list.get(i).render(buf);
212           if (i != N - 1) {
213             buf.append(", ");
214           }
215         }
216         buf.append(" ]\n");
217       }
218     }
219 
render(StringBuilder buf)220     void render(StringBuilder buf) {
221       buf.append("[ ");
222       renderString(buf, mLabel);
223       buf.append(", ");
224       renderString(buf, mLink);
225       buf.append(", ");
226       renderChildren(buf);
227       buf.append(", ");
228       renderString(buf, mSince);
229       buf.append(" ]");
230     }
231   }
232 }
233