package com.rectang.xsm.types;
import com.rectang.xsm.doc.*;
import com.rectang.xsm.io.PublishedFile;
import com.rectang.xsm.widget.HTMLTextArea;
import java.io.File;
import java.util.List;
import java.util.Iterator;
import java.util.Vector;
import org.jdom.Element;
public class Book
extends DocList
{
public static final SupportedOption GEN_TABLES = new SupportedOption( "GEN_TABLES",
"Generate the \"List of images\" and \"List of files\" pages", false );
public static final int DEPTH_CUTOFF = 4;
int[] index = new int[DEPTH_CUTOFF];
private Vector options;
String prev = null;
Vector contents = new Vector();
public Book( java.lang.String name )
{
super( name, new DocElement[]{new DocTree( "contents", new BookPage( "page" ) ),
new Gallery( "images" ), new Files( "files" )
} );
options = new Vector();
options.add( GEN_TABLES );
}
/* view maybe split into pieces with contents */
/* TODO make a nice edit layout
public void edit(Element node, String path, StringBuffer s) {
s.append("<p>You can <a href=\"XSM?action=page.edit&page=" + getPublishedPath());
s.append("&index=" + path + "/images@1\">edit</a> the books images<br>\n");
s.append("or <a href=\"XSM?action=page.edit&page=" + getPublishedPath());
s.append("&index=" + path + "/files@2\">edit</a> the books files<br>\n");
if (node.getChild("contents").getChildren("page").size() == 0) {
s.append("<a href=\"XSM?action=page.add&page=" + getPublishedPath());
s.append("&index=" + path + "/contents@0&addnode=page@0\">create");
s.append("</a> your books first page<br>\n");
} else
editKids(node.getChild("contents"), path + "/contents@0", path, "", s);
s.append("</p>");
}
*/
/* FIXME - need to insert some deletion code to remove stale page .htmls
* how to do this? do we remove the page that was deleted and ripple? */
/* TODO make a nice edit layout
private void editKids(Element node, String path, String root, String rel,
StringBuffer s) {
if (node.getChildren("page").size() == 0)
return;
Iterator children = node.getChildren("page").iterator();
s.append("<table border=\"0\">");
int counter = 0;
while (children.hasNext()) {
Element next = (Element) children.next();
String rootLink = "XSM?page=" + getPublishedPath() + "&index=" + root + "/contents@0&viewindex=" + root;
String movelink = rootLink + "&movenode=" + rel + "/page@" + counter + "&action=page.";
s.append("<tr><td>");
if (counter > 0) {
s.append("<a href=\"" + movelink + "up\"><img src=\"icons/go-up.png\"");
s.append("border=\"0\" alt=\"up\" title=\"up\"></a>");
}
s.append("<a href=\"" + rootLink + "&delnode=" + rel + "/page@" + counter);
s.append("&action=page.delete\"><img src=\"icons/edit-delete.png\" border=\"0\"");
s.append("alt=\"delete\" title=\"delete\"></a>\n");
if (children.hasNext()) {
s.append("<a href=\"" + movelink + "down\"><img src=\"icons/go-down.png\"");
s.append("border=\"0\" alt=\"down\" title=\"down\"></a>");
}
s.append("</td><td><a href=\"XSM?action=page.edit&page=" + getPublishedPath());
s.append("&index=" + path + "/page@" + counter + "\">");
s.append("edit</a> " + next.getChildText("title"));
if (next.getChildren("page").size() == 0) {
s.append("<font size=\"-2\">\t\t(<a href=\"XSM?action=page.add&page=");
s.append(getPublishedPath() + "&index=" + path + "/page@" + counter);
s.append("&addnode=page@0" + "\">... add a sub level ...</a>)</font>\n");
} else {
s.append("</td></tr><tr><td> </td><td>");
editKids(next, path + "/page@" + counter, root, rel + "/page@" + counter, s);
}
s.append("</td></tr>\n");
counter++;
}
s.append("<tr><td><a href=\"XSM?action=page.add&page=" + getPublishedPath());
s.append("&index=" + path + "&addnode=page@" + counter);
s.append("\"><img src=\"icons/document-new.png\" border=\"0\"");
s.append("alt=\"add page\" title=\"add page\"></a></td><td> </td></tr>\n");
s.append("</table>");
}
*/
public void publish( Element node, StringBuffer s )
{
List nodes = node.getChild( "contents" ).getChildren( elements[0].element
.getName() );
if ( nodes == null || nodes.size() == 0 )
{
return;
}
String pageDir = getPublishedPath() + File.separatorChar + "_pages"
+ File.separatorChar;
(getSite().getPublishedDoc( pageDir )).mkdir();
s.append( "<h2>Contents</h2>\n" );
generateContents( nodes.iterator(), "", 0, pageDir, s );
s.append( "<p>Or you can see the book in <a href=\"" );
s.append( getSite().getPrefixUrl() + pageDir );
s.append( "print.html\">1 page</a> (printer friendly).</p>" );
StringBuffer out;
if ( GEN_TABLES.getBoolean( getDoc() ) )
{
/* generate the gallery pages */
PublishedFile galleryFile = getSite().getPublishedDoc(
getPublishedPath() + File.separatorChar + "images.html" );
out = new StringBuffer();
elements[1].publish( node.getChild( "images" ), out );
getDoc().publishContent( galleryFile, out.toString(), getUser() );
/* generate the files page */
PublishedFile filesFile = getSite().getPublishedDoc(
getPublishedPath() + File.separatorChar + "files.html" );
out = new StringBuffer();
elements[2].publish( node.getChild( "files" ), out );
getDoc().publishContent( filesFile, out.toString(), getUser() );
}
generateContents( nodes.iterator(), 0, null );
generateView( nodes.iterator(), 0, pageDir, contents.iterator(), null );
/* output a single-page (printer friendly) version */
PublishedFile printFile = getSite().getPublishedDoc( pageDir
+ "print.html" );
out = new StringBuffer();
generateWholeView( nodes.iterator(), 0, out );
getDoc().publishContent( printFile, out.toString(), getUser() );
}
private void generateView( Iterator pages, int level, String dir,
Iterator contents, StringBuffer s )
{
if ( level < DEPTH_CUTOFF )
{
index[level] = 0;
}
if ( !pages.hasNext() )
{
return;
}
StringBuffer ret = new StringBuffer();
while ( pages.hasNext() )
{
Element next = (Element) pages.next();
StringBuffer content = new StringBuffer();
content.append( "<h2>" );
if ( level < DEPTH_CUTOFF )
{
index[level]++;
content.append( getId( level ) + " - " );
}
((BookPage) ((DocTree) elements[0]).element).elements[0]
.publish( next.getChild( "title" ), content );
content.append( "</h2>\n" );
((BookPage) ((DocTree) elements[0]).element).elements[1]
.publish( next.getChild( "content" ), content );
/* add sub page links if the sub pages are not to be included */
if ( level < DEPTH_CUTOFF - 1 )
{
if ( next.getChildren( "page" ).size() > 0 )
{
content.append( "\n<hr /><p class=\"footer\">Sub pages: <br />\n" );
Iterator subPages = next.getChildren( "page" ).iterator();
int counter = 0;
while ( subPages.hasNext() )
{
counter++;
Element child = (Element) subPages.next();
if ( next == null )
{
continue;
}
String title = child.getChildText( "title" );
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( dir + getId( level ) + "." + counter + ".html\">" );
content.append( title + "</a><br />\n" );
}
content.append( "</p>\n" );
}
}
else
{
ret.append( "<hr>\n" + content.toString() );
}
/* add the navigation links */
ContentElement nav = (ContentElement) contents.next();
content.append( "<hr /><table width=\"100%\" border=\"0\"><tr>" );
content.append( "<td width=\"33%\" align=\"center\">" );
if ( nav.prev == null )
{
content.append( " " );
}
else
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + "/_pages/" + nav.prev + ".html\">Previous</a>" );
}
content.append( "</td><td width=\"34%\" align=\"center\">" );
if ( level == 0 )
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + "/index.html\">Contents</a>" );
}
else
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( dir + getId( level - 1 ) + ".html\">Up</a>" );
}
content.append( "</td><td width=\"33%\" align=\"center\">" );
if ( nav.next == null )
{
content.append( " " );
}
else
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + "/_pages/" + nav.next + ".html\">Next</a>" );
}
content.append( "</td></tr></table>\n" );
StringBuffer sub = new StringBuffer();
generateView( next.getChildren( ((DocTree) elements[0]).element
.getName() ).iterator(), level + 1, dir, contents, sub );
PublishedFile out = getSite().getPublishedDoc( dir + getId( level ) + ".html" );
if ( level < DEPTH_CUTOFF - 1 )
{ // make our own page
getDoc().publishContent( out, content.toString(), getUser() );
}
else if ( level == DEPTH_CUTOFF - 1 )
{ // merge our page with subpages
getDoc().publishContent( out, content.toString() + sub.toString(), getUser() );
}
else // make no page, but pass our data up to be merged
{
ret.append( sub );
}
}
if ( level < DEPTH_CUTOFF )
{
return;
}
if ( s != null )
{
s.append( ret );
}
}
private class ContentElement
{
String prev, up, next;
public ContentElement( String prev, String up, String next )
{
this.prev = prev;
this.up = up;
this.next = next;
}
}
private void generateContents( Iterator pages, int level, String prev3 )
{
if ( level < DEPTH_CUTOFF )
{
index[level] = 0;
}
if ( !pages.hasNext() )
{
return;
}
while ( pages.hasNext() )
{
Element next = (Element) pages.next();
if ( level < DEPTH_CUTOFF )
{
index[level]++;
}
/* calculate the navigation links */
ContentElement elem = new ContentElement( prev, null, null );
contents.add( elem );
int thisPos = contents.indexOf( elem );
if ( thisPos > 0 )
{
((ContentElement) contents.get( thisPos - 1 )).next = getId( level );
}
prev = getId( level );
generateContents( next.getChildren( ((DocTree) elements[0]).element
.getName() ).iterator(), level + 1, getId( level ) );
}
}
private void generateWholeView( Iterator pages, int level, StringBuffer s )
{
if ( level < DEPTH_CUTOFF )
{
index[level] = 0;
}
if ( !pages.hasNext() )
{
return;
}
while ( pages.hasNext() )
{
Element next = (Element) pages.next();
s.append( "<h2>" );
if ( level < DEPTH_CUTOFF )
{
index[level]++;
s.append( "<a name=\"" + getId( level ) + "\">" + getId( level ) + "</a> - " );
}
((BookPage) ((DocTree) elements[0]).element).elements[0]
.publish( next.getChild( "title" ), s );
s.append( "</h2>\n" );
((BookPage) ((DocTree) elements[0]).element).elements[1]
.publish( next.getChild( "content" ), s );
s.append( "<hr>\n" );
generateWholeView( next.getChildren( ((DocTree) elements[0]).element
.getName() ).iterator(), level + 1, s );
}
}
private void generateContents( Iterator pages, String indent, int level,
String dir, StringBuffer s )
{
if ( level >= DEPTH_CUTOFF || !pages.hasNext() )
{
return;
}
index[level] = 0;
s.append( "<ul>" );
if ( level == 0 && GEN_TABLES.getBoolean( getDoc() ) )
{
s.append( "<li><a href=\"" + getSite().getPrefixUrl() );
s.append( getPublishedPath() + "/images.html\">List of images</a></li>\n" );
s.append( "<li><a href=\"" + getSite().getPrefixUrl() );
s.append( getPublishedPath() + "/files.html\">List of files</a></li>\n" );
}
while ( pages.hasNext() )
{
Element next = (Element) pages.next();
index[level]++;
s.append( "<li><a href=\"" + getSite().getPrefixUrl() );
s.append( dir + getId( level ) + ".html\">" + getId( level ) + " - " );
s.append( next.getChild( "title" ).getText() + "</a>\n" );
generateContents( next.getChildren( ((DocTree) elements[0])
.element.getName() ).iterator(), indent + "  ", level + 1,
dir, s );
s.append( "</li>\n" );
}
s.append( "</ul>" );
}
private String getId( int level )
{
if ( level < 0 )
{
return "";
}
int counter;
String ret = "" + index[0];
for ( counter = 1; counter <= level && counter < DEPTH_CUTOFF; counter++ )
{
ret += "." + index[counter];
}
return ret;
}
public List getSupportedOptions()
{
Vector ret = new Vector();
ret.addAll( options );
ret.addAll( element.getSupportedOptions() );
return ret;
}
}
class BookPage
extends DocList
{
public BookPage( java.lang.String name )
{
super( name, new DocElement[]{new com.rectang.xsm.widget.String( "title" ),
new HTMLTextArea( "content" )} );
}
}