From 1b45d1d08a4ff984e1d0741dd13f0759f6527ebf Mon Sep 17 00:00:00 2001 From: Dirk Dougherty Date: Tue, 17 Aug 2010 17:25:36 -0700 Subject: doc change: Samples browsing: starter templates and navtree gen support. Change-Id: I03f5eec1dcb71e96fed2ba0119a0b2c0bba56f49 --- src/com/google/doclava/DocFile.java | 2 + src/com/google/doclava/Doclava.java | 33 ++- src/com/google/doclava/SampleCode.java | 333 ++++++++++++++++++++++++++++-- src/com/google/doclava/SampleTagInfo.java | 32 ++- src/com/google/doclava/SinceTagger.java | 2 +- 5 files changed, 372 insertions(+), 30 deletions(-) diff --git a/src/com/google/doclava/DocFile.java b/src/com/google/doclava/DocFile.java index 9e56235..f699f58 100644 --- a/src/com/google/doclava/DocFile.java +++ b/src/com/google/doclava/DocFile.java @@ -157,6 +157,8 @@ public class DocFile { hdf.setValue("more", "true"); } else if (filename.indexOf("google") == 0) { hdf.setValue("google", "true"); + } else if (filename.indexOf("samples") == 0) { + hdf.setValue("samples", "true"); } else if (filename.indexOf("distribute") == 0) { hdf.setValue("distribute", "true"); } else if (filename.indexOf("about") == 0) { diff --git a/src/com/google/doclava/Doclava.java b/src/com/google/doclava/Doclava.java index 3bcc689..1a77828 100644 --- a/src/com/google/doclava/Doclava.java +++ b/src/com/google/doclava/Doclava.java @@ -91,6 +91,7 @@ public class Doclava { private static boolean gmsRef = false; private static boolean gcmRef = false; + private static boolean samplesRef = false; private static boolean sac = false; public static boolean checkLevel(int level) { @@ -322,8 +323,13 @@ public class Doclava { writeAssets(); + // Sample code pages + if (samplesRef) { + writeSamples(offlineMode, sampleCodes); + } + // Navigation tree - String refPrefix = new String(); + String refPrefix = new String(); if(gmsRef){ refPrefix = "gms-"; } else if(gcmRef){ @@ -351,11 +357,6 @@ public class Doclava { writeKeepList(keepListFile); } - // Sample Code - for (SampleCode sc : sampleCodes) { - sc.write(offlineMode); - } - // Index page writeIndex(); @@ -519,8 +520,12 @@ public class Doclava { return 2; } if (option.equals("-samplecode")) { + samplesRef = true; return 4; } + if (option.equals("-devsite")) { + return 1; + } if (option.equals("-htmldir")) { return 2; } @@ -1645,4 +1650,20 @@ public class Doclava { static String ensureSlash(String path) { return path.endsWith("/") ? path : path + "/"; } + + /** + * Process samples dirs that are specified in Android.mk. Generate html + * wrapped pages, copy files to output dir, and generate a SampleCode NavTree. + */ + public static void writeSamples(boolean offlineMode, ArrayList sampleCodes) { + // Go through SCs processing files. Create a root list for SC nodes, + // pass it to SCs for their NavTree children and append them. + List samplesList = new ArrayList(); + for (SampleCode sc : sampleCodes) { + samplesList.add(sc.write(offlineMode)); + } + // Pass full samplesList to SC to render to js file. + SampleCode.writeSamplesNavTree(samplesList); + } + } diff --git a/src/com/google/doclava/SampleCode.java b/src/com/google/doclava/SampleCode.java index 65d44b5..5294faf 100644 --- a/src/com/google/doclava/SampleCode.java +++ b/src/com/google/doclava/SampleCode.java @@ -30,22 +30,49 @@ public class SampleCode { public SampleCode(String source, String dest, String title) { mSource = source; mTitle = title; + int len = dest.length(); if (len > 1 && dest.charAt(len - 1) != '/') { mDest = dest + '/'; } else { mDest = dest; } + + //System.out.println("SampleCode init: source: " + mSource); + //System.out.println("SampleCode init: dest: " + mDest); + //System.out.println("SampleCode init: title: " + mTitle); + } - public void write(boolean offlineMode) { + public Node write(boolean offlineMode) { + List filelist = new ArrayList(); File f = new File(mSource); + String name = f.getName(); + String startname = name; + String subdir = mDest; + String mOut = subdir + name; if (!f.isDirectory()) { System.out.println("-samplecode not a directory: " + mSource); - return; + return null; } - - writeDirectory(f, mDest, offlineMode); + + if (offlineMode) + writeIndexOnly(f, mDest, offlineMode); + else { + Data hdf = Doclava.makeHDF(); + hdf.setValue("samples", "true"); + writeProjectDirectory(filelist, f, mDest, false, hdf, "Files."); + // values for handling breadcrumb for project.html file + hdf.setValue("page.title", "Project Structure"); + hdf.removeTree("parentdirs"); + hdf.setValue("parentdirs.0.Name", name); + hdf.setValue("showProjectPaths","true"); + hdf.setValue("samples", "true"); + ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension); //write the project.html file + // return a root SC node for the sample with children appended + return new Node(mTitle, "samples/" + startname + "/index.html", filelist, null); + } + return null; } public static String convertExtension(String s, String ext) { @@ -53,7 +80,7 @@ public class SampleCode { } public static String[] IMAGES = {".png", ".jpg", ".gif"}; - public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs"}; + public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"}; public static boolean inList(String s, String[] list) { for (String t : list) { @@ -63,9 +90,115 @@ public class SampleCode { } return false; } - - public void writeDirectory(File dir, String relative) { - writeDirectory(dir, relative, false); + + public static String mapTypes(String name) { + String type = name.substring(name.lastIndexOf('.') + 1, name.length()); + if (type.equals("xml") || type.equals("java")) { + if (name.equals("AndroidManifest.xml")) type = "manifest"; + return type; + } else { + return type = "file"; + } + } + + public void writeProjectDirectory(List parent, File dir, String relative, Boolean recursed, Data hdf, String newkey) { + TreeSet dirs = new TreeSet(); //dirs for project structure and breadcrumb + TreeSet files = new TreeSet(); //files for project structure and breadcrumb + + String subdir = relative; + String name = ""; + String label = ""; + String link = ""; + String type = ""; + int i = 0; + String expansion = ".Sub."; + String key = newkey; + + if (recursed) { + key = (key + expansion); + } else { + expansion = ""; + } + + for (File f: dir.listFiles()) { + name = f.getName(); + // don't process certain types of files + if (name.startsWith(".") || + name.startsWith("_") || + name.equals("default.properties") || + name.equals("build.properties") || + name.endsWith(".ttf") || + name.equals("Android.mk")) { + //System.out.println("Invalid File Type, bypassing: " + name); + continue; + } + if (f.isFile() && name.contains(".")){ + String path = relative + name; + type = mapTypes(name); + link = convertExtension(path, ".html"); + hdf.setValue("samples", "true");//dd needed? + + if (inList(path, IMAGES)) { + // copy these files to output directly + type = "img"; + ClearPage.copyFile(false, f, path); + writeImagePage(f, convertExtension(path, Doclava.htmlExtension), relative); + files.add(name); + hdf.setValue(key + i + ".Type", "img"); + hdf.setValue(key + i + ".Name", name); + hdf.setValue(key + i + ".Href", link); + } + if (inList(path, TEMPLATED)) { + // copied and goes through the template + ClearPage.copyFile(false, f, path); + writePage(f, convertExtension(path, Doclava.htmlExtension), relative); + files.add(name); + hdf.setValue(key + i + ".Type", type); + hdf.setValue(key + i + ".Name", name); + hdf.setValue(key + i + ".Href", link); + } + // add file to the navtree + parent.add(new Node(name, link , null, type)); + i++; + } else if (f.isDirectory()) { + List mchildren = new ArrayList(); + type = "dir"; + String dirpath = relative + name; + link = dirpath + "/index.html"; + String hdfkeyName = (key + i + ".Name"); + String hdfkeyType = (key + i + ".Type"); + String hdfkeyHref = (key + i + ".Href"); + hdf.setValue(hdfkeyName, name); + hdf.setValue(hdfkeyType, type); + hdf.setValue(hdfkeyHref, relative + name + "/" + "index.html"); + //System.out.println("Found directory, recursing. Current key: " + hdfkeyName); + writeProjectDirectory(mchildren, f, relative + name + "/", true, hdf, (key + i)); + if (mchildren.size() > 0) { + //dir is processed, now add it to the navtree + //don't link sidenav subdirs at this point (but cab use "link" to do so) + parent.add(new Node(name, null, mchildren, type)); + } + //dirs.add(name); //dd not used? + i++; + } + } + //dd not working yet + getSummaryFromDir(hdf, dir, newkey); + hdf.setValue("resType", "Sample Code"); + hdf.setValue("resTag", "sample"); + hdf.setValue("showProjectPaths","false"); + //If this is an index for the project root (assumed root if split length is 3 (development/samples/nn)), + //then remove the root dir so that it won't appear in the breadcrumb. Else just pass it through to + //setParentDirs as usual. + String mpath = dir + ""; + String sdir[] = mpath.split("/"); + if (sdir.length == 3 ) { + System.out.println("-----------------> this must be the root: [sdir len]" + sdir.length + "[dir]" + dir); + hdf.setValue("showProjectPaths","true"); + } + setParentDirs(hdf, relative, name, false); + System.out.println("writing sample index -- " + relative + "index" + Doclava.htmlExtension); + ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension); } public void writeDirectory(File dir, String relative, boolean offline) { @@ -81,7 +214,6 @@ public class SampleCode { } if (f.isFile()) { String out = relative + name; - if (inList(out, IMAGES)) { // copied directly ClearPage.copyFile(false, f, out); @@ -93,6 +225,7 @@ public class SampleCode { ClearPage.copyFile(false, f, out); writePage(f, convertExtension(out, Doclava.htmlExtension), subdir); files.add(name); + } // else ignored } else if (f.isDirectory()) { @@ -108,13 +241,14 @@ public class SampleCode { hdf.setValue("subdir", subdir); i = 0; for (String d : dirs) { - hdf.setValue("subdirs." + i + ".name", d); + hdf.setValue("subdirs." + i + ".Name", d); + hdf.setValue("files." + i + ".Href", convertExtension(d, ".html")); i++; } i = 0; for (String f : files) { - hdf.setValue("files." + i + ".name", f); - hdf.setValue("files." + i + ".href", convertExtension(f, ".html")); + hdf.setValue("files." + i + ".Name", f); + hdf.setValue("files." + i + ".Href", convertExtension(f, ".html")); i++; } @@ -122,6 +256,14 @@ public class SampleCode { ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension); } + public void writeIndexOnly(File dir, String relative, Boolean offline) { + Data hdf = writeIndex(dir); + if (!offline) relative = "/" + relative; + + System.out.println("writing indexonly at " + relative + "/index" + Doclava.htmlExtension); + ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension); + } + public Data writeIndex(File dir) { Data hdf = Doclava.makeHDF(); @@ -131,7 +273,7 @@ public class SampleCode { String filename = dir.getPath() + "/_index.html"; String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code", - true, false, true); + true, false, false, true); if (summary == null) { summary = ""; @@ -141,21 +283,70 @@ public class SampleCode { return hdf; } +//dd START reformat this + public Boolean getSummaryFromDir(Data hdf, File dir, String key) { + hdf.setValue("page.title", dir.getName()); + hdf.setValue("projectTitle", mTitle); + + String filename = dir.getPath() + "/_index.html"; + String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename, + -1,-1), filename, "sample code", true, false, false, true); + + if (summary != null) { + hdf.setValue(key + "SummaryFlag", "true"); + hdf.setValue("summary", summary); + //set the target for [info] link + hdf.setValue(key + "Href", dir + "/index.html"); + return true; + } + else { + hdf.setValue("summary", ""); + return false; + } + } + + Data setParentDirs(Data hdf, String subdir, String name, Boolean isFile) { + isFile = false; + int iter; + hdf.removeTree("parentdirs"); + //System.out.println("setParentDirs for " + subdir + name); + String s = subdir; + String urlParts[] = s.split("/"); + int n, l = (isFile)?1:0; + for (iter=2; iter < urlParts.length - l; iter++) { + n = iter-2; + //System.out.println("parentdirs." + n + ".Name == " + urlParts[iter]); + hdf.setValue("parentdirs." + n + ".Name", urlParts[iter]); + } + return hdf; + }//dd END reformat this + + + + + + + + + public void writePage(File f, String out, String subdir) { String name = f.getName(); - - String filename = f.getPath(); + String path = f.getPath(); String data = - SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code", - true, true, true); + SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path, "sample code", + true, true, true, true); data = Doclava.escape(data); Data hdf = Doclava.makeHDF(); - + hdf.setValue("samples", "true"); + setParentDirs(hdf, subdir, name, true); + hdf.setValue("projectTitle", mTitle); hdf.setValue("page.title", name); hdf.setValue("subdir", subdir); hdf.setValue("realFile", name); hdf.setValue("fileContents", data); + hdf.setValue("resTag", "sample"); + hdf.setValue("resType", "Sample Code"); ClearPage.write(hdf, "sample.cs", out); } @@ -166,12 +357,114 @@ public class SampleCode { String data = ""; Data hdf = Doclava.makeHDF(); - + hdf.setValue("samples", "true"); + setParentDirs(hdf, subdir, name, true); hdf.setValue("page.title", name); + hdf.setValue("projectTitle", mTitle); hdf.setValue("subdir", subdir); hdf.setValue("realFile", name); hdf.setValue("fileContents", data); - + hdf.setValue("resTag", "sample"); + hdf.setValue("resType", "Sample Code"); ClearPage.write(hdf, "sample.cs", out); } + + /** + * Render a SC node to a navtree js file. + */ + public static void writeSamplesNavTree(List tnode) { + Node node = new Node("Reference", "packages.html", tnode, 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()); + ClearPage.write(data, "samples_navtree_data.cs", "samples_navtree_data.js"); + } + + /** + * SampleCode variant of NavTree node. + */ + public static class Node { + private String mLabel; + private String mLink; + List mChildren; + private String mType; + + Node(String label, String link, List children, String type) { + mLabel = label; + mLink = link; + mChildren = children; + mType = type; + } + + 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, mType); + buf.append(" ]"); + } + } + } diff --git a/src/com/google/doclava/SampleTagInfo.java b/src/com/google/doclava/SampleTagInfo.java index 9b9e40a..4e14b2b 100644 --- a/src/com/google/doclava/SampleTagInfo.java +++ b/src/com/google/doclava/SampleTagInfo.java @@ -79,7 +79,7 @@ public class SampleTagInfo extends TagInfo { boolean trim = "@sample".equals(name); if (id == null || "".equals(id)) { - mIncluded = readFile(position, filename, id, trim, true, false); + mIncluded = readFile(position, filename, id, trim, true, false, false); } else { mIncluded = loadInclude(position, filename, id, trim); } @@ -106,6 +106,14 @@ public class SampleTagInfo extends TagInfo { } } + static String addLineNumber(String line, String num) { + StringBuilder numberedLine = new StringBuilder(); + numberedLine.append("
  • "); + numberedLine.append(line); + numberedLine.append("
  • "); + return numberedLine.substring(0); + } + static String loadInclude(SourcePositionInfo pos, String filename, String id, boolean trim) { Reader input = null; StringBuilder result = new StringBuilder(); @@ -196,20 +204,25 @@ public class SampleTagInfo extends TagInfo { } static String readFile(SourcePositionInfo pos, String filename, String id, boolean trim, - boolean escape, boolean errorOk) { + boolean escape, boolean numberedLines, boolean errorOk) { Reader input = null; StringBuilder result = new StringBuilder(); int trailing = 0; boolean started = false; + try { + input = new FileReader(filename); LineNumberReader lines = new LineNumberReader(input); while (true) { String line = lines.readLine(); + String lineNum = Integer.toString(lines.getLineNumber()); + if (line == null) { break; } + if (trim) { if (isIncludeLine(line)) { continue; @@ -223,15 +236,28 @@ public class SampleTagInfo extends TagInfo { if (escape) { line = escapeHtml(line); } + if (numberedLines) { + line = addLineNumber(line, lineNum); + } result.append(line); trailing = 1; // add \n next time, maybe started = true; } else { if (started) { - trailing++; + if (numberedLines) { + result.append('\n'); + line = line + " "; + line = addLineNumber(line, lineNum); + result.append(line); + } else { + trailing++; + } } } } else { + if (numberedLines) { + line = addLineNumber(line, lineNum); + } result.append(line); result.append('\n'); } diff --git a/src/com/google/doclava/SinceTagger.java b/src/com/google/doclava/SinceTagger.java index a2797c1..858d98f 100644 --- a/src/com/google/doclava/SinceTagger.java +++ b/src/com/google/doclava/SinceTagger.java @@ -30,7 +30,7 @@ import java.util.Map; /** - * Applies version information to the DroidDoc class model from apicheck XML files. Sample usage: + * Applies version information to the Doclava class model from apicheck XML files. Sample usage: * *
      *   ClassInfo[] classInfos = ...
    -- 
    cgit v1.2.3