Doclava: Add support for building samples toc from contents of a target browsable dir.
(cherry picked from commit 7537229470687560714401104558abdf82f81441)
Change-Id: I26cbdde207040d1b5db5ccb1793d396567fd4163
diff --git a/src/com/google/doclava/SampleCode.java b/src/com/google/doclava/SampleCode.java
index 88c36dc..45f9833 100644
--- a/src/com/google/doclava/SampleCode.java
+++ b/src/com/google/doclava/SampleCode.java
@@ -15,13 +15,22 @@
*/
package com.google.doclava;
-import com.google.clearsilver.jsilver.data.Data;
-import java.util.*;
-import java.io.*;
+import java.util.Arrays;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
import java.util.regex.Pattern;
import java.util.regex.Matcher;
+import java.io.File;
+import com.google.clearsilver.jsilver.data.Data;
+
+/**
+* Represents a browsable sample code project, with methods for managing
+* metadata collection, file output, sorting, etc.
+*/
public class SampleCode {
String mSource;
String mDest;
@@ -29,6 +38,17 @@
String mProjectDir;
String mTags;
+ /** Max size for browseable images/video. If a source file exceeds this size,
+ * a file is generated with a generic placeholder and the original file is not
+ * copied to out.
+ */
+ private static final double MAX_FILE_SIZE_BYTES = 2097152;
+
+ /** When full tree nav is enabled, generate an index for every dir
+ * and linkify the breadcrumb paths in all files.
+ */
+ private static final boolean FULL_TREE_NAVIGATION = false;
+
public SampleCode(String source, String dest, String title) {
mSource = source;
mTitle = title;
@@ -42,85 +62,129 @@
mDest = dest;
}
}
- //System.out.println("SampleCode init: source: " + mSource);
- //System.out.println("SampleCode init: dest: " + mDest);
- //System.out.println("SampleCode init: title: " + mTitle);
-
}
- public Node write(boolean offlineMode) {
+ /**
+ * Iterates a given sample code project gathering metadata for files and building
+ * a node tree that reflects the project's directory structure. After iterating
+ * the project, this method adds the project's metadata to jd_lists_unified,
+ * so that it is accessible for dynamic content and search suggestions.
+ *
+ * @param offlineMode Ignored -- offline-docs mode is not currently supported for
+ * browsable sample code projects.
+ * @return A root Node for the project containing its metadata and tree structure.
+ */
+ public Node setSamplesTOC(boolean offlineMode) {
List<Node> filelist = new ArrayList<Node>();
File f = new File(mSource);
mProjectDir = f.getName();
String name = mProjectDir;
- String startname = name;
- String subdir = mDest;
- String mOut = subdir + name;
+ String mOut = mDest + name;
if (!f.isDirectory()) {
System.out.println("-samplecode not a directory: " + mSource);
return null;
}
- if (offlineMode)
- writeIndexOnly(f, mDest, offlineMode);
- else {
- Data hdf = Doclava.makeHDF();
- hdf.setValue("samples", "true");
- hdf.setValue("projectDir", mProjectDir);
- writeProjectDirectory(filelist, f, mDest, false, hdf, "Files.");
- writeProjectStructure(name, hdf);
- hdf.removeTree("parentdirs");
- hdf.setValue("parentdirs.0.Name", name);
- //Write root _index.jd to out and add metadata to Node.
- Node rootNode = writeProjectIndexCs(hdf, f, null,
- new Node.Builder().setLabel(mProjectDir).setLink("samples/"
- + startname + "/index.html").setChildren(filelist).build());
- // return a root SC node for the sample with children appended
- return rootNode;
+ Data hdf = Doclava.makeHDF();
+ setProjectStructure(filelist, f, mDest);
+ String link = ClearPage.toroot + "samples/" + name + "/index" + Doclava.htmlExtension;
+ Node rootNode = writeSampleIndexCs(hdf, f,
+ new Node.Builder().setLabel(mProjectDir).setLink(link).setChildren(filelist).build(),false);
+ return rootNode;
+ }
+
+ /**
+ * For a given sample code project dir, iterate through the project generating
+ * browsable html for all valid sample code files. After iterating the project
+ * generate a templated index file to the project output root.
+ *
+ * @param offlineMode Ignored -- offline-docs mode is not currently supported for
+ * browsable sample code projects.
+ */
+ public void writeSamplesFiles(boolean offlineMode) {
+ List<Node> filelist = new ArrayList<Node>();
+ File f = new File(mSource);
+ mProjectDir = f.getName();
+ String name = mProjectDir;
+ String mOut = mDest + name;
+ if (!f.isDirectory()) {
+ System.out.println("-samplecode not a directory: " + mSource);
}
- return null;
+
+ Data hdf = Doclava.makeHDF();
+ if (Doclava.samplesNavTree != null) {
+ hdf.setValue("samples_toc_tree", Doclava.samplesNavTree.getValue("samples_toc_tree", ""));
+ }
+ hdf.setValue("samples", "true");
+ hdf.setValue("projectDir", mProjectDir);
+ writeProjectDirectory(f, mDest, false, hdf, "Files.");
+ writeProjectStructure(name, hdf);
+ hdf.removeTree("parentdirs");
+ hdf.setValue("parentdirs.0.Name", name);
+ boolean writeFiles = true;
+ String link = "samples/" + name + "/index" + Doclava.htmlExtension;
+ //Write root _index.jd to out and add metadata to Node.
+ writeSampleIndexCs(hdf, f,
+ new Node.Builder().setLabel(mProjectDir).setLink(link).build(), true);
}
- public static String convertExtension(String s, String ext) {
- return s.substring(0, s.lastIndexOf('.')) + ext;
- }
-
- public static String[] IMAGES = {".png", ".jpg", ".gif"};
- public static String[] VIDEOS = {".mp4", ".ogv", ".webm"};
- public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"};
-
- public static boolean inList(String s, String[] list) {
- for (String t : list) {
- if (s.endsWith(t)) {
- return true;
+ /**
+ * Given the root Node for a sample code project, iterates through the project
+ * gathering metadata and project tree structure. Unsupported file types are
+ * filtered from the project output. The collected project Nodes are appended to
+ * the root project node.
+ *
+ * @param parent The root Node that represents this sample code project.
+ * @param dir The current dir being processed.
+ * @param relative Relative path for creating links to this file.
+ */
+ public void setProjectStructure(List<Node> parent, File dir, String relative) {
+ String name, link;
+ File[] dirContents = dir.listFiles();
+ Arrays.sort(dirContents, byTypeAndName);
+ for (File f: dirContents) {
+ name = f.getName();
+ if (!isValidFiletype(name)) {
+ continue;
+ }
+ if (f.isFile() && name.contains(".")) {
+ String path = relative + name;
+ link = convertExtension(path, Doclava.htmlExtension);
+ if (inList(path, IMAGES) || inList(path, VIDEOS) || inList(path, TEMPLATED)) {
+ parent.add(new Node.Builder().setLabel(name).setLink(ClearPage.toroot + link).build());
+ }
+ } else if (f.isDirectory()) {
+ List<Node> mchildren = new ArrayList<Node>();
+ String dirpath = relative + name + "/";
+ setProjectStructure(mchildren, f, dirpath);
+ if (mchildren.size() > 0) {
+ parent.add(new Node.Builder().setLabel(name).setLink(ClearPage.toroot
+ + dirpath).setChildren(mchildren).build());
+ }
}
}
- return false;
}
- public static String mapTypes(String name) {
- String type = name.substring(name.lastIndexOf('.') + 1, name.length());
- if ("xml".equals(type) || "java".equals(type)) {
- if ("AndroidManifest.xml".equals(name)) type = "manifest";
- return type;
- } else {
- return type = "file";
- }
- }
-
- public void writeProjectDirectory(List<Node> parent, File dir, String relative, Boolean recursed, Data hdf, String newkey) {
- TreeSet<String> dirs = new TreeSet<String>(); //dirs for project structure and breadcrumb
- TreeSet<String> files = new TreeSet<String>(); //files for project structure and breadcrumb
-
- String subdir = relative;
+ /**
+ * Given a root sample code project path, iterates through the project
+ * setting page metadata to manage html output and writing/copying files to
+ * the output directory. Source files are templated and images are templated
+ * and linked to the original image.
+ *
+ * @param dir The current dir being processed.
+ * @param relative Relative path for creating links to this file.
+ * @param recursed Whether the method is being called recursively.
+ * @param hdf The data to read/write for files in this project.
+ * @param newKey Key passed in recursion for managing cs child trees.
+ */
+ public void writeProjectDirectory(File dir, String relative, Boolean recursed,
+ Data hdf, String newkey) {
String name = "";
- String label = "";
String link = "";
String type = "";
int i = 0;
String expansion = ".Sub.";
String key = newkey;
- double maxFileSizeBytes = 2097152; //Max size for browseable images/video
if (recursed) {
key = (key + expansion);
@@ -132,180 +196,160 @@
Arrays.sort(dirContents, byTypeAndName);
for (File f: dirContents) {
name = f.getName();
- // don't process certain types of files
- if (name.startsWith(".") ||
- name.startsWith("_") ||
- "default.properties".equals(name) ||
- "build.properties".equals(name) ||
- name.endsWith(".ttf") ||
- name.endsWith(".gradle") ||
- name.endsWith(".bat") ||
- "Android.mk".equals(name)) {
- //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";
- if (f.length() < maxFileSizeBytes) {
- ClearPage.copyFile(false, f, path);
- writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
+ if (!isValidFiletype(name)) {
+ continue;
+ }
+ if (f.isFile() && name.contains(".")) {
+ String path = relative + name;
+ type = mapTypes(name);
+ link = convertExtension(path, Doclava.htmlExtension);
+ if (inList(path, IMAGES)) {
+ type = "img";
+ if (f.length() < MAX_FILE_SIZE_BYTES) {
+ ClearPage.copyFile(false, f, path);
+ writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
relative, type, true);
- } else {
- //too large for browsing, skip copying and show generic icon
- writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
+ } else {
+ writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
relative, type, false);
- }
- files.add(name);
- hdf.setValue(key + i + ".Type", "img");
- hdf.setValue(key + i + ".Name", name);
- hdf.setValue(key + i + ".Href", link);
- hdf.setValue(key + i + ".RelPath", relative);
- }
- if (inList(path, VIDEOS)) {
- // copy these files to output directly
- type = "video";
- if (f.length() < maxFileSizeBytes) {
- ClearPage.copyFile(false, f, path);
- writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
+ }
+ hdf.setValue(key + i + ".Type", "img");
+ hdf.setValue(key + i + ".Name", name);
+ hdf.setValue(key + i + ".Href", link);
+ hdf.setValue(key + i + ".RelPath", relative);
+ } else if (inList(path, VIDEOS)) {
+ type = "video";
+ if (f.length() < MAX_FILE_SIZE_BYTES) {
+ ClearPage.copyFile(false, f, path);
+ writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
relative, type, true);
- } else {
- //too large for browsing, skip copying and show generic icon
- writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
+ } else {
+ writeImageVideoPage(f, convertExtension(path, Doclava.htmlExtension),
relative, type, false);
- }
- files.add(name);
- hdf.setValue(key + i + ".Type", "video");
- hdf.setValue(key + i + ".Name", name);
- hdf.setValue(key + i + ".Href", link);
- hdf.setValue(key + i + ".RelPath", relative);
- }
- 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);
- hdf.setValue(key + i + ".RelPath", relative);
- }
- // add file to the navtree
- parent.add(new Node.Builder().setLabel(name).setLink(link).setType(type).build());
- i++;
- } else if (f.isDirectory()) {
- List<Node> mchildren = new ArrayList<Node>();
- type = "dir";
- String dirpath = relative + name;
- link = dirpath + "/index.html";
+ }
+ hdf.setValue(key + i + ".Type", "video");
+ hdf.setValue(key + i + ".Name", name);
+ hdf.setValue(key + i + ".Href", link);
+ hdf.setValue(key + i + ".RelPath", relative);
+ } else if (inList(path, TEMPLATED)) {
+ writePage(f, convertExtension(path, Doclava.htmlExtension), relative, hdf);
+ hdf.setValue(key + i + ".Type", type);
+ hdf.setValue(key + i + ".Name", name);
+ hdf.setValue(key + i + ".Href", link);
+ hdf.setValue(key + i + ".RelPath", relative);
+ }
+ i++;
+ } else if (f.isDirectory()) {
+ List<Node> mchildren = new ArrayList<Node>();
+ type = "dir";
+ String dirpath = relative + name;
+ link = dirpath + "/index" + Doclava.htmlExtension;
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 can use "link" to do so)
- parent.add(new Node.Builder().setLabel(name).setChildren(mchildren).setType(type).build());
- }
- dirs.add(name);
- i++;
- }
-
+ hdf.setValue(hdfkeyName, name);
+ hdf.setValue(hdfkeyType, type);
+ hdf.setValue(hdfkeyHref, relative + name + "/" + "index" + Doclava.htmlExtension);
+ writeProjectDirectory(f, relative + name + "/", true, hdf, (key + i));
+ i++;
+ }
}
- //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("/");
+
setParentDirs(hdf, relative, name, false);
//Generate an index.html page for each dir being processed
- ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
- //concatenate dirs in the navtree. Comment out or remove to restore normal navtree
- squashNodes(parent);
- }
-
- public void writeProjectStructure(String dir, Data hdf) {
- //System.out.println(">>-- writing project structure for " + dir );
- hdf.setValue("projectStructure", "true");
- hdf.setValue("projectDir", mProjectDir);
- hdf.setValue("page.title", mProjectDir + " Structure");
- hdf.setValue("projectTitle", mTitle);
- //write the project.html file
- ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension);
- hdf.setValue("projectStructure", "");
+ if (FULL_TREE_NAVIGATION) {
+ ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
+ }
}
/**
* Processes a templated project index page from _index.jd in a project root.
* Each sample project must have an index, and each index locally defines it's own
* page.tags and sample.group cs vars. This method takes a SC node on input, reads
- * any local vars from the _index.jd, generates an html file to out, then updates
- * the SC node with the page vars and returns it to the caller.
+ * any local vars from the _index.jd, optionally generates an html file to out,
+ * then updates the SC node with the page vars and returns it to the caller.
*
+ * @param hdf The data source to read/write for this index file.
+ * @param dir The sample project root directory.
+ * @param tnode A Node to serve as the project's root node.
+ * @param writeFiles If true, generates output files only. If false, collects
+ * metadata only.
+ * @return The tnode root with any metadata/child Nodes appended.
*/
- public Node writeProjectIndexCs(Data hdf, File dir, String key, Node tnode) {
- //hdf.setValue("summary", "");
- //hdf.setValue("summaryFlag", "");
+ public Node writeSampleIndexCs(Data hdf, File dir, Node tnode, boolean writeFiles) {
+
String filename = dir.getAbsolutePath() + "/_index.jd";
+ String mGroup = "";
File f = new File(filename);
String rel = dir.getPath();
- String mGroup = "";
- hdf.setValue("samples", "true");
- //set any default page variables for root index
- hdf.setValue("page.title", mProjectDir);
- hdf.setValue("projectDir", mProjectDir);
- hdf.setValue("projectTitle", mTitle);
- //add the download/project links to the landing pages.
- hdf.setValue("samplesProjectIndex", "true");
+ if (writeFiles) {
- if (!f.isFile()) {
- //The sample didn't have any _index.jd, so create a stub.
- ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
- //Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
- // + ": Root _index.jd must be present and must define sample.group"
- // + " tag. Please see ... for details.");
- } else {
- DocFile.writePage(filename, rel, mDest + "index" + Doclava.htmlExtension, hdf);
- PageMetadata.setPageMetadata(f, rel, mDest + "index" + Doclava.htmlExtension, hdf, Doclava.sTaglist);
- tnode.setTags(hdf.getValue("page.tags", ""));
+ hdf.setValue("samples", "true");
+ //set any default page variables for root index
+ hdf.setValue("page.title", mProjectDir);
+ hdf.setValue("projectDir", mProjectDir);
+ hdf.setValue("projectTitle", mTitle);
+ //add the download/project links to the landing pages.
+ hdf.setValue("samplesProjectIndex", "true");
+ if (!f.isFile()) {
+ //The directory didn't have an _index.jd, so create a stub.
+ ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
+ } else {
+ DocFile.writePage(filename, rel, mDest + "index" + Doclava.htmlExtension, hdf);
+ PageMetadata.setPageMetadata(f, rel, mDest + "index" + Doclava.htmlExtension,
+ hdf, Doclava.sTaglist);
+ }
+ } else if (f.isFile()) {
+ //gather metadata for toc and jd_lists_unified
+ DocFile.getPageMetadata(filename, hdf);
mGroup = hdf.getValue("sample.group", "");
- if (mGroup.equals("")) {
+ if (!"".equals(mGroup)) {
+ tnode.setGroup(hdf.getValue("sample.group", ""));
+ } else {
//Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
// + ": Root _index.jd must be present and must define sample.group"
// + " tag. Please see ... for details.");
- } else {
- tnode.setGroup(hdf.getValue("sample.group", ""));
}
}
return tnode;
}
/**
- * Keep track of file parents
+ * Sets metadata for managing html output and generates the project view page
+ * for a project.
+ *
+ * @param dir The project root dir.
+ * @param hdf The data to read/write for files in this project.
+ */
+ public void writeProjectStructure(String dir, Data hdf) {
+ hdf.setValue("projectStructure", "true");
+ hdf.setValue("projectDir", mProjectDir);
+ hdf.setValue("page.title", mProjectDir + " Structure");
+ hdf.setValue("projectTitle", mTitle);
+ ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension);
+ hdf.setValue("projectStructure", "");
+ }
+
+ /**
+ * Keeps track of each file's parent dirs. Used for generating path breadcrumbs in html.
+ *
+ * @param dir The data to read/write for this file.
+ * @param hdf The relative path for this file, from samples root.
+ * @param subdir The relative path for this file, from samples root.
+ * @param name The name of the file (minus extension).
+ * @param isFile Whether this is a file (not a dir).
*/
Data setParentDirs(Data hdf, String subdir, String name, Boolean isFile) {
- //set whether to linkify the crumb dirs on each sample code page
- hdf.setValue("pathCrumbLinks", "");
- //isFile = false;
+ if (FULL_TREE_NAVIGATION) {
+ hdf.setValue("linkfyPathCrumb", "");
+ }
int iter;
hdf.removeTree("parentdirs");
String s = subdir;
String urlParts[] = s.split("/");
- //int n, l = (isFile)?1:0;
int n, l = 1;
- //System.out.println("setParentDirs for " + subdir + name);
for (iter=1; iter < urlParts.length; iter++) {
n = iter-1;
- //System.out.println("parentdirs." + n + ".Name == " + urlParts[iter]);
hdf.setValue("parentdirs." + n + ".Name", urlParts[iter]);
hdf.setValue("parentdirs." + n + ".Link", subdir + "index" + Doclava.htmlExtension);
}
@@ -313,20 +357,16 @@
}
/**
- * Write a templated source code file to out.
+ * Writes a templated source code file to out.
*/
- public void writePage(File f, String out, String subdir) {
+ public void writePage(File f, String out, String subdir, Data hdf) {
String name = f.getName();
String path = f.getPath();
- String data =
- SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path, "sample code",
- true, true, true, true);
+ String data = SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path,
+ "sample code", true, true, true, true);
data = Doclava.escape(data);
- Data hdf = Doclava.makeHDF();
-
String relative = subdir.replaceFirst("samples/", "");
- hdf.setValue("samples", "true");
setParentDirs(hdf, subdir, name, true);
hdf.setValue("projectTitle", mTitle);
hdf.setValue("projectDir", mProjectDir);
@@ -336,17 +376,21 @@
hdf.setValue("realFile", name);
hdf.setValue("fileContents", data);
hdf.setValue("resTag", "sample");
- hdf.setValue("resType", "Sample Code");
ClearPage.write(hdf, "sample.cs", out);
}
/**
- * Write a templated image or video file to out.
+ * Writes a templated image or video file to out.
*/
public void writeImageVideoPage(File f, String out, String subdir,
- String resourceType, boolean browsable) {
+ String resourceType, boolean browsable) {
Data hdf = Doclava.makeHDF();
+ if (Doclava.samplesNavTree != null) {
+ hdf.setValue("samples_toc_tree", Doclava.samplesNavTree.getValue("samples_toc_tree", ""));
+ }
+ hdf.setValue("samples", "true");
+
String name = f.getName();
if (!browsable) {
hdf.setValue("noDisplay", "true");
@@ -359,16 +403,24 @@
hdf.setValue("subdir", subdir);
hdf.setValue("resType", resourceType);
hdf.setValue("realFile", name);
+
ClearPage.write(hdf, "sample.cs", out);
}
/**
- * Render a SC node tree to a navtree js file.
+ * Given a node containing sample code projects and a node containing all valid
+ * group nodes, extract project nodes from tnode and append them to the group node
+ * that matches their sample.group metadata.
+ *
+ * @param tnode A list of nodes containing sample code projects.
+ * @param groupnodes A list of nodes that represent the valid sample groups.
+ * @return The groupnodes list with all projects appended properly to their
+ * associated sample groups.
*/
public static void writeSamplesNavTree(List<Node> tnode, List<Node> groupnodes) {
- Node node = new
- Node.Builder().setLabel("Reference").setLink("packages.html").setChildren(tnode).build();
+ Node node = new Node.Builder().setLabel("Samples").setLink(ClearPage.toroot
+ + "samples/index" + Doclava.htmlExtension).setChildren(tnode).build();
if (groupnodes != null) {
for (int i = 0; i < tnode.size(); i++) {
@@ -380,25 +432,19 @@
if (groupnodes.get(n).getChildren() == null) {
groupnodes.remove(n);
n--;
+ } else {
+ Collections.sort(groupnodes.get(n).getChildren(), byLabel);
}
}
node.setChildren(groupnodes);
}
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);
+ node.renderGroupNodesTOC(buf);
+ if (Doclava.samplesNavTree != null) {
+ Doclava.samplesNavTree.setValue("samples_toc_tree", buf.toString());
}
- Data data = Doclava.makeHDF();
- data.setValue("reference_tree", buf.toString());
- ClearPage.write(data, "samples_navtree_data.cs", "samples_navtree_data.js");
}
/**
@@ -424,7 +470,7 @@
}
/**
- * Sort by type and name (alpha), with manifest and src always at top.
+ * Sorts an array of files by type and name (alpha), with manifest always at top.
*/
Comparator<File> byTypeAndName = new Comparator<File>() {
public int compare (File one, File other) {
@@ -441,22 +487,27 @@
};
/**
- * Concatenate dirs that only hold dirs to simplify nav tree
+ * Sorts a list of Nodes by label.
+ */
+ public static Comparator<Node> byLabel = new Comparator<Node>() {
+ public int compare(Node one, Node other) {
+ return one.getLabel().compareTo(other.getLabel());
+ }
+ };
+
+ /**
+ * Concatenates dirs that only hold dirs, to simplify nav tree
*/
public static List<Node> squashNodes(List<Node> tnode) {
List<Node> list = tnode;
for(int i = 0; i < list.size(); ++i) {
- //only squash dirs that contain another dir whose list size is 1 and
- //that don't contain endpoints
if (("dir".equals(list.get(i).getType())) &&
(list.size() == 1) &&
(list.get(i).getChildren().get(0).getChildren() != null)) {
String thisLabel = list.get(i).getLabel();
String childLabel = list.get(i).getChildren().get(0).getLabel();
String newLabel = thisLabel + "/" + childLabel;
- //Set label of parent and mChildren to those of child-child, skipping
- //squashed dir
list.get(i).setLabel(newLabel);
list.get(i).setChildren(list.get(i).getChildren().get(0).getChildren());
} else {
@@ -466,6 +517,59 @@
return list;
}
+ public static String convertExtension(String s, String ext) {
+ return s.substring(0, s.lastIndexOf('.')) + ext;
+ }
+
+ /**
+ * Whitelists of valid image/video and source code types.
+ */
+ public static String[] IMAGES = {".png", ".jpg", ".gif"};
+ public static String[] VIDEOS = {".mp4", ".ogv", ".webm"};
+ public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"};
+
+ public static boolean inList(String s, String[] list) {
+ for (String t : list) {
+ if (s.endsWith(t)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Maps filenames to a set of generic types. Used for displaying files/dirs
+ * in the project view page.
+ */
+ public static String mapTypes(String name) {
+ String type = name.substring(name.lastIndexOf('.') + 1, name.length());
+ if ("xml".equals(type) || "java".equals(type)) {
+ if ("AndroidManifest.xml".equals(name)) type = "manifest";
+ return type;
+ } else {
+ return type = "file";
+ }
+ }
+
+ /**
+ * Validates a source file from a project against restrictions to determine
+ * whether to include the file in the browsable project output.
+ */
+ public boolean isValidFiletype(String name) {
+ if (name.startsWith(".") ||
+ name.startsWith("_") ||
+ "default.properties".equals(name) ||
+ "build.properties".equals(name) ||
+ name.endsWith(".ttf") ||
+ name.endsWith(".gradle") ||
+ name.endsWith(".bat") ||
+ "Android.mk".equals(name)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+
/**
* SampleCode variant of NavTree node.
*/
@@ -473,7 +577,6 @@
private String mLabel;
private String mLink;
private String mGroup; // from sample.group in _index.jd
- private List<String> mTags; // from page.tags in _index.jd
private List<Node> mChildren;
private String mType;
@@ -481,150 +584,114 @@
mLabel = builder.mLabel;
mLink = builder.mLink;
mGroup = builder.mGroup;
- mTags = builder.mTags;
mChildren = builder.mChildren;
mType = builder.mType;
}
public static class Builder {
private String mLabel, mLink, mGroup, mType;
- private List<String> mTags = null;
private List<Node> mChildren = null;
public Builder setLabel(String mLabel) { this.mLabel = mLabel; return this;}
public Builder setLink(String mLink) { this.mLink = mLink; return this;}
public Builder setGroup(String mGroup) { this.mGroup = mGroup; return this;}
- public Builder setTags(List<String> mTags) { this.mTags = mTags; return this;}
public Builder setChildren(List<Node> mChildren) { this.mChildren = mChildren; return this;}
public Builder setType(String mType) { this.mType = mType; return this;}
public Node build() {return new Node(this);}
}
- public Node(String mLabel,
- String mLink,
- String mGroup,
- List<String> mTags,
- List<Node> mChildren,
- String mType) {
- this.mLabel = mLabel;
- this.mLink = mLink;
- this.mGroup = mGroup;
- this.mTags = mTags;
- this.mChildren = mChildren;
- this.mType = mType; }
-
- 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) {
+ /**
+ * Renders browsable sample groups and projects to an html list, starting
+ * from the group nodes and then rendering their project nodes and finally their
+ * child dirs and files.
+ */
+ void renderGroupNodesTOC(StringBuilder buf) {
List<Node> 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");
+ return;
} 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(", ");
+ final int n = list.size();
+ for (int i = 0; i < n; i++) {
+ if (list.get(i).getChildren() == null) {
+ continue;
+ } else {
+ buf.append("<li class=\"nav-section\">");
+ buf.append("<div class=\"nav-section-header\">");
+ buf.append("<a href=\"" + list.get(i).getLink() + "\" title=\""
+ + list.get(i).getLabel() + "\">"
+ + list.get(i).getLabel() + "</a>");
+ buf.append("</div>");
+ buf.append("<ul>");
+ list.get(i).renderProjectNodesTOC(buf);
}
}
- buf.append(" ]\n");
+ buf.append("</ul>");
+ buf.append("</li>");
}
}
- void renderTags(StringBuilder buf) {
- List<String> list = mTags;
+ /**
+ * Renders a list of sample code projects associated with a group node.
+ */
+ void renderProjectNodesTOC(StringBuilder buf) {
+ List<Node> list = mChildren;
+ if (list == null || list.size() == 0) {
+ return;
+ } else {
+ final int n = list.size();
+ for (int i = 0; i < n; i++) {
+ if (list.get(i).getChildren() == null) {
+ continue;
+ } else {
+ buf.append("<li class=\"nav-section\">");
+ buf.append("<div class=\"nav-section-header\">");
+ buf.append("<a href=\"" + list.get(i).getLink() + "\" title=\""
+ + list.get(i).getLabel() + "\">"
+ + list.get(i).getLabel() + "</a>");
+ buf.append("</div>");
+ buf.append("<ul>");
+ list.get(i).renderChildrenToc(buf);
+ }
+ }
+ buf.append("</ul>");
+ buf.append("</li>");
+ }
+ }
+
+ /**
+ * Renders child dirs and files associated with a project node.
+ */
+ void renderChildrenToc(StringBuilder buf) {
+ List<Node> list = mChildren;
if (list == null || list.size() == 0) {
buf.append("null");
} else {
- buf.append("[ ");
- final int N = list.size();
- for (int i = 0; i < N; i++) {
- String tagval = list.get(i).toString();
- buf.append('"');
- final int L = tagval.length();
- for (int t = 0; t < L; t++) {
- char c = tagval.charAt(t);
- if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
- buf.append(c);
- } else {
- buf.append("\\u");
- for (int m = 0; m < 4; m++) {
- char x = (char) (c & 0x000f);
- if (x > 10) {
- x = (char) (x - 10 + 'a');
- } else {
- x = (char) (x + '0');
- }
- buf.append(x);
- c >>= 4;
- }
- }
+ final int n = list.size();
+ for (int i = 0; i < n; i++) {
+ if (list.get(i).getChildren() == null) {
+ buf.append("<li>");
+ buf.append("<a href=\"" + list.get(i).getLink() + "\" title=\""
+ + list.get(i).getLabel() + "\">"
+ + list.get(i).getLabel() + "</a>");
+ buf.append(" </li>");
+ } else {
+ buf.append("<li class=\"nav-section sticky\">");
+ buf.append("<div class=\"nav-section-header empty\">");
+ buf.append("<a href=\"#\" onclick=\"return false;\" title=\""
+ + list.get(i).getLabel() + "\">"
+ + list.get(i).getLabel() + "/</a>");
+ buf.append("</div>");
+ buf.append("<ul>");
+ list.get(i).renderChildrenToc(buf);
}
- buf.append('"');
- if (i != N - 1) {
- buf.append(", ");
- }
}
- buf.append(" ]");
+ buf.append("</ul>");
+ buf.append("</li>");
}
}
- void render(StringBuilder buf) {
- buf.append("[ ");
- renderString(buf, mLabel);
- buf.append(", ");
- renderString(buf, mLink);
- buf.append(", ");
- renderString(buf, mGroup);
- buf.append(", ");
- renderTags(buf);
- buf.append(", ");
- renderChildren(buf);
- buf.append(", ");
- renderString(buf, mType);
- buf.append(" ]");
- }
-
- public List<Node> getChildren() {
- if (mChildren != null) {
- return mChildren;
- } else {
- return null;
- }
- }
-
- public void setChildren(List<Node> node) {
- mChildren = node;
- }
-
+ /**
+ * Node getters and setters
+ */
public String getLabel() {
return mLabel;
}
@@ -633,16 +700,12 @@
mLabel = label;
}
- public String getType() {
- return mType.toString();
- }
-
- public String getHref() {
+ public String getLink() {
return mLink;
}
- public void setHref(String link) {
- mLink = link;
+ public void setLink(String ref) {
+ mLink = ref;
}
public String getGroup() {
@@ -653,157 +716,20 @@
mGroup = group;
}
- public void setTags(String tags) {
- List<String> tagList = new ArrayList();
- String[] tagParts = tags.split(",");
-
- for (int iter = 0; iter < tagParts.length; iter++) {
- String item = tagParts[iter].replaceAll("\"", "").trim();
- tagList.add(item);
- }
- mTags = tagList;
- }
- }
-
- /**
- * Write the project's templated _index.html
- * @deprecated
- *
- */
- public void writeProjectIndex(Data hdf) {
- //System.out.println(">>-- writing project index for " + mDest );
- hdf.setValue("projectDir", mProjectDir);
- hdf.setValue("page.title", mProjectDir + " Sample");
- hdf.setValue("projectTitle", mTitle);
- ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
- }
-
- /**
- * Grab the contents of an _index.html summary from a dir.
- * @deprecated
- */
- public void getSummaryFromDir(Data hdf, File dir, String key) {
- //System.out.println("Getting summary for " + dir + "/_index.html");
- hdf.setValue("summary", "");
- hdf.setValue("summaryFlag", "");
- 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;
- }
- }
-
- /**
- * @deprecated
- */
- public void writeDirectory(File dir, String relative, boolean offline) {
- TreeSet<String> dirs = new TreeSet<String>();
- TreeSet<String> files = new TreeSet<String>();
-
- String subdir = relative; // .substring(mDest.length());
-
- for (File f : dir.listFiles()) {
- String name = f.getName();
- if (name.startsWith(".") || name.startsWith("_")) {
- continue;
- }
- if (f.isFile()) {
- String out = relative + name;
- if (inList(out, IMAGES)) {
- // copied directly
- ClearPage.copyFile(false, f, out);
- writeImagePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
- files.add(name);
- }
- if (inList(out, TEMPLATED)) {
- // copied and goes through the template
- ClearPage.copyFile(false, f, out);
- writePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
- files.add(name);
-
- }
- // else ignored
- } else if (f.isDirectory()) {
- writeDirectory(f, relative + name + "/", offline);
- dirs.add(name);
- }
+ public List<Node> getChildren() {
+ return mChildren;
}
- // write the index page
- int i;
-
- Data hdf = writeIndex(dir);
- hdf.setValue("subdir", subdir);
- i = 0;
- for (String d : dirs) {
- 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"));
- i++;
+ public void setChildren(List<Node> node) {
+ mChildren = node;
}
- if (!offline) relative = "/" + relative;
- ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
- }
-
- /**
- * @deprecated
- */
- 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);
- }
-
- /**
- * @deprecated
- */
- public Data writeIndex(File dir) {
- Data hdf = Doclava.makeHDF();
- hdf.setValue("page.title", dir.getName() + " - " + mTitle);
- 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) {
- summary = "";
+ public String getType() {
+ return mType;
}
- hdf.setValue("summary", summary);
- return hdf;
- }
-
- /**
- * @deprecated
- */
- public void writeImagePage(File f, String out, String subdir) {
- Data hdf = Doclava.makeHDF();
- String name = f.getName();
-
- hdf.setValue("samples", "true");
- setParentDirs(hdf, subdir, name, true);
- hdf.setValue("page.title", name);
- hdf.setValue("projectTitle", mTitle);
- hdf.setValue("projectDir", mProjectDir);
- hdf.setValue("subdir", subdir);
- hdf.setValue("realFile", name);
- hdf.setValue("resTag", "sample");
- hdf.setValue("resType", "sampleImage");
- ClearPage.write(hdf, "sample.cs", out);
+ public void setType(String type) {
+ mType = type;
+ }
}
}