blob: 88c36dc37a02f0291147779a39998b79f932c253 [file] [log] [blame]
Ben Dodson920dbbb2010-08-04 15:21:06 -07001/*
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
17package com.google.doclava;
Ben Dodson920dbbb2010-08-04 15:21:06 -070018import com.google.clearsilver.jsilver.data.Data;
19
20import java.util.*;
21import java.io.*;
Dirk Doughertye52f6d82013-09-04 17:27:29 -070022import java.util.regex.Pattern;
23import java.util.regex.Matcher;
Ben Dodson920dbbb2010-08-04 15:21:06 -070024
25public class SampleCode {
26 String mSource;
27 String mDest;
28 String mTitle;
Dirk Doughertyc11a4672013-08-23 19:14:10 -070029 String mProjectDir;
Dirk Dougherty25586c02013-08-30 16:21:15 -070030 String mTags;
Ben Dodson920dbbb2010-08-04 15:21:06 -070031
32 public SampleCode(String source, String dest, String title) {
33 mSource = source;
34 mTitle = title;
Dirk Dougherty25586c02013-08-30 16:21:15 -070035 mTags = null;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070036
Dirk Dougherty815f9342013-09-12 00:30:28 -070037 if (dest != null) {
38 int len = dest.length();
39 if (len > 1 && dest.charAt(len - 1) != '/') {
40 mDest = dest + '/';
41 } else {
42 mDest = dest;
43 }
Ben Dodson920dbbb2010-08-04 15:21:06 -070044 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070045 //System.out.println("SampleCode init: source: " + mSource);
46 //System.out.println("SampleCode init: dest: " + mDest);
47 //System.out.println("SampleCode init: title: " + mTitle);
48
Ben Dodson920dbbb2010-08-04 15:21:06 -070049 }
50
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070051 public Node write(boolean offlineMode) {
52 List<Node> filelist = new ArrayList<Node>();
Ben Dodson920dbbb2010-08-04 15:21:06 -070053 File f = new File(mSource);
Dirk Doughertyc11a4672013-08-23 19:14:10 -070054 mProjectDir = f.getName();
55 String name = mProjectDir;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070056 String startname = name;
57 String subdir = mDest;
58 String mOut = subdir + name;
Ben Dodson920dbbb2010-08-04 15:21:06 -070059 if (!f.isDirectory()) {
60 System.out.println("-samplecode not a directory: " + mSource);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070061 return null;
Ben Dodson920dbbb2010-08-04 15:21:06 -070062 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070063
64 if (offlineMode)
65 writeIndexOnly(f, mDest, offlineMode);
66 else {
67 Data hdf = Doclava.makeHDF();
68 hdf.setValue("samples", "true");
Dirk Doughertyc11a4672013-08-23 19:14:10 -070069 hdf.setValue("projectDir", mProjectDir);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070070 writeProjectDirectory(filelist, f, mDest, false, hdf, "Files.");
Dirk Doughertyc11a4672013-08-23 19:14:10 -070071 writeProjectStructure(name, hdf);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070072 hdf.removeTree("parentdirs");
73 hdf.setValue("parentdirs.0.Name", name);
Dirk Doughertye52f6d82013-09-04 17:27:29 -070074 //Write root _index.jd to out and add metadata to Node.
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -070075 Node rootNode = writeProjectIndexCs(hdf, f, null,
76 new Node.Builder().setLabel(mProjectDir).setLink("samples/"
77 + startname + "/index.html").setChildren(filelist).build());
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070078 // return a root SC node for the sample with children appended
Dirk Doughertye52f6d82013-09-04 17:27:29 -070079 return rootNode;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070080 }
81 return null;
Ben Dodson920dbbb2010-08-04 15:21:06 -070082 }
83
84 public static String convertExtension(String s, String ext) {
85 return s.substring(0, s.lastIndexOf('.')) + ext;
86 }
87
88 public static String[] IMAGES = {".png", ".jpg", ".gif"};
Dirk Dougherty35427702013-11-18 15:22:01 -080089 public static String[] VIDEOS = {".mp4", ".ogv", ".webm"};
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070090 public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"};
Ben Dodson920dbbb2010-08-04 15:21:06 -070091
92 public static boolean inList(String s, String[] list) {
93 for (String t : list) {
94 if (s.endsWith(t)) {
95 return true;
96 }
97 }
98 return false;
99 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700100
101 public static String mapTypes(String name) {
102 String type = name.substring(name.lastIndexOf('.') + 1, name.length());
Dirk Dougherty187b9852013-11-23 12:05:36 -0800103 if ("xml".equals(type) || "java".equals(type)) {
104 if ("AndroidManifest.xml".equals(name)) type = "manifest";
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700105 return type;
106 } else {
107 return type = "file";
108 }
109 }
110
111 public void writeProjectDirectory(List<Node> parent, File dir, String relative, Boolean recursed, Data hdf, String newkey) {
112 TreeSet<String> dirs = new TreeSet<String>(); //dirs for project structure and breadcrumb
113 TreeSet<String> files = new TreeSet<String>(); //files for project structure and breadcrumb
114
115 String subdir = relative;
116 String name = "";
117 String label = "";
118 String link = "";
119 String type = "";
120 int i = 0;
121 String expansion = ".Sub.";
122 String key = newkey;
Dirk Dougherty35427702013-11-18 15:22:01 -0800123 double maxFileSizeBytes = 2097152; //Max size for browseable images/video
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700124
125 if (recursed) {
126 key = (key + expansion);
127 } else {
128 expansion = "";
129 }
130
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700131 File[] dirContents = dir.listFiles();
132 Arrays.sort(dirContents, byTypeAndName);
133 for (File f: dirContents) {
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700134 name = f.getName();
135 // don't process certain types of files
136 if (name.startsWith(".") ||
137 name.startsWith("_") ||
Dirk Dougherty187b9852013-11-23 12:05:36 -0800138 "default.properties".equals(name) ||
139 "build.properties".equals(name) ||
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700140 name.endsWith(".ttf") ||
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700141 name.endsWith(".gradle") ||
142 name.endsWith(".bat") ||
Dirk Dougherty187b9852013-11-23 12:05:36 -0800143 "Android.mk".equals(name)) {
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700144 //System.out.println("Invalid File Type, bypassing: " + name);
145 continue;
146 }
147 if (f.isFile() && name.contains(".")){
148 String path = relative + name;
149 type = mapTypes(name);
150 link = convertExtension(path, ".html");
151 hdf.setValue("samples", "true");//dd needed?
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700152 if (inList(path, IMAGES)) {
153 // copy these files to output directly
154 type = "img";
Dirk Dougherty35427702013-11-18 15:22:01 -0800155 if (f.length() < maxFileSizeBytes) {
156 ClearPage.copyFile(false, f, path);
157 writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
158 relative, type, true);
159 } else {
160 //too large for browsing, skip copying and show generic icon
161 writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
162 relative, type, false);
163 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700164 files.add(name);
165 hdf.setValue(key + i + ".Type", "img");
166 hdf.setValue(key + i + ".Name", name);
167 hdf.setValue(key + i + ".Href", link);
Dirk Dougherty25586c02013-08-30 16:21:15 -0700168 hdf.setValue(key + i + ".RelPath", relative);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700169 }
Dirk Dougherty35427702013-11-18 15:22:01 -0800170 if (inList(path, VIDEOS)) {
171 // copy these files to output directly
172 type = "video";
173 if (f.length() < maxFileSizeBytes) {
174 ClearPage.copyFile(false, f, path);
175 writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
176 relative, type, true);
177 } else {
178 //too large for browsing, skip copying and show generic icon
179 writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
180 relative, type, false);
181 }
182 files.add(name);
183 hdf.setValue(key + i + ".Type", "video");
184 hdf.setValue(key + i + ".Name", name);
185 hdf.setValue(key + i + ".Href", link);
186 hdf.setValue(key + i + ".RelPath", relative);
187 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700188 if (inList(path, TEMPLATED)) {
189 // copied and goes through the template
190 ClearPage.copyFile(false, f, path);
191 writePage(f, convertExtension(path, Doclava.htmlExtension), relative);
192 files.add(name);
193 hdf.setValue(key + i + ".Type", type);
194 hdf.setValue(key + i + ".Name", name);
195 hdf.setValue(key + i + ".Href", link);
Dirk Dougherty25586c02013-08-30 16:21:15 -0700196 hdf.setValue(key + i + ".RelPath", relative);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700197 }
198 // add file to the navtree
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700199 parent.add(new Node.Builder().setLabel(name).setLink(link).setType(type).build());
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700200 i++;
201 } else if (f.isDirectory()) {
202 List<Node> mchildren = new ArrayList<Node>();
203 type = "dir";
204 String dirpath = relative + name;
205 link = dirpath + "/index.html";
206 String hdfkeyName = (key + i + ".Name");
207 String hdfkeyType = (key + i + ".Type");
208 String hdfkeyHref = (key + i + ".Href");
209 hdf.setValue(hdfkeyName, name);
210 hdf.setValue(hdfkeyType, type);
211 hdf.setValue(hdfkeyHref, relative + name + "/" + "index.html");
212 //System.out.println("Found directory, recursing. Current key: " + hdfkeyName);
213 writeProjectDirectory(mchildren, f, relative + name + "/", true, hdf, (key + i));
214 if (mchildren.size() > 0) {
215 //dir is processed, now add it to the navtree
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700216 //don't link sidenav subdirs at this point (but can use "link" to do so)
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700217 parent.add(new Node.Builder().setLabel(name).setChildren(mchildren).setType(type).build());
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700218 }
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700219 dirs.add(name);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700220 i++;
221 }
Dirk Dougherty25586c02013-08-30 16:21:15 -0700222
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700223 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700224 //If this is an index for the project root (assumed root if split length is 3 (development/samples/nn)),
225 //then remove the root dir so that it won't appear in the breadcrumb. Else just pass it through to
226 //setParentDirs as usual.
227 String mpath = dir + "";
228 String sdir[] = mpath.split("/");
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700229 setParentDirs(hdf, relative, name, false);
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700230 //Generate an index.html page for each dir being processed
231 ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
232 //concatenate dirs in the navtree. Comment out or remove to restore normal navtree
Dirk Dougherty25586c02013-08-30 16:21:15 -0700233 squashNodes(parent);
Scott Maine27c9502011-01-19 14:07:39 -0800234 }
235
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700236 public void writeProjectStructure(String dir, Data hdf) {
237 //System.out.println(">>-- writing project structure for " + dir );
238 hdf.setValue("projectStructure", "true");
239 hdf.setValue("projectDir", mProjectDir);
240 hdf.setValue("page.title", mProjectDir + " Structure");
241 hdf.setValue("projectTitle", mTitle);
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700242 //write the project.html file
243 ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700244 hdf.setValue("projectStructure", "");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700245 }
246
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700247 /**
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700248 * Processes a templated project index page from _index.jd in a project root.
249 * Each sample project must have an index, and each index locally defines it's own
250 * page.tags and sample.group cs vars. This method takes a SC node on input, reads
251 * any local vars from the _index.jd, generates an html file to out, then updates
252 * the SC node with the page vars and returns it to the caller.
253 *
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700254 */
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700255 public Node writeProjectIndexCs(Data hdf, File dir, String key, Node tnode) {
256 //hdf.setValue("summary", "");
257 //hdf.setValue("summaryFlag", "");
258 String filename = dir.getAbsolutePath() + "/_index.jd";
259 File f = new File(filename);
260 String rel = dir.getPath();
261 String mGroup = "";
262 hdf.setValue("samples", "true");
263 //set any default page variables for root index
264 hdf.setValue("page.title", mProjectDir);
Dirk Dougherty25586c02013-08-30 16:21:15 -0700265 hdf.setValue("projectDir", mProjectDir);
Dirk Dougherty25586c02013-08-30 16:21:15 -0700266 hdf.setValue("projectTitle", mTitle);
Dirk Dougherty35427702013-11-18 15:22:01 -0800267 //add the download/project links to the landing pages.
268 hdf.setValue("samplesProjectIndex", "true");
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700269
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700270 if (!f.isFile()) {
271 //The sample didn't have any _index.jd, so create a stub.
272 ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
273 //Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
274 // + ": Root _index.jd must be present and must define sample.group"
275 // + " tag. Please see ... for details.");
276 } else {
277 DocFile.writePage(filename, rel, mDest + "index" + Doclava.htmlExtension, hdf);
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700278 PageMetadata.setPageMetadata(f, rel, mDest + "index" + Doclava.htmlExtension, hdf, Doclava.sTaglist);
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700279 tnode.setTags(hdf.getValue("page.tags", ""));
280 mGroup = hdf.getValue("sample.group", "");
281 if (mGroup.equals("")) {
282 //Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
283 // + ": Root _index.jd must be present and must define sample.group"
284 // + " tag. Please see ... for details.");
285 } else {
286 tnode.setGroup(hdf.getValue("sample.group", ""));
287 }
288 }
289 return tnode;
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700290 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700291
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700292 /**
293 * Keep track of file parents
294 */
295 Data setParentDirs(Data hdf, String subdir, String name, Boolean isFile) {
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700296 //set whether to linkify the crumb dirs on each sample code page
297 hdf.setValue("pathCrumbLinks", "");
298 //isFile = false;
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700299 int iter;
300 hdf.removeTree("parentdirs");
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700301 String s = subdir;
302 String urlParts[] = s.split("/");
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700303 //int n, l = (isFile)?1:0;
304 int n, l = 1;
305 //System.out.println("setParentDirs for " + subdir + name);
306 for (iter=1; iter < urlParts.length; iter++) {
307 n = iter-1;
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700308 //System.out.println("parentdirs." + n + ".Name == " + urlParts[iter]);
309 hdf.setValue("parentdirs." + n + ".Name", urlParts[iter]);
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700310 hdf.setValue("parentdirs." + n + ".Link", subdir + "index" + Doclava.htmlExtension);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700311 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700312 return hdf;
313 }
314
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700315 /**
316 * Write a templated source code file to out.
317 */
Ben Dodson920dbbb2010-08-04 15:21:06 -0700318 public void writePage(File f, String out, String subdir) {
319 String name = f.getName();
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700320 String path = f.getPath();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700321 String data =
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700322 SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path, "sample code",
323 true, true, true, true);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700324 data = Doclava.escape(data);
325
326 Data hdf = Doclava.makeHDF();
Dirk Dougherty25586c02013-08-30 16:21:15 -0700327
328 String relative = subdir.replaceFirst("samples/", "");
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700329 hdf.setValue("samples", "true");
330 setParentDirs(hdf, subdir, name, true);
331 hdf.setValue("projectTitle", mTitle);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700332 hdf.setValue("projectDir", mProjectDir);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700333 hdf.setValue("page.title", name);
334 hdf.setValue("subdir", subdir);
Dirk Dougherty25586c02013-08-30 16:21:15 -0700335 hdf.setValue("relative", relative);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700336 hdf.setValue("realFile", name);
337 hdf.setValue("fileContents", data);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700338 hdf.setValue("resTag", "sample");
339 hdf.setValue("resType", "Sample Code");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700340
341 ClearPage.write(hdf, "sample.cs", out);
342 }
343
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700344 /**
Dirk Dougherty35427702013-11-18 15:22:01 -0800345 * Write a templated image or video file to out.
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700346 */
Dirk Dougherty35427702013-11-18 15:22:01 -0800347 public void writeImageVideoPage(File f, String out, String subdir,
348 String resourceType, boolean browsable) {
Ben Dodson920dbbb2010-08-04 15:21:06 -0700349 Data hdf = Doclava.makeHDF();
Dirk Dougherty35427702013-11-18 15:22:01 -0800350 String name = f.getName();
351 if (!browsable) {
352 hdf.setValue("noDisplay", "true");
353 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700354 setParentDirs(hdf, subdir, name, true);
Dirk Dougherty35427702013-11-18 15:22:01 -0800355 hdf.setValue("samples", "true");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700356 hdf.setValue("page.title", name);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700357 hdf.setValue("projectTitle", mTitle);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700358 hdf.setValue("projectDir", mProjectDir);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700359 hdf.setValue("subdir", subdir);
Dirk Dougherty35427702013-11-18 15:22:01 -0800360 hdf.setValue("resType", resourceType);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700361 hdf.setValue("realFile", name);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700362 ClearPage.write(hdf, "sample.cs", out);
363 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700364
365 /**
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700366 * Render a SC node tree to a navtree js file.
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700367 */
Dirk Dougherty815f9342013-09-12 00:30:28 -0700368 public static void writeSamplesNavTree(List<Node> tnode, List<Node> groupnodes) {
369
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700370 Node node = new
371 Node.Builder().setLabel("Reference").setLink("packages.html").setChildren(tnode).build();
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700372
Dirk Dougherty815f9342013-09-12 00:30:28 -0700373 if (groupnodes != null) {
374 for (int i = 0; i < tnode.size(); i++) {
Dirk Dougherty187b9852013-11-23 12:05:36 -0800375 if (tnode.get(i) != null) {
376 groupnodes = appendNodeGroups(tnode.get(i), groupnodes);
377 }
Dirk Dougherty815f9342013-09-12 00:30:28 -0700378 }
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700379 for (int n = 0; n < groupnodes.size(); n++) {
380 if (groupnodes.get(n).getChildren() == null) {
381 groupnodes.remove(n);
382 n--;
383 }
384 }
Dirk Dougherty815f9342013-09-12 00:30:28 -0700385 node.setChildren(groupnodes);
386 }
387
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700388 StringBuilder buf = new StringBuilder();
389 if (false) {
390 // if you want a root node
391 buf.append("[");
392 node.render(buf);
393 buf.append("]");
394 } else {
395 // if you don't want a root node
396 node.renderChildren(buf);
397 }
398
399 Data data = Doclava.makeHDF();
400 data.setValue("reference_tree", buf.toString());
401 ClearPage.write(data, "samples_navtree_data.cs", "samples_navtree_data.js");
402 }
403
Dirk Dougherty25586c02013-08-30 16:21:15 -0700404 /**
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700405 * For a given project root node, get the group and then iterate the list of valid
406 * groups looking for a match. If found, append the project to that group node.
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700407 * Samples that reference a valid sample group tag are added to a list for that
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700408 * group. Samples declare a sample.group tag in their _index.jd files.
Dirk Dougherty815f9342013-09-12 00:30:28 -0700409 */
410 private static List<Node> appendNodeGroups(Node gNode, List<Node> groupnodes) {
411 List<Node> mgrouplist = new ArrayList<Node>();
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700412 for (int i = 0; i < groupnodes.size(); i++) {
Dirk Dougherty187b9852013-11-23 12:05:36 -0800413 if (gNode.getGroup().equals(groupnodes.get(i).getLabel())) {
Dirk Dougherty815f9342013-09-12 00:30:28 -0700414 if (groupnodes.get(i).getChildren() == null) {
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700415 mgrouplist.add(gNode);
Dirk Dougherty815f9342013-09-12 00:30:28 -0700416 groupnodes.get(i).setChildren(mgrouplist);
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700417 } else {
418 groupnodes.get(i).getChildren().add(gNode);
Dirk Dougherty815f9342013-09-12 00:30:28 -0700419 }
Dirk Dougherty815f9342013-09-12 00:30:28 -0700420 break;
Dirk Dougherty1d8fa8d2013-09-12 19:01:02 -0700421 }
Dirk Dougherty815f9342013-09-12 00:30:28 -0700422 }
423 return groupnodes;
424 }
425
426 /**
Dirk Dougherty25586c02013-08-30 16:21:15 -0700427 * Sort by type and name (alpha), with manifest and src always at top.
428 */
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700429 Comparator<File> byTypeAndName = new Comparator<File>() {
430 public int compare (File one, File other) {
431 if (one.isDirectory() && !other.isDirectory()) {
432 return 1;
433 } else if (!one.isDirectory() && other.isDirectory()) {
434 return -1;
Dirk Dougherty187b9852013-11-23 12:05:36 -0800435 } else if ("AndroidManifest.xml".equals(one.getName())) {
Dirk Dougherty25586c02013-08-30 16:21:15 -0700436 return -1;
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700437 } else {
438 return one.compareTo(other);
439 }
440 }
441 };
442
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700443 /**
Dirk Dougherty25586c02013-08-30 16:21:15 -0700444 * Concatenate dirs that only hold dirs to simplify nav tree
445 */
Dirk Dougherty815f9342013-09-12 00:30:28 -0700446 public static List<Node> squashNodes(List<Node> tnode) {
Dirk Dougherty25586c02013-08-30 16:21:15 -0700447 List<Node> list = tnode;
448
449 for(int i = 0; i < list.size(); ++i) {
450 //only squash dirs that contain another dir whose list size is 1 and
451 //that don't contain endpoints
Dirk Dougherty187b9852013-11-23 12:05:36 -0800452 if (("dir".equals(list.get(i).getType())) &&
Dirk Dougherty25586c02013-08-30 16:21:15 -0700453 (list.size() == 1) &&
454 (list.get(i).getChildren().get(0).getChildren() != null)) {
455 String thisLabel = list.get(i).getLabel();
456 String childLabel = list.get(i).getChildren().get(0).getLabel();
457 String newLabel = thisLabel + "/" + childLabel;
458 //Set label of parent and mChildren to those of child-child, skipping
459 //squashed dir
460 list.get(i).setLabel(newLabel);
461 list.get(i).setChildren(list.get(i).getChildren().get(0).getChildren());
462 } else {
463 continue;
464 }
465 }
466 return list;
467 }
468
469 /**
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700470 * SampleCode variant of NavTree node.
471 */
472 public static class Node {
473 private String mLabel;
474 private String mLink;
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700475 private String mGroup; // from sample.group in _index.jd
476 private List<String> mTags; // from page.tags in _index.jd
Dirk Dougherty25586c02013-08-30 16:21:15 -0700477 private List<Node> mChildren;
478 private String mType;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700479
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700480 private Node(Builder builder) {
481 mLabel = builder.mLabel;
482 mLink = builder.mLink;
483 mGroup = builder.mGroup;
484 mTags = builder.mTags;
485 mChildren = builder.mChildren;
486 mType = builder.mType;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700487 }
488
Dirk Doughertyf9d9cb02013-09-13 19:45:17 -0700489 public static class Builder {
490 private String mLabel, mLink, mGroup, mType;
491 private List<String> mTags = null;
492 private List<Node> mChildren = null;
493 public Builder setLabel(String mLabel) { this.mLabel = mLabel; return this;}
494 public Builder setLink(String mLink) { this.mLink = mLink; return this;}
495 public Builder setGroup(String mGroup) { this.mGroup = mGroup; return this;}
496 public Builder setTags(List<String> mTags) { this.mTags = mTags; return this;}
497 public Builder setChildren(List<Node> mChildren) { this.mChildren = mChildren; return this;}
498 public Builder setType(String mType) { this.mType = mType; return this;}
499 public Node build() {return new Node(this);}
500 }
501
502 public Node(String mLabel,
503 String mLink,
504 String mGroup,
505 List<String> mTags,
506 List<Node> mChildren,
507 String mType) {
508 this.mLabel = mLabel;
509 this.mLink = mLink;
510 this.mGroup = mGroup;
511 this.mTags = mTags;
512 this.mChildren = mChildren;
513 this.mType = mType; }
514
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700515 static void renderString(StringBuilder buf, String s) {
516 if (s == null) {
517 buf.append("null");
518 } else {
519 buf.append('"');
520 final int N = s.length();
521 for (int i = 0; i < N; i++) {
522 char c = s.charAt(i);
523 if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
524 buf.append(c);
525 } else {
526 buf.append("\\u");
527 for (int j = 0; i < 4; i++) {
528 char x = (char) (c & 0x000f);
529 if (x > 10) {
530 x = (char) (x - 10 + 'a');
531 } else {
532 x = (char) (x + '0');
533 }
534 buf.append(x);
535 c >>= 4;
536 }
537 }
538 }
539 buf.append('"');
540 }
541 }
542
543 void renderChildren(StringBuilder buf) {
544 List<Node> list = mChildren;
545 if (list == null || list.size() == 0) {
546 // We output null for no children. That way empty lists here can just
547 // be a byproduct of how we generate the lists.
548 buf.append("null");
549 } else {
550 buf.append("[ ");
551 final int N = list.size();
552 for (int i = 0; i < N; i++) {
553 list.get(i).render(buf);
554 if (i != N - 1) {
555 buf.append(", ");
556 }
557 }
558 buf.append(" ]\n");
559 }
560 }
561
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700562 void renderTags(StringBuilder buf) {
563 List<String> list = mTags;
564 if (list == null || list.size() == 0) {
565 buf.append("null");
566 } else {
567 buf.append("[ ");
568 final int N = list.size();
569 for (int i = 0; i < N; i++) {
570 String tagval = list.get(i).toString();
571 buf.append('"');
572 final int L = tagval.length();
573 for (int t = 0; t < L; t++) {
574 char c = tagval.charAt(t);
575 if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
576 buf.append(c);
577 } else {
578 buf.append("\\u");
579 for (int m = 0; m < 4; m++) {
580 char x = (char) (c & 0x000f);
581 if (x > 10) {
582 x = (char) (x - 10 + 'a');
583 } else {
584 x = (char) (x + '0');
585 }
586 buf.append(x);
587 c >>= 4;
588 }
589 }
590 }
591 buf.append('"');
592 if (i != N - 1) {
593 buf.append(", ");
594 }
595 }
596 buf.append(" ]");
597 }
598 }
599
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700600 void render(StringBuilder buf) {
601 buf.append("[ ");
602 renderString(buf, mLabel);
603 buf.append(", ");
604 renderString(buf, mLink);
605 buf.append(", ");
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700606 renderString(buf, mGroup);
607 buf.append(", ");
608 renderTags(buf);
609 buf.append(", ");
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700610 renderChildren(buf);
611 buf.append(", ");
612 renderString(buf, mType);
613 buf.append(" ]");
614 }
Dirk Dougherty25586c02013-08-30 16:21:15 -0700615
616 public List<Node> getChildren() {
617 if (mChildren != null) {
618 return mChildren;
619 } else {
620 return null;
621 }
622 }
623
624 public void setChildren(List<Node> node) {
625 mChildren = node;
626 }
627
628 public String getLabel() {
629 return mLabel;
630 }
631
632 public void setLabel(String label) {
633 mLabel = label;
634 }
635
636 public String getType() {
637 return mType.toString();
638 }
639
640 public String getHref() {
641 return mLink;
642 }
643
644 public void setHref(String link) {
645 mLink = link;
646 }
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700647
Dirk Dougherty815f9342013-09-12 00:30:28 -0700648 public String getGroup() {
649 return mGroup;
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700650 }
651
Dirk Dougherty815f9342013-09-12 00:30:28 -0700652 public void setGroup(String group) {
653 mGroup = group;
Dirk Doughertye52f6d82013-09-04 17:27:29 -0700654 }
655
656 public void setTags(String tags) {
657 List<String> tagList = new ArrayList();
658 String[] tagParts = tags.split(",");
659
660 for (int iter = 0; iter < tagParts.length; iter++) {
661 String item = tagParts[iter].replaceAll("\"", "").trim();
662 tagList.add(item);
663 }
664 mTags = tagList;
665 }
666 }
667
668 /**
669 * Write the project's templated _index.html
670 * @deprecated
671 *
672 */
673 public void writeProjectIndex(Data hdf) {
674 //System.out.println(">>-- writing project index for " + mDest );
675 hdf.setValue("projectDir", mProjectDir);
676 hdf.setValue("page.title", mProjectDir + " Sample");
677 hdf.setValue("projectTitle", mTitle);
678 ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
679 }
680
681 /**
682 * Grab the contents of an _index.html summary from a dir.
683 * @deprecated
684 */
685 public void getSummaryFromDir(Data hdf, File dir, String key) {
686 //System.out.println("Getting summary for " + dir + "/_index.html");
687 hdf.setValue("summary", "");
688 hdf.setValue("summaryFlag", "");
689 String filename = dir.getPath() + "/_index.html";
690 String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename,
691 -1,-1), filename, "sample code", true, false, false, true);
692 if (summary != null) {
693 hdf.setValue(key + "SummaryFlag", "true");
694 hdf.setValue("summary", summary);
695 //set the target for [info] link
696 //hdf.setValue(key + "Href", dir + "/index.html");
697 //return true;
698 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700699 }
700
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700701 /**
702 * @deprecated
703 */
704 public void writeDirectory(File dir, String relative, boolean offline) {
705 TreeSet<String> dirs = new TreeSet<String>();
706 TreeSet<String> files = new TreeSet<String>();
707
708 String subdir = relative; // .substring(mDest.length());
709
710 for (File f : dir.listFiles()) {
711 String name = f.getName();
712 if (name.startsWith(".") || name.startsWith("_")) {
713 continue;
714 }
715 if (f.isFile()) {
716 String out = relative + name;
717 if (inList(out, IMAGES)) {
718 // copied directly
719 ClearPage.copyFile(false, f, out);
720 writeImagePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
721 files.add(name);
722 }
723 if (inList(out, TEMPLATED)) {
724 // copied and goes through the template
725 ClearPage.copyFile(false, f, out);
726 writePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
727 files.add(name);
728
729 }
730 // else ignored
731 } else if (f.isDirectory()) {
732 writeDirectory(f, relative + name + "/", offline);
733 dirs.add(name);
734 }
735 }
736
737 // write the index page
738 int i;
739
740 Data hdf = writeIndex(dir);
741 hdf.setValue("subdir", subdir);
742 i = 0;
743 for (String d : dirs) {
744 hdf.setValue("subdirs." + i + ".Name", d);
745 hdf.setValue("files." + i + ".Href", convertExtension(d, ".html"));
746 i++;
747 }
748 i = 0;
749 for (String f : files) {
750 hdf.setValue("files." + i + ".Name", f);
751 hdf.setValue("files." + i + ".Href", convertExtension(f, ".html"));
752 i++;
753 }
754
755 if (!offline) relative = "/" + relative;
756 ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
757 }
758
759 /**
760 * @deprecated
761 */
762 public void writeIndexOnly(File dir, String relative, Boolean offline) {
763 Data hdf = writeIndex(dir);
764 if (!offline) relative = "/" + relative;
765
766 System.out.println("writing indexonly at " + relative + "/index" + Doclava.htmlExtension);
767 ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
768 }
769
770 /**
771 * @deprecated
772 */
773 public Data writeIndex(File dir) {
774 Data hdf = Doclava.makeHDF();
775 hdf.setValue("page.title", dir.getName() + " - " + mTitle);
776 hdf.setValue("projectTitle", mTitle);
777
778 String filename = dir.getPath() + "/_index.html";
779 String summary =
780 SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code",
781 true, false, false, true);
782
783 if (summary == null) {
784 summary = "";
785 }
786 hdf.setValue("summary", summary);
787
788 return hdf;
789 }
790
Dirk Dougherty35427702013-11-18 15:22:01 -0800791 /**
792 * @deprecated
793 */
794 public void writeImagePage(File f, String out, String subdir) {
795 Data hdf = Doclava.makeHDF();
796 String name = f.getName();
797
798 hdf.setValue("samples", "true");
799 setParentDirs(hdf, subdir, name, true);
800 hdf.setValue("page.title", name);
801 hdf.setValue("projectTitle", mTitle);
802 hdf.setValue("projectDir", mProjectDir);
803 hdf.setValue("subdir", subdir);
804 hdf.setValue("realFile", name);
805 hdf.setValue("resTag", "sample");
806 hdf.setValue("resType", "sampleImage");
807 ClearPage.write(hdf, "sample.cs", out);
808 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700809}