blob: ba301f4764c76c595ea4ea952eabeb2a5ac928e4 [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.*;
22
23
24public class SampleCode {
25 String mSource;
26 String mDest;
27 String mTitle;
Dirk Doughertyc11a4672013-08-23 19:14:10 -070028 String mProjectDir;
Ben Dodson920dbbb2010-08-04 15:21:06 -070029
30 public SampleCode(String source, String dest, String title) {
31 mSource = source;
32 mTitle = title;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070033
Ben Dodson920dbbb2010-08-04 15:21:06 -070034 int len = dest.length();
35 if (len > 1 && dest.charAt(len - 1) != '/') {
36 mDest = dest + '/';
37 } else {
38 mDest = dest;
39 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070040
Dirk Doughertyc11a4672013-08-23 19:14:10 -070041
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070042 //System.out.println("SampleCode init: source: " + mSource);
43 //System.out.println("SampleCode init: dest: " + mDest);
44 //System.out.println("SampleCode init: title: " + mTitle);
45
Ben Dodson920dbbb2010-08-04 15:21:06 -070046 }
47
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070048 public Node write(boolean offlineMode) {
49 List<Node> filelist = new ArrayList<Node>();
Ben Dodson920dbbb2010-08-04 15:21:06 -070050 File f = new File(mSource);
Dirk Doughertyc11a4672013-08-23 19:14:10 -070051 mProjectDir = f.getName();
52 String name = mProjectDir;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070053 String startname = name;
54 String subdir = mDest;
55 String mOut = subdir + name;
Ben Dodson920dbbb2010-08-04 15:21:06 -070056 if (!f.isDirectory()) {
57 System.out.println("-samplecode not a directory: " + mSource);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070058 return null;
Ben Dodson920dbbb2010-08-04 15:21:06 -070059 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070060
61 if (offlineMode)
62 writeIndexOnly(f, mDest, offlineMode);
63 else {
64 Data hdf = Doclava.makeHDF();
65 hdf.setValue("samples", "true");
Dirk Doughertyc11a4672013-08-23 19:14:10 -070066 hdf.setValue("projectDir", mProjectDir);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070067 writeProjectDirectory(filelist, f, mDest, false, hdf, "Files.");
Dirk Doughertyc11a4672013-08-23 19:14:10 -070068 writeProjectStructure(name, hdf);
69 getSummaryFromDir(hdf, f, "Files.");
70 writeProjectIndex(hdf);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070071 hdf.removeTree("parentdirs");
72 hdf.setValue("parentdirs.0.Name", name);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070073 // return a root SC node for the sample with children appended
Dirk Doughertyc11a4672013-08-23 19:14:10 -070074 return new Node(mProjectDir, "samples/" + startname + "/index.html", filelist, null);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070075 }
76 return null;
Ben Dodson920dbbb2010-08-04 15:21:06 -070077 }
78
79 public static String convertExtension(String s, String ext) {
80 return s.substring(0, s.lastIndexOf('.')) + ext;
81 }
82
83 public static String[] IMAGES = {".png", ".jpg", ".gif"};
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070084 public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"};
Ben Dodson920dbbb2010-08-04 15:21:06 -070085
86 public static boolean inList(String s, String[] list) {
87 for (String t : list) {
88 if (s.endsWith(t)) {
89 return true;
90 }
91 }
92 return false;
93 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -070094
95 public static String mapTypes(String name) {
96 String type = name.substring(name.lastIndexOf('.') + 1, name.length());
97 if (type.equals("xml") || type.equals("java")) {
98 if (name.equals("AndroidManifest.xml")) type = "manifest";
99 return type;
100 } else {
101 return type = "file";
102 }
103 }
104
105 public void writeProjectDirectory(List<Node> parent, File dir, String relative, Boolean recursed, Data hdf, String newkey) {
106 TreeSet<String> dirs = new TreeSet<String>(); //dirs for project structure and breadcrumb
107 TreeSet<String> files = new TreeSet<String>(); //files for project structure and breadcrumb
108
109 String subdir = relative;
110 String name = "";
111 String label = "";
112 String link = "";
113 String type = "";
114 int i = 0;
115 String expansion = ".Sub.";
116 String key = newkey;
117
118 if (recursed) {
119 key = (key + expansion);
120 } else {
121 expansion = "";
122 }
123
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700124 File[] dirContents = dir.listFiles();
125 Arrays.sort(dirContents, byTypeAndName);
126 for (File f: dirContents) {
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700127 name = f.getName();
128 // don't process certain types of files
129 if (name.startsWith(".") ||
130 name.startsWith("_") ||
131 name.equals("default.properties") ||
132 name.equals("build.properties") ||
133 name.endsWith(".ttf") ||
134 name.equals("Android.mk")) {
135 //System.out.println("Invalid File Type, bypassing: " + name);
136 continue;
137 }
138 if (f.isFile() && name.contains(".")){
139 String path = relative + name;
140 type = mapTypes(name);
141 link = convertExtension(path, ".html");
142 hdf.setValue("samples", "true");//dd needed?
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700143 if (inList(path, IMAGES)) {
144 // copy these files to output directly
145 type = "img";
146 ClearPage.copyFile(false, f, path);
147 writeImagePage(f, convertExtension(path, Doclava.htmlExtension), relative);
148 files.add(name);
149 hdf.setValue(key + i + ".Type", "img");
150 hdf.setValue(key + i + ".Name", name);
151 hdf.setValue(key + i + ".Href", link);
152 }
153 if (inList(path, TEMPLATED)) {
154 // copied and goes through the template
155 ClearPage.copyFile(false, f, path);
156 writePage(f, convertExtension(path, Doclava.htmlExtension), relative);
157 files.add(name);
158 hdf.setValue(key + i + ".Type", type);
159 hdf.setValue(key + i + ".Name", name);
160 hdf.setValue(key + i + ".Href", link);
161 }
162 // add file to the navtree
163 parent.add(new Node(name, link , null, type));
164 i++;
165 } else if (f.isDirectory()) {
166 List<Node> mchildren = new ArrayList<Node>();
167 type = "dir";
168 String dirpath = relative + name;
169 link = dirpath + "/index.html";
170 String hdfkeyName = (key + i + ".Name");
171 String hdfkeyType = (key + i + ".Type");
172 String hdfkeyHref = (key + i + ".Href");
173 hdf.setValue(hdfkeyName, name);
174 hdf.setValue(hdfkeyType, type);
175 hdf.setValue(hdfkeyHref, relative + name + "/" + "index.html");
176 //System.out.println("Found directory, recursing. Current key: " + hdfkeyName);
177 writeProjectDirectory(mchildren, f, relative + name + "/", true, hdf, (key + i));
178 if (mchildren.size() > 0) {
179 //dir is processed, now add it to the navtree
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700180 //don't link sidenav subdirs at this point (but can use "link" to do so)
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700181 parent.add(new Node(name, null, mchildren, type));
182 }
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700183 dirs.add(name);
184
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700185 i++;
186 }
187 }
188 //dd not working yet
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700189 //Get summary from any _index files in any project dirs (currently disabled)
190 // getSummaryFromDir(hdf, dir, newkey);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700191 //If this is an index for the project root (assumed root if split length is 3 (development/samples/nn)),
192 //then remove the root dir so that it won't appear in the breadcrumb. Else just pass it through to
193 //setParentDirs as usual.
194 String mpath = dir + "";
195 String sdir[] = mpath.split("/");
196 if (sdir.length == 3 ) {
197 System.out.println("-----------------> this must be the root: [sdir len]" + sdir.length + "[dir]" + dir);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700198 hdf.setValue("showProjectPaths","true");//dd remove here?
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700199 }
200 setParentDirs(hdf, relative, name, false);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700201 //System.out.println("writing sample index -- " + relative + "index" + Doclava.htmlExtension);
202 //hdf.setValue("projectTitle", mTitle);
203 //ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
Scott Maine27c9502011-01-19 14:07:39 -0800204 }
205
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700206 public void writeProjectStructure(String dir, Data hdf) {
207 //System.out.println(">>-- writing project structure for " + dir );
208 hdf.setValue("projectStructure", "true");
209 hdf.setValue("projectDir", mProjectDir);
210 hdf.setValue("page.title", mProjectDir + " Structure");
211 hdf.setValue("projectTitle", mTitle);
212 ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension); //write the project.html file
213 hdf.setValue("projectStructure", "");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700214 }
215
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700216 /**
217 * Write the project's templated _index.html
218 */
219 public void writeProjectIndex(Data hdf) {
220 //System.out.println(">>-- writing project index for " + mDest );
221 hdf.setValue("projectDir", mProjectDir);
222 hdf.setValue("page.title", mProjectDir + " Sample");
223 hdf.setValue("projectTitle", mTitle);
224 ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700225 }
226
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700227 /**
228 * Grab the contents of an _index.html summary from a dir.
229 */
230 public void getSummaryFromDir(Data hdf, File dir, String key) {
231 //System.out.println("Getting summary for " + dir + "/_index.html");
232 hdf.setValue("summary", "");
233 hdf.setValue("summaryFlag", "");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700234 String filename = dir.getPath() + "/_index.html";
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700235 String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename,
236 -1,-1), filename, "sample code", true, false, false, true);
237 if (summary != null) {
238 hdf.setValue(key + "SummaryFlag", "true");
239 hdf.setValue("summary", summary);
240 //set the target for [info] link
241 //hdf.setValue(key + "Href", dir + "/index.html");
242 //return true;
243 }
244 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700245
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700246 /**
247 * Keep track of file parents
248 */
249 Data setParentDirs(Data hdf, String subdir, String name, Boolean isFile) {
250 isFile = false;
251 int iter;
252 hdf.removeTree("parentdirs");
253 //System.out.println("setParentDirs for " + subdir + name);
254 String s = subdir;
255 String urlParts[] = s.split("/");
256 int n, l = (isFile)?1:0;
257 for (iter=2; iter < urlParts.length - l; iter++) {
258 n = iter-2;
259 //System.out.println("parentdirs." + n + ".Name == " + urlParts[iter]);
260 hdf.setValue("parentdirs." + n + ".Name", urlParts[iter]);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700261 }
Ben Dodson920dbbb2010-08-04 15:21:06 -0700262 return hdf;
263 }
264
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700265 /**
266 * Write a templated source code file to out.
267 */
Ben Dodson920dbbb2010-08-04 15:21:06 -0700268 public void writePage(File f, String out, String subdir) {
269 String name = f.getName();
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700270 String path = f.getPath();
Ben Dodson920dbbb2010-08-04 15:21:06 -0700271 String data =
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700272 SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path, "sample code",
273 true, true, true, true);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700274 data = Doclava.escape(data);
275
276 Data hdf = Doclava.makeHDF();
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700277 hdf.setValue("samples", "true");
278 setParentDirs(hdf, subdir, name, true);
279 hdf.setValue("projectTitle", mTitle);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700280 hdf.setValue("projectDir", mProjectDir);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700281 hdf.setValue("page.title", name);
282 hdf.setValue("subdir", subdir);
283 hdf.setValue("realFile", name);
284 hdf.setValue("fileContents", data);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700285 hdf.setValue("resTag", "sample");
286 hdf.setValue("resType", "Sample Code");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700287
288 ClearPage.write(hdf, "sample.cs", out);
289 }
290
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700291 /**
292 * Write a templated image file to out.
293 */
Ben Dodson920dbbb2010-08-04 15:21:06 -0700294 public void writeImagePage(File f, String out, String subdir) {
295 String name = f.getName();
296
297 String data = "<img src=\"" + name + "\" title=\"" + name + "\" />";
298
299 Data hdf = Doclava.makeHDF();
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700300 hdf.setValue("samples", "true");
301 setParentDirs(hdf, subdir, name, true);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700302 hdf.setValue("page.title", name);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700303 hdf.setValue("projectTitle", mTitle);
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700304 hdf.setValue("projectDir", mProjectDir);
Ben Dodson920dbbb2010-08-04 15:21:06 -0700305 hdf.setValue("subdir", subdir);
306 hdf.setValue("realFile", name);
307 hdf.setValue("fileContents", data);
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700308 hdf.setValue("resTag", "sample");
309 hdf.setValue("resType", "Sample Code");
Ben Dodson920dbbb2010-08-04 15:21:06 -0700310 ClearPage.write(hdf, "sample.cs", out);
311 }
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700312
313 /**
314 * Render a SC node to a navtree js file.
315 */
316 public static void writeSamplesNavTree(List<Node> tnode) {
317 Node node = new Node("Reference", "packages.html", tnode, null);
318
319 StringBuilder buf = new StringBuilder();
320 if (false) {
321 // if you want a root node
322 buf.append("[");
323 node.render(buf);
324 buf.append("]");
325 } else {
326 // if you don't want a root node
327 node.renderChildren(buf);
328 }
329
330 Data data = Doclava.makeHDF();
331 data.setValue("reference_tree", buf.toString());
332 ClearPage.write(data, "samples_navtree_data.cs", "samples_navtree_data.js");
333 }
334
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700335 Comparator<File> byTypeAndName = new Comparator<File>() {
336 public int compare (File one, File other) {
337 if (one.isDirectory() && !other.isDirectory()) {
338 return 1;
339 } else if (!one.isDirectory() && other.isDirectory()) {
340 return -1;
341 } else {
342 return one.compareTo(other);
343 }
344 }
345 };
346
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700347 /**
348 * SampleCode variant of NavTree node.
349 */
350 public static class Node {
351 private String mLabel;
352 private String mLink;
353 List<Node> mChildren;
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700354 public String mType;
Dirk Dougherty1b45d1d2010-08-17 17:25:36 -0700355
356 Node(String label, String link, List<Node> children, String type) {
357 mLabel = label;
358 mLink = link;
359 mChildren = children;
360 mType = type;
361 }
362
363 static void renderString(StringBuilder buf, String s) {
364 if (s == null) {
365 buf.append("null");
366 } else {
367 buf.append('"');
368 final int N = s.length();
369 for (int i = 0; i < N; i++) {
370 char c = s.charAt(i);
371 if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
372 buf.append(c);
373 } else {
374 buf.append("\\u");
375 for (int j = 0; i < 4; i++) {
376 char x = (char) (c & 0x000f);
377 if (x > 10) {
378 x = (char) (x - 10 + 'a');
379 } else {
380 x = (char) (x + '0');
381 }
382 buf.append(x);
383 c >>= 4;
384 }
385 }
386 }
387 buf.append('"');
388 }
389 }
390
391 void renderChildren(StringBuilder buf) {
392 List<Node> list = mChildren;
393 if (list == null || list.size() == 0) {
394 // We output null for no children. That way empty lists here can just
395 // be a byproduct of how we generate the lists.
396 buf.append("null");
397 } else {
398 buf.append("[ ");
399 final int N = list.size();
400 for (int i = 0; i < N; i++) {
401 list.get(i).render(buf);
402 if (i != N - 1) {
403 buf.append(", ");
404 }
405 }
406 buf.append(" ]\n");
407 }
408 }
409
410 void render(StringBuilder buf) {
411 buf.append("[ ");
412 renderString(buf, mLabel);
413 buf.append(", ");
414 renderString(buf, mLink);
415 buf.append(", ");
416 renderChildren(buf);
417 buf.append(", ");
418 renderString(buf, mType);
419 buf.append(" ]");
420 }
421 }
422
Dirk Doughertyc11a4672013-08-23 19:14:10 -0700423 /**
424 * @deprecated
425 */
426 public void writeDirectory(File dir, String relative, boolean offline) {
427 TreeSet<String> dirs = new TreeSet<String>();
428 TreeSet<String> files = new TreeSet<String>();
429
430 String subdir = relative; // .substring(mDest.length());
431
432 for (File f : dir.listFiles()) {
433 String name = f.getName();
434 if (name.startsWith(".") || name.startsWith("_")) {
435 continue;
436 }
437 if (f.isFile()) {
438 String out = relative + name;
439 if (inList(out, IMAGES)) {
440 // copied directly
441 ClearPage.copyFile(false, f, out);
442 writeImagePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
443 files.add(name);
444 }
445 if (inList(out, TEMPLATED)) {
446 // copied and goes through the template
447 ClearPage.copyFile(false, f, out);
448 writePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
449 files.add(name);
450
451 }
452 // else ignored
453 } else if (f.isDirectory()) {
454 writeDirectory(f, relative + name + "/", offline);
455 dirs.add(name);
456 }
457 }
458
459 // write the index page
460 int i;
461
462 Data hdf = writeIndex(dir);
463 hdf.setValue("subdir", subdir);
464 i = 0;
465 for (String d : dirs) {
466 hdf.setValue("subdirs." + i + ".Name", d);
467 hdf.setValue("files." + i + ".Href", convertExtension(d, ".html"));
468 i++;
469 }
470 i = 0;
471 for (String f : files) {
472 hdf.setValue("files." + i + ".Name", f);
473 hdf.setValue("files." + i + ".Href", convertExtension(f, ".html"));
474 i++;
475 }
476
477 if (!offline) relative = "/" + relative;
478 ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
479 }
480
481 /**
482 * @deprecated
483 */
484 public void writeIndexOnly(File dir, String relative, Boolean offline) {
485 Data hdf = writeIndex(dir);
486 if (!offline) relative = "/" + relative;
487
488 System.out.println("writing indexonly at " + relative + "/index" + Doclava.htmlExtension);
489 ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
490 }
491
492 /**
493 * @deprecated
494 */
495 public Data writeIndex(File dir) {
496 Data hdf = Doclava.makeHDF();
497 hdf.setValue("page.title", dir.getName() + " - " + mTitle);
498 hdf.setValue("projectTitle", mTitle);
499
500 String filename = dir.getPath() + "/_index.html";
501 String summary =
502 SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code",
503 true, false, false, true);
504
505 if (summary == null) {
506 summary = "";
507 }
508 hdf.setValue("summary", summary);
509
510 return hdf;
511 }
512
Ben Dodson920dbbb2010-08-04 15:21:06 -0700513}