package com.rectang.xsm.types;
import java.util.*;
import org.jdom.Element;
import com.rectang.xsm.doc.DocElement;
import com.rectang.xsm.doc.DocGroup;
import com.rectang.xsm.doc.DocList;
import com.rectang.xsm.doc.SupportedOption;
import com.rectang.xsm.io.PublishedFile;
import com.rectang.xsm.io.XSMDocument;
import com.rectang.xsm.widget.PreviewedImage;
import com.rectang.xsm.site.*;
import com.rectang.xsm.util.FileUtils;
public class Gallery
extends DocGroup
{
public static final SupportedOption THUMB_ROWS = new SupportedOption( "THUMB_ROWS",
"The number of rows on each thumbnail page", 3 );
public static final SupportedOption THUMB_COLS = new SupportedOption( "THUMB_COLS",
"The number of columns on each thumbnail page", 3 );
public static final SupportedOption NAV_POSITION = new SupportedOption( "NAV_POSITION",
"Display gallery navigation at the top, bottom or both", "both" );
private Vector options;
public Gallery( java.lang.String name )
{
super( name, new GalleryItem( "image" ) );
options = new Vector();
options.add( THUMB_ROWS );
options.add( THUMB_COLS );
options.add( NAV_POSITION );
}
/* FIXME - add a save + delete methods to remove the old preview pages if needed */
/* TODO maybe tidy this up a tad ??? */
private class VectorPair
{
public Vector pages, elements;
public VectorPair( Vector a, Vector b )
{
this.pages = a;
this.elements = b;
}
}
private VectorPair getSubGalleries()
{
Vector pages = new Vector();
Vector elements = new Vector();
Iterator subPages = getPage().getSubPages().iterator();
if ( subPages == null || !subPages.hasNext() )
{
return new VectorPair( pages, elements );
}
while ( subPages.hasNext() )
{
Page page = (Page) subPages.next();
if ( !(page instanceof DocumentPage) )
{
continue;
}
DocumentPage next = (DocumentPage) page;
/* do not thumbnail hidden pages */
if ( next.getHidden() )
{
continue;
}
try
{
Element elem = next.getXSMDocument().getContentElement();
if ( elem != null && elem.getName().equals( "gallery" ) )
{
pages.add( next );
elements.add( elem.getChild( "image" ) );
}
}
catch ( Exception e )
{
/* don't add */
e.printStackTrace();
}
}
return new VectorPair( pages, elements );
}
public void view( Element node, StringBuffer s )
{
int galleryIndex = 0;
VectorPair galleries = getSubGalleries();
Iterator subGals = galleries.pages.iterator();
while ( subGals.hasNext() )
{
DocumentPage next = (DocumentPage) subGals.next();
if ( next != null )
{
s.append( "<img src=\"" );
s.append( getSite().getRootUrl() );
s.append( next.getPath() );
s.append( java.io.File.separatorChar );
s.append( "_images" );
s.append( java.io.File.separatorChar );
s.append( FileUtils.getImageThumbnailName( path( (Element) galleries.elements.get( galleryIndex ) ) ) );
s.append( "\" /><br />Gallery: " );
s.append( next.getTitle() );
s.append( "<br />\n<br />\n" );
}
else
{
s.append( "No images in gallery \"" + next.getTitle() + "\"<br />\n<br />\n" );
}
galleryIndex++;
}
s.append( "</p>\n" );
super.view( node, s );
}
public void publish( Element node, StringBuffer s )
{
List children = node.getChildren( element.getName() );
Iterator allChildren = children.iterator();
VectorPair pair = getSubGalleries();
Vector galleryPages = pair.pages;
Vector galleryElements = pair.elements;
Iterator subGalleries = galleryElements.iterator();
String previewDir = getPreviewPath( "" );
(getSite().getPublishedDoc( previewDir )).mkdir();
int thumb_rows = THUMB_ROWS.getInteger( getDoc() );
int thumb_cols = THUMB_COLS.getInteger( getDoc() );
int thumb_cells = thumb_cols * thumb_rows;
int counter = 0;
int pageCounter = 0;
int totalImages = children.size();
int total = totalImages + galleryPages.size();
int totalPages = (((total - (total % (thumb_cells))) / (thumb_cells)));
if ( (total % (thumb_cells)) != 0 )
{
totalPages++;
}
PublishedFile file = null;
StringBuffer content = new StringBuffer();
StringBuffer page = new StringBuffer();
Element before = null;
int galleries = galleryPages.size();
boolean hasNext = subGalleries.hasNext() || allChildren.hasNext();
Element after = null;
if ( hasNext )
{
if ( subGalleries.hasNext() )
{
after = (Element) subGalleries.next();
}
else
{
after = (Element) allChildren.next();
}
}
int galleryIndex = 0;
Element[] nexts = new Element[thumb_cols];
while ( hasNext )
{
nexts[0] = after;
for ( int i = 1; i < thumb_cols; i++ )
{
nexts[i] = null;
if ( subGalleries.hasNext() )
{
nexts[i] = (Element) subGalleries.next();
}
else if ( allChildren.hasNext() )
{
nexts[i] = (Element) allChildren.next();
}
}
hasNext = subGalleries.hasNext() || allChildren.hasNext();
if ( hasNext )
{
if ( subGalleries.hasNext() )
{
after = (Element) subGalleries.next();
}
else
{
after = (Element) allChildren.next();
}
}
else
{
after = null;
}
if ( counter % (thumb_cells) == 0 )
{
page = new StringBuffer();
page.append( "<center>\n" );
page.append( "<table border=\"0\" cellpadding=\"2\" cellspacing=\"0\"" );
page.append( " width=\"100%\">\n" );
}
page.append( "<tr>\n" );
/* pics */
for ( int i = 0; i < thumb_cols; i++ )
{
generateImage( nexts[i], previewDir, (counter + i) < galleries,
(DocumentPage) getVectorId( galleryPages, galleryIndex + i ), page );
}
page.append( "</tr><tr>\n" );
/* captions */
for ( int i = 0; i < thumb_cols; i++ )
{
generateCaption( nexts[i], (counter + i) < galleries,
(DocumentPage) getVectorId( galleryPages, galleryIndex + i ), page );
}
page.append( "</tr>\n" );
page.append( "<tr><td colspan=\"" + thumb_cols + "\"> </td></tr>\n" );
/* preview pages */
for ( int i = 0; i < thumb_cols; i++ )
{
if ( (counter + i) >= galleries )
{
Element prev = before;
if ( i > 0 )
{
prev = nexts[i - 1];
}
Element next = after;
if ( i < thumb_cols - 1 )
{
next = nexts[i + 1];
}
generatePreviewPage( nexts[i], prev, next, (counter + i) - galleries, totalImages, previewDir,
pageCounter );
}
}
before = nexts[thumb_cols - 1];
counter += thumb_cols;
galleryIndex += thumb_cols;
if ( (counter / thumb_cols) % thumb_rows == 0 || !hasNext )
{
page.append( "</table>\n</center>\n" );
String navPos = NAV_POSITION.getString( getDoc() );
if ( navPos.equals( "top" ) || navPos.equals( "both" ) )
{
publishThumbNav( pageCounter, hasNext, totalPages, content );
}
content.append( page );
if ( navPos.equals( "bottom" ) || navPos.equals( "both" ) )
{
publishThumbNav( pageCounter, hasNext, totalPages, content );
}
if ( pageCounter == 0 )
{
s.append( content );
}
else
{
getDoc().publishContent( file, content.toString(), getUser() );
}
file = getSite().getPublishedDoc( getPublishedPath() + "/_thumbs/"
+ ++pageCounter + ".html" );
content = new StringBuffer();
}
}
if ( content.length() != 0 )
{
getDoc().publishContent( file, content.toString(), getUser() );
}
String parentPath = (new java.io.File( getPublishedPath() )).getParent();
if ( !parentPath.equals( "/" ) )
{
HierarchicalPage parent = (HierarchicalPage) getSite().getPage( parentPath );
if ( parent instanceof DocumentPage )
{
XSMDocument parentDoc = ((DocumentPage) parent).getXSMDocument();
if ( parentDoc != null &&
parentDoc.getContentElement().getName().equals( "gallery" ) )
{
parentDoc.publish( getUser() );
}
}
}
}
private void publishThumbNav( int counter, boolean hasNext, int total,
StringBuffer s )
{
String pStr = "";
String nStr = "";
if ( counter > 0 )
{
if ( counter == 1 )
{
pStr = "<a href=\"" + getSite().getPrefixUrl() + getPublishedPath() + "/index.html\">Previous</a>";
}
else
{
pStr = "<a href=\"" + getSite().getPrefixUrl() + getPublishedPath() + "/_thumbs/" + (counter - 1)
+ ".html\">Previous</a>";
}
}
if ( hasNext )
{
nStr = "<a href=\"" + getSite().getPrefixUrl() + getPublishedPath() + "/_thumbs/" + (counter + 1) + ".html\">Next</a>";
}
s.append( "<p class=\"xsm_gallery_nav\">\n" );
s.append( "<span class=\"xsm_gallery_nav_prev\">" + pStr + "</span>\n" );
s.append( "<span class=\"xsm_gallery_nav_next\">" + nStr );
s.append( "</span>\n" );
s.append( "<span class=\"xsm_gallery_nav_curr\">" );
s.append( (counter + 1) + " of " + total + "</span>\n" );
s.append( "</p>\n" );
}
private Object getVectorId( Vector v, int id )
{
if ( id >= v.size() )
{
return null;
}
return v.get( id );
}
private void generateImage( Element node, String dir, boolean gallery,
DocumentPage subGallery, StringBuffer s )
{
/* FIXME - rounding errors */
int percent = 100 / THUMB_COLS.getInteger( getDoc() );
if ( node == null )
{
s.append( "<td class=\"xsm_gallery_thumb\" width=\"" + percent + "%\"> </td>" );
return;
}
s.append( "<td class=\"xsm_gallery_thumb\" align=\"center\" width=\"" + percent + "%\">" );
if ( gallery )
{
s.append( "<a href=\"" + getSite().getPrefixUrl() );
s.append( subGallery.getPath() + "/index.html\">" );
}
else
{
s.append( previewLink( node, dir ) );
}
s.append( "<img src=\"" + getSite().getPrefixUrl() );
if ( gallery )
{
if ( node == null )
{
s.append( "(no image)" );
}
else
{
s.append( subGallery.getPath() + java.io.File.separatorChar + "_images" );
s.append( java.io.File.separatorChar );
s.append( FileUtils.getImageThumbnailName( path( node ) ) );
}
}
else
{
s.append( com.rectang.xsm.widget.Image.getPath( this,
FileUtils.getImageThumbnailName( path( node ) ) ) );
}
s.append( "\" border=\"0\"/></a>\n</td>\n" );
}
private String previewLink( Element node, String dir )
{
return "<a href=\"" + getSite().getPrefixUrl() + dir
+ path( node ) + ".html\">";
}
private void generateCaption( Element node, boolean gallery, DocumentPage subGallery,
StringBuffer s )
{
/* FIXME - rounding errors */
int percent = 100 / THUMB_COLS.getInteger( getDoc() );
if ( node == null )
{
s.append( "<td class=\"xsm_gallery_caption\" width=\"" + percent + "%\"> </td>" );
return;
}
s.append( "<td class=\"xsm_gallery_caption\" width=\"" + percent + "%\">" );
s.append( "<p>" );
if ( gallery )
{
if ( node != null )
{
s.append( "Gallery: <a href=\"" + getSite().getPrefixUrl() );
s.append( subGallery.getPath() + "/index.html\">" );
s.append( subGallery.getTitle() + "</a>" );
}
}
else
{
s.append( caption( node ) );
}
int comments = node.getChild( "comments" ).getChildren( "comment" ).size();
if ( comments > 0 )
{
s.append( "<br />" + comments + " comment" + ((comments != 1) ? "s" : "") );
}
s.append( "</p></td>\n" );
}
private void generatePreviewPage( Element node, Element before, Element after,
int pos, int tot, String dir, int page )
{
if ( node == null )
{
return;
}
PublishedFile out = getSite().getPublishedDoc( dir + path( node ) + ".html" );
boolean full = PreviewedImage.KEEP_ORIG.getBoolean( getDoc() );
StringBuffer content = new StringBuffer();
content.append( "<div class=\"xsm_gallery_preview\">\n" );
String navPos = NAV_POSITION.getString( getDoc() );
if ( navPos.equals( "top" ) || navPos.equals( "both" ) )
{
publishPreviewNav( pos, tot, before, after, dir, content );
}
if ( full )
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + java.io.File.separatorChar + "_images" );
content.append( java.io.File.separatorChar + path( node ) + "\" target=\"_blank\">" );
}
content.append( "<img border=\"0\"src=\"" );
content.append( getSite().getPrefixUrl() );
content.append( com.rectang.xsm.widget.Image.getPath( this,
FileUtils.getImagePreviewName( path( node ) ) ) + "\">" );
if ( full )
{
content.append( "</a>" );
}
content.append( "\n<p>" + caption( node ) + "</p>\n" );
if ( navPos.equals( "bottom" ) || navPos.equals( "both" ) )
{
publishPreviewNav( pos, tot, before, after, dir, content );
}
content.append( "<p class=\"xsm_gallery_nav_up\">" );
if ( page == 0 )
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + "/index.html\">Up</a>" );
}
else
{
content.append( "<a href=\"" + getSite().getPrefixUrl() );
content.append( getPublishedPath() + "/_thumbs/" + page + ".html\">Up</a>" );
}
content.append( "</p></div>\n" );
Element comments = node.getChild( "comments" );
int commentCount = comments.getChildren( "comment" ).size();
if ( commentCount > 0 )
{
content.append( "<p><b>Comments:</b></p>" );
((GalleryItem) element).elements[2].publish( comments, content );
}
getDoc().publishContent( out, content.toString(), getUser() );
}
private void publishPreviewNav( int pos, int tot, Element before,
Element after, String dir, StringBuffer s )
{
String prev = " ";
if ( pos > 0 )
{
prev = previewLink( before, dir ) + "Previous</a>";
}
String next = " ";
if ( pos < tot - 1 )
{
next = previewLink( after, dir ) + "Next</a>";
}
s.append( "<p class=\"xsm_gallery_nav\">\n" );
s.append( "<span class=\"xsm_gallery_nav_prev\">" );
s.append( prev + "</span>\n" );
s.append( "<span class=\"xsm_gallery_nav_next\">" );
s.append( next + "</span>\n" );
s.append( "<span class=\"xsm_gallery_nav_curr\">" );
s.append( (pos + 1) + " of " + tot + "</span>\n" );
s.append( "</p>\n" );
}
private String path( Element node )
{
if ( node == null )
{
return "";
}
return node.getChild( "path" ).getValue();
}
private String caption( Element node )
{
if ( node == null )
{
return "";
}
return node.getChild( "caption" ).getValue();
}
protected java.lang.String getPreviewPath( java.lang.String name )
{
return getPublishedPath() + java.io.File.separatorChar + "_previews"
+ java.io.File.separatorChar + name;
}
public List getSupportedOptions()
{
Vector ret = new Vector();
ret.addAll( options );
ret.addAll( element.getSupportedOptions() );
return ret;
}
}
class GalleryItem
extends DocList
{
public GalleryItem( String name )
{
super( name, new DocElement[]{
new GalleryPreviewedImage( "path" ),
new com.rectang.xsm.widget.String( "caption" ),
new GalleryCommentList( "comments" )
} );
}
}
class GalleryPreviewedImage
extends PreviewedImage
{
public GalleryPreviewedImage( java.lang.String name )
{
super( name );
}
public void destroy( Element node )
{
getSite().getPublishedDoc( getPublishedPath() + java.io.File.separatorChar + "_previews" + java.io.File.separatorChar
+ node.getText() + ".html" ).delete();
super.destroy( node );
/* FIXME here we need to trigger Gallery to check that it still needs all
* of its thumbnail pages */
}
}
class GalleryCommentList
extends DocGroup
{
public GalleryCommentList( String name )
{
super( name, new GalleryComment( "comment" ) );
}
public void publish( Element node, StringBuffer s )
{
Iterator children = node.getChildren( "comment" ).iterator();
while ( children.hasNext() )
{
Element next = (Element) children.next();
element.publish( next, s );
}
}
}
class GalleryComment
extends DocList
{
public GalleryComment( String name )
{
super( name, new DocElement[]{
new com.rectang.xsm.widget.TextArea( "body" ),
new com.rectang.xsm.widget.Value( "author", com.rectang.xsm.widget.Value.FULLNAME ),
new com.rectang.xsm.widget.Value( "time", com.rectang.xsm.widget.Value.DATE )} );
}
public void publish( Element node, StringBuffer s )
{
s.append( "<p><b>" );
elements[1].publish( node.getChild( "author" ), s );
s.append( "</b> (" );
elements[2].publish( node.getChild( "time" ), s );
s.append( ")<br />" );
elements[0].publish( node.getChild( "body" ), s );
s.append( "</p>" );
}
}