package railo.runtime.tag;
import java.io.IOException;
import railo.commons.lang.StringUtil;
import railo.runtime.exp.ExpressionException;
import railo.runtime.exp.PageException;
import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl;
import railo.runtime.functions.string.CJustify;
import railo.runtime.functions.string.LJustify;
import railo.runtime.functions.string.RJustify;
import railo.runtime.op.Caster;
/**
* Builds a table in a CFML page. Use the cfcol tag to define table column and row
* characteristics. The cftable tag renders data either as preformatted text, or, with the HTMLTable
* attribute, as an HTML table. Use cftable to create tables if you don't want to write HTML table tag
* code, or if your data can be well presented as preformatted text.
*
*
*
**/
public final class Table extends BodyTagTryCatchFinallyImpl {
/**
* Field <code>ALIGN_LEFT</code>
*/
public static final short ALIGN_LEFT=0;
/**
* Field <code>ALIGN_CENTER</code>
*/
public static final short ALIGN_CENTER=1;
/**
* Field <code>ALIGN_RIGHT</code>
*/
public static final short ALIGN_RIGHT=2;
/** Name of the cfquery from which to draw data. */
private railo.runtime.type.Query query;
/** Maximum number of rows to display in the table. */
private int maxrows=Integer.MAX_VALUE;
/** Specifies the query row from which to start processing. */
private int startrow=1;
/** Adds a border to the table. Use only when you specify the HTMLTable attribute for the table. */
private boolean border;
/** Displays headers for each column, as specified in the cfcol tag. */
private boolean colheaders;
/** Number of spaces to insert between columns 'default is 2'. */
private int colspacing=2;
/** Renders the table as an HTML 3.0 table. */
private boolean htmltable;
/** Number of lines to use for the table header. The default is 2, which leaves one line between
** the headers and the first row of the table. */
private int headerlines=2;
StringBuffer header=new StringBuffer();
StringBuffer body=new StringBuffer();
private int initRow;
private int count=0;
private boolean startNewRow;
@Override
public void release() {
super.release();
query=null;
maxrows=Integer.MAX_VALUE;
startrow=1;
border=false;
colheaders=false;
colspacing=2;
htmltable=false;
headerlines=2;
if(header.length()>0)header=new StringBuffer();
body=new StringBuffer();
count=0;
}
/** set the value query
* Name of the cfquery from which to draw data.
* @param query value to set
* @throws PageException
**/
public void setQuery(String query) throws PageException {
this.query = Caster.toQuery(pageContext.getVariable(query));
}
/** set the value maxrows
* Maximum number of rows to display in the table.
* @param maxrows value to set
**/
public void setMaxrows(double maxrows) {
this.maxrows=(int)maxrows;
}
/** set the value startrow
* Specifies the query row from which to start processing.
* @param startrow value to set
**/
public void setStartrow(double startrow) {
this.startrow=(int)startrow;
if(this.startrow<=0)this.startrow=1;
}
/** set the value border
* Adds a border to the table. Use only when you specify the HTMLTable attribute for the table.
* @param border value to set
**/
public void setBorder(boolean border) {
this.border=border;
}
/** set the value colheaders
* Displays headers for each column, as specified in the cfcol tag.
* @param colheaders value to set
**/
public void setColheaders(boolean colheaders) {
this.colheaders=colheaders;
}
/** set the value colspacing
* Number of spaces to insert between columns 'default is 2'.
* @param colspacing value to set
**/
public void setColspacing(double colspacing) {
this.colspacing=(int)colspacing;
}
/** set the value htmltable
* Renders the table as an HTML 3.0 table.
* @param htmltable value to set
**/
public void setHtmltable(boolean htmltable) {
this.htmltable=htmltable;
}
/** set the value headerlines
* Number of lines to use for the table header. The default is 2, which leaves one line between
* the headers and the first row of the table.
* @param headerlines value to set
**/
public void setHeaderlines(double headerlines) {
this.headerlines=(int)headerlines;
if(this.headerlines<2)this.headerlines=2;
}
@Override
public int doStartTag() throws PageException {
startNewRow=true;
initRow=query.getRecordcount();
query.go(startrow,pageContext.getId());
pageContext.undefinedScope().addQuery(query);
return query.getRecordcount()>=startrow?EVAL_BODY_INCLUDE:SKIP_BODY;
}
@Override
public void doInitBody() {
//if(htmltable) body.append("<tr>\n");
}
@Override
public int doAfterBody() throws PageException {
if(htmltable) body.append("</tr>\n");
else body.append('\n');
startNewRow=true;
//print.out(query.getCurrentrow()+"-"+query.getRecordcount());
return ++count<maxrows && query.next()?EVAL_BODY_AGAIN:SKIP_BODY;
}
@Override
public int doEndTag() throws PageException {
try {
_doEndTag();
} catch (IOException e) {
throw Caster.toPageException(e);
}
return EVAL_PAGE;
}
private void _doEndTag() throws IOException {
if(htmltable) {
pageContext.forceWrite("<table colspacing=\""+colspacing+"\"");
if(border) {
pageContext.forceWrite(" border=\"1\"");
}
pageContext.forceWrite(">\n");
if(header.length()>0) {
pageContext.forceWrite("<tr>\n");
pageContext.forceWrite(header.toString());
pageContext.forceWrite("</tr>\n");
}
pageContext.forceWrite(body.toString());
pageContext.forceWrite("</table>");
}
else {
pageContext.forceWrite("<pre>");
if(header.length()>0) {
pageContext.forceWrite(header.toString());
pageContext.forceWrite(StringUtil.repeatString("\n",headerlines-1));
}
pageContext.forceWrite(body.toString());
pageContext.forceWrite("</pre>");
}
}
@Override
public void doFinally() {
try {
pageContext.undefinedScope().removeQuery();
if(query!=null)query.go(initRow,pageContext.getId());
}
catch (PageException e) { }
}
/**
* @param strHeader
* @param text
* @param align
* @param width
* @throws ExpressionException
*/
public void setCol(String strHeader, String text, short align, int width) throws ExpressionException {
// HTML
if(htmltable) {
if(colheaders && count==0 && strHeader.trim().length()>0) {
header.append("\t<th");
addAlign(header,align);
addWidth(header,width);
header.append(">");
header.append(strHeader);
header.append("</th>\n");
}
if(htmltable && startNewRow) {
body.append("<tr>\n");
startNewRow=false;
}
body.append("\t<td");
addAlign(body,align);
addWidth(body,width);
body.append(">");
body.append(text);
body.append("</td>\n");
}
// PRE
else {
if(width<0) width=20;
if(colheaders && count==0 && strHeader.trim().length()>0) {
addPre(header,align,strHeader,width);
}
addPre(body,align,text,width);
}
}
private void addAlign(StringBuffer data,short align) {
data.append(" align=\"");
data.append(toStringAlign(align));
data.append("\"");
}
private void addWidth(StringBuffer data,int width) {
if(width>=-1) {
data.append(" width=\"");
data.append(width);
data.append("%\"");
}
}
private void addPre(StringBuffer data,short align,String value, int length) throws ExpressionException {
if(align==ALIGN_RIGHT) data.append(RJustify.call(pageContext,value,length));
else if(align==ALIGN_CENTER) data.append(CJustify.call(pageContext,value,length));
else data.append(LJustify.call(pageContext,value,length));
}
private String toStringAlign(short align) {
if(align==ALIGN_RIGHT) return "right";
if(align==ALIGN_CENTER) return "center";
return "left";
}
}