001 package railo.runtime.tag; 002 003 import java.io.IOException; 004 005 import railo.commons.lang.StringUtil; 006 import railo.runtime.exp.ExpressionException; 007 import railo.runtime.exp.PageException; 008 import railo.runtime.ext.tag.BodyTagTryCatchFinallyImpl; 009 import railo.runtime.functions.string.CJustify; 010 import railo.runtime.functions.string.LJustify; 011 import railo.runtime.functions.string.RJustify; 012 import railo.runtime.op.Caster; 013 014 /** 015 * Builds a table in a CFML page. Use the cfcol tag to define table column and row 016 * characteristics. The cftable tag renders data either as preformatted text, or, with the HTMLTable 017 * attribute, as an HTML table. Use cftable to create tables if you don't want to write HTML table tag 018 * code, or if your data can be well presented as preformatted text. 019 * 020 * 021 * 022 **/ 023 public final class Table extends BodyTagTryCatchFinallyImpl { 024 025 /** 026 * Field <code>ALIGN_LEFT</code> 027 */ 028 public static final short ALIGN_LEFT=0; 029 /** 030 * Field <code>ALIGN_CENTER</code> 031 */ 032 public static final short ALIGN_CENTER=1; 033 /** 034 * Field <code>ALIGN_RIGHT</code> 035 */ 036 public static final short ALIGN_RIGHT=2; 037 038 /** Name of the cfquery from which to draw data. */ 039 private railo.runtime.type.Query query; 040 041 /** Maximum number of rows to display in the table. */ 042 private int maxrows=Integer.MAX_VALUE; 043 044 /** Specifies the query row from which to start processing. */ 045 private int startrow=1; 046 047 /** Adds a border to the table. Use only when you specify the HTMLTable attribute for the table. */ 048 private boolean border; 049 050 /** Displays headers for each column, as specified in the cfcol tag. */ 051 private boolean colheaders; 052 053 /** Number of spaces to insert between columns 'default is 2'. */ 054 private int colspacing=2; 055 056 /** Renders the table as an HTML 3.0 table. */ 057 private boolean htmltable; 058 059 /** Number of lines to use for the table header. The default is 2, which leaves one line between 060 ** the headers and the first row of the table. */ 061 private int headerlines=2; 062 063 StringBuffer header=new StringBuffer(); 064 StringBuffer body=new StringBuffer(); 065 066 private int initRow; 067 068 private int count=0; 069 private boolean startNewRow; 070 071 @Override 072 public void release() { 073 super.release(); 074 query=null; 075 maxrows=Integer.MAX_VALUE; 076 startrow=1; 077 border=false; 078 colheaders=false; 079 colspacing=2; 080 htmltable=false; 081 headerlines=2; 082 if(header.length()>0)header=new StringBuffer(); 083 body=new StringBuffer(); 084 count=0; 085 } 086 087 /** set the value query 088 * Name of the cfquery from which to draw data. 089 * @param query value to set 090 * @throws PageException 091 **/ 092 public void setQuery(String query) throws PageException { 093 this.query = Caster.toQuery(pageContext.getVariable(query)); 094 } 095 096 /** set the value maxrows 097 * Maximum number of rows to display in the table. 098 * @param maxrows value to set 099 **/ 100 public void setMaxrows(double maxrows) { 101 this.maxrows=(int)maxrows; 102 } 103 104 /** set the value startrow 105 * Specifies the query row from which to start processing. 106 * @param startrow value to set 107 **/ 108 public void setStartrow(double startrow) { 109 this.startrow=(int)startrow; 110 if(this.startrow<=0)this.startrow=1; 111 } 112 113 /** set the value border 114 * Adds a border to the table. Use only when you specify the HTMLTable attribute for the table. 115 * @param border value to set 116 **/ 117 public void setBorder(boolean border) { 118 this.border=border; 119 } 120 121 /** set the value colheaders 122 * Displays headers for each column, as specified in the cfcol tag. 123 * @param colheaders value to set 124 **/ 125 public void setColheaders(boolean colheaders) { 126 this.colheaders=colheaders; 127 } 128 129 /** set the value colspacing 130 * Number of spaces to insert between columns 'default is 2'. 131 * @param colspacing value to set 132 **/ 133 public void setColspacing(double colspacing) { 134 this.colspacing=(int)colspacing; 135 } 136 137 /** set the value htmltable 138 * Renders the table as an HTML 3.0 table. 139 * @param htmltable value to set 140 **/ 141 public void setHtmltable(boolean htmltable) { 142 this.htmltable=htmltable; 143 } 144 145 /** set the value headerlines 146 * Number of lines to use for the table header. The default is 2, which leaves one line between 147 * the headers and the first row of the table. 148 * @param headerlines value to set 149 **/ 150 public void setHeaderlines(double headerlines) { 151 this.headerlines=(int)headerlines; 152 if(this.headerlines<2)this.headerlines=2; 153 } 154 155 156 @Override 157 public int doStartTag() throws PageException { 158 startNewRow=true; 159 initRow=query.getRecordcount(); 160 query.go(startrow,pageContext.getId()); 161 pageContext.undefinedScope().addQuery(query); 162 return query.getRecordcount()>=startrow?EVAL_BODY_INCLUDE:SKIP_BODY; 163 } 164 165 @Override 166 public void doInitBody() { 167 //if(htmltable) body.append("<tr>\n"); 168 } 169 170 @Override 171 public int doAfterBody() throws PageException { 172 if(htmltable) body.append("</tr>\n"); 173 else body.append('\n'); 174 startNewRow=true; 175 //print.out(query.getCurrentrow()+"-"+query.getRecordcount()); 176 return ++count<maxrows && query.next()?EVAL_BODY_AGAIN:SKIP_BODY; 177 } 178 179 @Override 180 public int doEndTag() throws PageException { 181 try { 182 _doEndTag(); 183 } catch (IOException e) { 184 throw Caster.toPageException(e); 185 } 186 return EVAL_PAGE; 187 } 188 private void _doEndTag() throws IOException { 189 if(htmltable) { 190 pageContext.forceWrite("<table colspacing=\""+colspacing+"\""); 191 if(border) { 192 pageContext.forceWrite(" border=\"1\""); 193 } 194 pageContext.forceWrite(">\n"); 195 if(header.length()>0) { 196 pageContext.forceWrite("<tr>\n"); 197 pageContext.forceWrite(header.toString()); 198 pageContext.forceWrite("</tr>\n"); 199 } 200 pageContext.forceWrite(body.toString()); 201 pageContext.forceWrite("</table>"); 202 } 203 else { 204 pageContext.forceWrite("<pre>"); 205 if(header.length()>0) { 206 pageContext.forceWrite(header.toString()); 207 pageContext.forceWrite(StringUtil.repeatString("\n",headerlines-1)); 208 } 209 pageContext.forceWrite(body.toString()); 210 pageContext.forceWrite("</pre>"); 211 } 212 } 213 214 @Override 215 public void doFinally() { 216 try { 217 pageContext.undefinedScope().removeQuery(); 218 if(query!=null)query.go(initRow,pageContext.getId()); 219 } 220 catch (PageException e) { } 221 } 222 223 /** 224 * @param strHeader 225 * @param text 226 * @param align 227 * @param width 228 * @throws ExpressionException 229 */ 230 public void setCol(String strHeader, String text, short align, int width) throws ExpressionException { 231 // HTML 232 if(htmltable) { 233 if(colheaders && count==0 && strHeader.trim().length()>0) { 234 header.append("\t<th"); 235 addAlign(header,align); 236 addWidth(header,width); 237 header.append(">"); 238 header.append(strHeader); 239 header.append("</th>\n"); 240 } 241 if(htmltable && startNewRow) { 242 body.append("<tr>\n"); 243 startNewRow=false; 244 } 245 246 body.append("\t<td"); 247 addAlign(body,align); 248 addWidth(body,width); 249 body.append(">"); 250 body.append(text); 251 body.append("</td>\n"); 252 } 253 // PRE 254 else { 255 if(width<0) width=20; 256 if(colheaders && count==0 && strHeader.trim().length()>0) { 257 addPre(header,align,strHeader,width); 258 } 259 addPre(body,align,text,width); 260 261 } 262 } 263 264 private void addAlign(StringBuffer data,short align) { 265 data.append(" align=\""); 266 data.append(toStringAlign(align)); 267 data.append("\""); 268 } 269 270 private void addWidth(StringBuffer data,int width) { 271 if(width>=-1) { 272 data.append(" width=\""); 273 data.append(width); 274 data.append("%\""); 275 } 276 } 277 278 private void addPre(StringBuffer data,short align,String value, int length) throws ExpressionException { 279 if(align==ALIGN_RIGHT) data.append(RJustify.call(pageContext,value,length)); 280 else if(align==ALIGN_CENTER) data.append(CJustify.call(pageContext,value,length)); 281 else data.append(LJustify.call(pageContext,value,length)); 282 283 } 284 285 private String toStringAlign(short align) { 286 if(align==ALIGN_RIGHT) return "right"; 287 if(align==ALIGN_CENTER) return "center"; 288 return "left"; 289 } 290 }