Home | History | Annotate | Download | only in doclava
      1 /*
      2  * Copyright (C) 2010 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.doclava;
     18 import com.google.clearsilver.jsilver.data.Data;
     19 
     20 import java.util.*;
     21 import java.io.*;
     22 import java.util.regex.Pattern;
     23 import java.util.regex.Matcher;
     24 
     25 public class SampleCode {
     26   String mSource;
     27   String mDest;
     28   String mTitle;
     29   String mProjectDir;
     30   String mTags;
     31 
     32   public SampleCode(String source, String dest, String title) {
     33     mSource = source;
     34     mTitle = title;
     35     mTags = null;
     36 
     37     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       }
     44     }
     45     //System.out.println("SampleCode init: source: " + mSource);
     46     //System.out.println("SampleCode init: dest: " + mDest);
     47     //System.out.println("SampleCode init: title: " + mTitle);
     48 
     49   }
     50 
     51   public Node write(boolean offlineMode) {
     52     List<Node> filelist = new ArrayList<Node>();
     53     File f = new File(mSource);
     54     mProjectDir = f.getName();
     55     String name = mProjectDir;
     56     String startname = name;
     57     String subdir = mDest;
     58     String mOut = subdir + name;
     59     if (!f.isDirectory()) {
     60       System.out.println("-samplecode not a directory: " + mSource);
     61       return null;
     62     }
     63 
     64     if (offlineMode)
     65       writeIndexOnly(f, mDest, offlineMode);
     66     else {
     67       Data hdf = Doclava.makeHDF();
     68       hdf.setValue("samples", "true");
     69       hdf.setValue("projectDir", mProjectDir);
     70       writeProjectDirectory(filelist, f, mDest, false, hdf, "Files.");
     71       writeProjectStructure(name, hdf);
     72       hdf.removeTree("parentdirs");
     73       hdf.setValue("parentdirs.0.Name", name);
     74       //Write root _index.jd to out and add metadata to Node.
     75       Node rootNode = writeProjectIndexCs(hdf, f, null, new Node(mProjectDir,
     76           "samples/" + startname + "/index.html", null, null, filelist, null));
     77       // return a root SC node for the sample with children appended
     78       return rootNode;
     79     }
     80     return null;
     81   }
     82 
     83   public static String convertExtension(String s, String ext) {
     84     return s.substring(0, s.lastIndexOf('.')) + ext;
     85   }
     86 
     87   public static String[] IMAGES = {".png", ".jpg", ".gif"};
     88   public static String[] TEMPLATED = {".java", ".xml", ".aidl", ".rs",".txt", ".TXT"};
     89 
     90   public static boolean inList(String s, String[] list) {
     91     for (String t : list) {
     92       if (s.endsWith(t)) {
     93         return true;
     94       }
     95     }
     96     return false;
     97   }
     98 
     99   public static String mapTypes(String name) {
    100     String type = name.substring(name.lastIndexOf('.') + 1, name.length());
    101     if (type.equals("xml") || type.equals("java")) {
    102       if (name.equals("AndroidManifest.xml")) type = "manifest";
    103       return type;
    104     } else {
    105       return type = "file";
    106     }
    107   }
    108 
    109   public void writeProjectDirectory(List<Node> parent, File dir, String relative, Boolean recursed, Data hdf, String newkey) {
    110     TreeSet<String> dirs = new TreeSet<String>(); //dirs for project structure and breadcrumb
    111     TreeSet<String> files = new TreeSet<String>(); //files for project structure and breadcrumb
    112 
    113     String subdir = relative;
    114     String name = "";
    115     String label = "";
    116     String link = "";
    117     String type = "";
    118     int i = 0;
    119     String expansion = ".Sub.";
    120     String key = newkey;
    121 
    122     if (recursed) {
    123       key = (key + expansion);
    124     } else {
    125       expansion = "";
    126     }
    127 
    128     File[] dirContents = dir.listFiles();
    129     Arrays.sort(dirContents, byTypeAndName);
    130     for (File f: dirContents) {
    131       name = f.getName();
    132       // don't process certain types of files
    133       if (name.startsWith(".") ||
    134           name.startsWith("_") ||
    135           name.equals("default.properties") ||
    136           name.equals("build.properties") ||
    137           name.endsWith(".ttf") ||
    138           name.endsWith(".gradle") ||
    139           name.endsWith(".bat") ||
    140           name.equals("Android.mk")) {
    141          //System.out.println("Invalid File Type, bypassing: " + name);
    142          continue;
    143        }
    144        if (f.isFile() && name.contains(".")){
    145          String path = relative + name;
    146          type = mapTypes(name);
    147          link = convertExtension(path, ".html");
    148          hdf.setValue("samples", "true");//dd needed?
    149          if (inList(path, IMAGES)) {
    150            // copy these files to output directly
    151            type = "img";
    152            ClearPage.copyFile(false, f, path);
    153            writeImagePage(f, convertExtension(path, Doclava.htmlExtension), relative);
    154            files.add(name);
    155            hdf.setValue(key + i + ".Type", "img");
    156            hdf.setValue(key + i + ".Name", name);
    157            hdf.setValue(key + i + ".Href", link);
    158            hdf.setValue(key + i + ".RelPath", relative);
    159          }
    160          if (inList(path, TEMPLATED)) {
    161            // copied and goes through the template
    162            ClearPage.copyFile(false, f, path);
    163            writePage(f, convertExtension(path, Doclava.htmlExtension), relative);
    164            files.add(name);
    165            hdf.setValue(key + i + ".Type", type);
    166            hdf.setValue(key + i + ".Name", name);
    167            hdf.setValue(key + i + ".Href", link);
    168            hdf.setValue(key + i + ".RelPath", relative);
    169          }
    170          // add file to the navtree
    171          parent.add(new Node(name, link, null, null, null, type));
    172          i++;
    173        } else if (f.isDirectory()) {
    174          List<Node> mchildren = new ArrayList<Node>();
    175          type = "dir";
    176          String dirpath = relative + name;
    177          link = dirpath + "/index.html";
    178          String hdfkeyName = (key + i + ".Name");
    179          String hdfkeyType = (key + i + ".Type");
    180          String hdfkeyHref = (key + i + ".Href");
    181          hdf.setValue(hdfkeyName, name);
    182          hdf.setValue(hdfkeyType, type);
    183          hdf.setValue(hdfkeyHref, relative + name + "/" + "index.html");
    184          //System.out.println("Found directory, recursing. Current key: " + hdfkeyName);
    185          writeProjectDirectory(mchildren, f, relative + name + "/", true, hdf, (key + i));
    186          if (mchildren.size() > 0) {
    187            //dir is processed, now add it to the navtree
    188            //don't link sidenav subdirs at this point (but can use "link" to do so)
    189           parent.add(new Node(name, null, null, null, mchildren, type));
    190          }
    191          dirs.add(name);
    192          i++;
    193        }
    194 
    195     }
    196     //dd not working yet
    197     //Get summary from any _index files in any project dirs (currently disabled)
    198     //  getSummaryFromDir(hdf, dir, newkey);
    199     //If this is an index for the project root (assumed root if split length is 3 (development/samples/nn)),
    200     //then remove the root dir so that it won't appear in the breadcrumb. Else just pass it through to
    201     //setParentDirs as usual.
    202     String mpath = dir + "";
    203     String sdir[] = mpath.split("/");
    204     if (sdir.length == 3 ) {
    205       System.out.println("-----------------> this must be the root: [sdir len]" + sdir.length + "[dir]" + dir);
    206       hdf.setValue("showProjectPaths","true");//dd remove here?
    207     }
    208     setParentDirs(hdf, relative, name, false);
    209     //Generate an index.html page for each dir being processed
    210     ClearPage.write(hdf, "sampleindex.cs", relative + "/index" + Doclava.htmlExtension);
    211     //concatenate dirs in the navtree. Comment out or remove to restore normal navtree
    212     squashNodes(parent);
    213   }
    214 
    215   public void writeProjectStructure(String dir, Data hdf) {
    216       //System.out.println(">>-- writing project structure for " + dir );
    217       hdf.setValue("projectStructure", "true");
    218       hdf.setValue("projectDir", mProjectDir);
    219       hdf.setValue("page.title", mProjectDir + " Structure");
    220       hdf.setValue("projectTitle", mTitle);
    221       //write the project.html file
    222       ClearPage.write(hdf, "sampleindex.cs", mDest + "project" + Doclava.htmlExtension);
    223       hdf.setValue("projectStructure", "");
    224   }
    225 
    226   /**
    227   * Processes a templated project index page from _index.jd in a project root.
    228   * Each sample project must have an index, and each index locally defines it's own
    229   * page.tags and sample.group cs vars. This method takes a SC node on input, reads
    230   * any local vars from the _index.jd, generates an html file to out, then updates
    231   * the SC node with the page vars and returns it to the caller.
    232   *
    233   */
    234   public Node writeProjectIndexCs(Data hdf, File dir, String key, Node tnode) {
    235     //hdf.setValue("summary", "");
    236     //hdf.setValue("summaryFlag", "");
    237     String filename = dir.getAbsolutePath() + "/_index.jd";
    238     File f = new File(filename);
    239     String rel = dir.getPath();
    240     String mGroup = "";
    241     hdf.setValue("samples", "true");
    242     //set any default page variables for root index
    243     hdf.setValue("page.title", mProjectDir);
    244     hdf.setValue("projectDir", mProjectDir);
    245     hdf.setValue("projectTitle", mTitle);
    246 
    247     if (!f.isFile()) {
    248       //The sample didn't have any _index.jd, so create a stub.
    249       ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
    250       //Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
    251       //          + ": Root _index.jd must be present and must define sample.group"
    252       //          + " tag. Please see ... for details.");
    253     } else {
    254       DocFile.writePage(filename, rel, mDest + "index" + Doclava.htmlExtension, hdf);
    255       tnode.setTags(hdf.getValue("page.tags", ""));
    256       mGroup = hdf.getValue("sample.group", "");
    257       if (mGroup.equals("")) {
    258         //Errors.error(Errors.INVALID_SAMPLE_INDEX, null, "Sample " + mProjectDir
    259         //          + ": Root _index.jd must be present and must define sample.group"
    260         //          + " tag. Please see ... for details.");
    261       } else {
    262       tnode.setGroup(hdf.getValue("sample.group", ""));
    263       }
    264     }
    265     return tnode;
    266   }
    267 
    268   /**
    269   * Keep track of file parents
    270   */
    271   Data setParentDirs(Data hdf, String subdir, String name, Boolean isFile) {
    272     //set whether to linkify the crumb dirs on each sample code page
    273     hdf.setValue("pathCrumbLinks", "");
    274         //isFile = false;
    275     int iter;
    276     hdf.removeTree("parentdirs");
    277     String s = subdir;
    278     String urlParts[] = s.split("/");
    279     //int n, l = (isFile)?1:0;
    280     int n, l = 1;
    281     //System.out.println("setParentDirs for " + subdir + name);
    282     for (iter=1; iter < urlParts.length; iter++) {
    283       n = iter-1;
    284       //System.out.println("parentdirs." + n + ".Name == " + urlParts[iter]);
    285       hdf.setValue("parentdirs." + n + ".Name", urlParts[iter]);
    286       hdf.setValue("parentdirs." + n + ".Link", subdir + "index" + Doclava.htmlExtension);
    287     }
    288     return hdf;
    289   }
    290 
    291   /**
    292   * Write a templated source code file to out.
    293   */
    294   public void writePage(File f, String out, String subdir) {
    295     String name = f.getName();
    296     String path = f.getPath();
    297     String data =
    298         SampleTagInfo.readFile(new SourcePositionInfo(path, -1, -1), path, "sample code",
    299             true, true, true, true);
    300     data = Doclava.escape(data);
    301 
    302     Data hdf = Doclava.makeHDF();
    303 
    304     String relative = subdir.replaceFirst("samples/", "");
    305     hdf.setValue("samples", "true");
    306     setParentDirs(hdf, subdir, name, true);
    307     hdf.setValue("projectTitle", mTitle);
    308     hdf.setValue("projectDir", mProjectDir);
    309     hdf.setValue("page.title", name);
    310     hdf.setValue("subdir", subdir);
    311     hdf.setValue("relative", relative);
    312     hdf.setValue("realFile", name);
    313     hdf.setValue("fileContents", data);
    314     hdf.setValue("resTag", "sample");
    315     hdf.setValue("resType", "Sample Code");
    316 
    317     ClearPage.write(hdf, "sample.cs", out);
    318   }
    319 
    320   /**
    321   * Write a templated image file to out.
    322   */
    323   public void writeImagePage(File f, String out, String subdir) {
    324     String name = f.getName();
    325 
    326     String data = "<img src=\"" + name + "\" title=\"" + name + "\" />";
    327 
    328     Data hdf = Doclava.makeHDF();
    329     hdf.setValue("samples", "true");
    330     setParentDirs(hdf, subdir, name, true);
    331     hdf.setValue("page.title", name);
    332     hdf.setValue("projectTitle", mTitle);
    333     hdf.setValue("projectDir", mProjectDir);
    334     hdf.setValue("subdir", subdir);
    335     hdf.setValue("realFile", name);
    336     hdf.setValue("fileContents", data);
    337     hdf.setValue("resTag", "sample");
    338     hdf.setValue("resType", "Sample Code");
    339     ClearPage.write(hdf, "sample.cs", out);
    340   }
    341 
    342   /**
    343   * Render a SC node tree to a navtree js file.
    344   */
    345   public static void writeSamplesNavTree(List<Node> tnode, List<Node> groupnodes) {
    346 
    347     Node node = new Node("Reference", "packages.html", null, null, tnode, null);
    348 
    349     if (groupnodes != null) {
    350       for (int i = 0; i < tnode.size(); i++) {
    351         groupnodes = appendNodeGroups(tnode.get(i), groupnodes);
    352       }
    353       for (int n = 0; n < groupnodes.size(); n++) {
    354         if (groupnodes.get(n).getChildren() == null) {
    355           groupnodes.remove(n);
    356           n--;
    357         }
    358       }
    359       node.setChildren(groupnodes);
    360     }
    361 
    362     StringBuilder buf = new StringBuilder();
    363     if (false) {
    364     // if you want a root node
    365       buf.append("[");
    366       node.render(buf);
    367       buf.append("]");
    368     } else {
    369       // if you don't want a root node
    370       node.renderChildren(buf);
    371     }
    372 
    373     Data data = Doclava.makeHDF();
    374     data.setValue("reference_tree", buf.toString());
    375     ClearPage.write(data, "samples_navtree_data.cs", "samples_navtree_data.js");
    376   }
    377 
    378   /**
    379   * For a given project root node, get the group and then iterate the list of valid
    380   * groups looking for a match. If found, append the project to that group node.
    381   * Samples the reference a valid sample group tag are added to a list for that
    382   * group. Samples declare a sample.group tag in their _index.jd files.
    383   */
    384   private static List<Node> appendNodeGroups(Node gNode, List<Node> groupnodes) {
    385     List<Node> mgrouplist = new ArrayList<Node>();
    386     for (int i = 0; i < groupnodes.size(); i++) {
    387       if (groupnodes.get(i).getLabel().equals(gNode.getGroup())) {
    388         if (groupnodes.get(i).getChildren() == null) {
    389           mgrouplist.add(gNode);
    390           groupnodes.get(i).setChildren(mgrouplist);
    391         } else {
    392           groupnodes.get(i).getChildren().add(gNode);
    393         }
    394         break;
    395       }
    396     }
    397     return groupnodes;
    398   }
    399 
    400   /**
    401   * Sort by type and name (alpha), with manifest and src always at top.
    402   */
    403   Comparator<File> byTypeAndName = new Comparator<File>() {
    404     public int compare (File one, File other) {
    405       if (one.isDirectory() && !other.isDirectory()) {
    406         return 1;
    407       } else if (!one.isDirectory() && other.isDirectory()) {
    408         return -1;
    409       } else if (one.getName().equals("AndroidManifest.xml")) {
    410         return -1;
    411       } else if (one.getName().equals("src")) {
    412         return -1;
    413       } else {
    414         return one.compareTo(other);
    415       }
    416     }
    417   };
    418 
    419   /**
    420   * Concatenate dirs that only hold dirs to simplify nav tree
    421   */
    422   public static List<Node> squashNodes(List<Node> tnode) {
    423     List<Node> list = tnode;
    424 
    425     for(int i = 0; i < list.size(); ++i) {
    426       //only squash dirs that contain another dir whose list size is 1 and
    427       //that don't contain endpoints
    428       if ((list.get(i).getType().equals("dir")) &&
    429           (list.size() == 1) &&
    430           (list.get(i).getChildren().get(0).getChildren() != null)) {
    431         String thisLabel = list.get(i).getLabel();
    432         String childLabel =  list.get(i).getChildren().get(0).getLabel();
    433         String newLabel = thisLabel + "/" + childLabel;
    434         //Set label of parent and mChildren to those of child-child, skipping
    435         //squashed dir
    436         list.get(i).setLabel(newLabel);
    437         list.get(i).setChildren(list.get(i).getChildren().get(0).getChildren());
    438       } else {
    439         continue;
    440       }
    441     }
    442     return list;
    443   }
    444 
    445   /**
    446   * SampleCode variant of NavTree node.
    447   */
    448   public static class Node {
    449     private String mLabel;
    450     private String mLink;
    451     private String mGroup; // from sample.group in _index.jd
    452     private List<String> mTags; // from page.tags in _index.jd
    453     private List<Node> mChildren;
    454     private String mType;
    455 
    456     Node(String label, String link, String group, List<String> tags, List<Node> children, String type) {
    457       mLabel = label;
    458       mLink = link;
    459       mGroup = group;
    460       mTags = tags;
    461       mChildren = children;
    462       mType = type;
    463     }
    464 
    465     static void renderString(StringBuilder buf, String s) {
    466       if (s == null) {
    467         buf.append("null");
    468       } else {
    469         buf.append('"');
    470         final int N = s.length();
    471         for (int i = 0; i < N; i++) {
    472           char c = s.charAt(i);
    473           if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
    474             buf.append(c);
    475           } else {
    476             buf.append("\\u");
    477             for (int j = 0; i < 4; i++) {
    478               char x = (char) (c & 0x000f);
    479               if (x > 10) {
    480                 x = (char) (x - 10 + 'a');
    481               } else {
    482                 x = (char) (x + '0');
    483               }
    484               buf.append(x);
    485               c >>= 4;
    486             }
    487           }
    488         }
    489         buf.append('"');
    490       }
    491     }
    492 
    493     void renderChildren(StringBuilder buf) {
    494       List<Node> list = mChildren;
    495       if (list == null || list.size() == 0) {
    496         // We output null for no children. That way empty lists here can just
    497         // be a byproduct of how we generate the lists.
    498         buf.append("null");
    499       } else {
    500         buf.append("[ ");
    501         final int N = list.size();
    502         for (int i = 0; i < N; i++) {
    503           list.get(i).render(buf);
    504           if (i != N - 1) {
    505             buf.append(", ");
    506           }
    507         }
    508         buf.append(" ]\n");
    509       }
    510     }
    511 
    512     void renderTags(StringBuilder buf) {
    513       List<String> list = mTags;
    514       if (list == null || list.size() == 0) {
    515         buf.append("null");
    516       } else {
    517         buf.append("[ ");
    518         final int N = list.size();
    519         for (int i = 0; i < N; i++) {
    520           String tagval = list.get(i).toString();
    521           buf.append('"');
    522           final int L = tagval.length();
    523           for (int t = 0; t < L; t++) {
    524             char c = tagval.charAt(t);
    525             if (c >= ' ' && c <= '~' && c != '"' && c != '\\') {
    526               buf.append(c);
    527             } else {
    528               buf.append("\\u");
    529               for (int m = 0; m < 4; m++) {
    530                 char x = (char) (c & 0x000f);
    531                 if (x > 10) {
    532                   x = (char) (x - 10 + 'a');
    533                 } else {
    534                   x = (char) (x + '0');
    535                 }
    536                 buf.append(x);
    537                 c >>= 4;
    538               }
    539             }
    540           }
    541           buf.append('"');
    542           if (i != N - 1) {
    543             buf.append(", ");
    544           }
    545         }
    546         buf.append(" ]");
    547       }
    548     }
    549 
    550     void render(StringBuilder buf) {
    551       buf.append("[ ");
    552       renderString(buf, mLabel);
    553       buf.append(", ");
    554       renderString(buf, mLink);
    555       buf.append(", ");
    556       renderString(buf, mGroup);
    557       buf.append(", ");
    558       renderTags(buf);
    559       buf.append(", ");
    560       renderChildren(buf);
    561       buf.append(", ");
    562       renderString(buf, mType);
    563       buf.append(" ]");
    564     }
    565 
    566     public List<Node> getChildren() {
    567       if (mChildren != null) {
    568         return mChildren;
    569       } else {
    570         return null;
    571       }
    572     }
    573 
    574     public void setChildren(List<Node> node) {
    575         mChildren = node;
    576     }
    577 
    578     public String getLabel() {
    579       return mLabel;
    580     }
    581 
    582     public void setLabel(String label) {
    583        mLabel = label;
    584     }
    585 
    586     public String getType() {
    587       return mType.toString();
    588     }
    589 
    590     public String getHref() {
    591       return mLink;
    592     }
    593 
    594     public void setHref(String link) {
    595       mLink = link;
    596     }
    597 
    598     public String getGroup() {
    599       return mGroup;
    600     }
    601 
    602     public void setGroup(String group) {
    603       mGroup = group;
    604     }
    605 
    606     public void setTags(String tags) {
    607       List<String> tagList = new ArrayList();
    608       String[] tagParts = tags.split(",");
    609 
    610       for (int iter = 0; iter < tagParts.length; iter++) {
    611         String item = tagParts[iter].replaceAll("\"", "").trim();
    612         tagList.add(item);
    613       }
    614       mTags = tagList;
    615     }
    616   }
    617 
    618   /**
    619   * Write the project's templated _index.html
    620   * @deprecated
    621   *
    622   */
    623   public void writeProjectIndex(Data hdf) {
    624     //System.out.println(">>-- writing project index for " + mDest );
    625     hdf.setValue("projectDir", mProjectDir);
    626     hdf.setValue("page.title", mProjectDir + " Sample");
    627     hdf.setValue("projectTitle", mTitle);
    628     ClearPage.write(hdf, "sampleindex.cs", mDest + "index" + Doclava.htmlExtension);
    629   }
    630 
    631   /**
    632   * Grab the contents of an _index.html summary from a dir.
    633   * @deprecated
    634   */
    635   public void getSummaryFromDir(Data hdf, File dir, String key) {
    636     //System.out.println("Getting summary for " + dir + "/_index.html");
    637     hdf.setValue("summary", "");
    638     hdf.setValue("summaryFlag", "");
    639     String filename = dir.getPath() + "/_index.html";
    640     String summary = SampleTagInfo.readFile(new SourcePositionInfo(filename,
    641                           -1,-1), filename, "sample code", true, false, false, true);
    642     if (summary != null) {
    643       hdf.setValue(key + "SummaryFlag", "true");
    644       hdf.setValue("summary", summary);
    645       //set the target for [info] link
    646       //hdf.setValue(key + "Href", dir + "/index.html");
    647       //return true;
    648     }
    649   }
    650 
    651   /**
    652   * @deprecated
    653   */
    654   public void writeDirectory(File dir, String relative, boolean offline) {
    655     TreeSet<String> dirs = new TreeSet<String>();
    656     TreeSet<String> files = new TreeSet<String>();
    657 
    658     String subdir = relative; // .substring(mDest.length());
    659 
    660     for (File f : dir.listFiles()) {
    661       String name = f.getName();
    662       if (name.startsWith(".") || name.startsWith("_")) {
    663         continue;
    664       }
    665       if (f.isFile()) {
    666         String out = relative + name;
    667         if (inList(out, IMAGES)) {
    668           // copied directly
    669           ClearPage.copyFile(false, f, out);
    670           writeImagePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
    671           files.add(name);
    672         }
    673         if (inList(out, TEMPLATED)) {
    674           // copied and goes through the template
    675           ClearPage.copyFile(false, f, out);
    676           writePage(f, convertExtension(out, Doclava.htmlExtension), subdir);
    677           files.add(name);
    678 
    679         }
    680         // else ignored
    681       } else if (f.isDirectory()) {
    682         writeDirectory(f, relative + name + "/", offline);
    683         dirs.add(name);
    684       }
    685     }
    686 
    687     // write the index page
    688     int i;
    689 
    690     Data hdf = writeIndex(dir);
    691     hdf.setValue("subdir", subdir);
    692     i = 0;
    693     for (String d : dirs) {
    694       hdf.setValue("subdirs." + i + ".Name", d);
    695       hdf.setValue("files." + i + ".Href", convertExtension(d, ".html"));
    696       i++;
    697     }
    698     i = 0;
    699     for (String f : files) {
    700       hdf.setValue("files." + i + ".Name", f);
    701       hdf.setValue("files." + i + ".Href", convertExtension(f, ".html"));
    702       i++;
    703     }
    704 
    705     if (!offline) relative = "/" + relative;
    706     ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
    707   }
    708 
    709   /**
    710   * @deprecated
    711   */
    712   public void writeIndexOnly(File dir, String relative, Boolean offline) {
    713     Data hdf = writeIndex(dir);
    714     if (!offline) relative = "/" + relative;
    715 
    716       System.out.println("writing indexonly at " + relative + "/index" + Doclava.htmlExtension);
    717       ClearPage.write(hdf, "sampleindex.cs", relative + "index" + Doclava.htmlExtension);
    718   }
    719 
    720   /**
    721   * @deprecated
    722   */
    723   public Data writeIndex(File dir) {
    724     Data hdf = Doclava.makeHDF();
    725     hdf.setValue("page.title", dir.getName() + " - " + mTitle);
    726     hdf.setValue("projectTitle", mTitle);
    727 
    728     String filename = dir.getPath() + "/_index.html";
    729     String summary =
    730         SampleTagInfo.readFile(new SourcePositionInfo(filename, -1, -1), filename, "sample code",
    731             true, false, false, true);
    732 
    733     if (summary == null) {
    734       summary = "";
    735     }
    736     hdf.setValue("summary", summary);
    737 
    738     return hdf;
    739   }
    740 
    741 }
    742