package net.xoetrope.builder.w3c.html.tags;
import net.xoetrope.builder.w3c.html.XHtmlBuilder;
import net.xoetrope.builder.w3c.html.XHtmlFormLayout;
import info.clearthought.layout.TableLayout;
import info.clearthought.layout.TableLayoutConstraints;
import java.awt.Color;
import java.util.ArrayList;
import java.util.Enumeration;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.border.LineBorder;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import net.xoetrope.swing.XLabel;
import net.xoetrope.xui.XComponentFactory;
/**
* Processing for the html tr, td, th elements
* <p> Copyright (c) Xoetrope Ltd., 2002-2006</p>
* <p> $Revision: 1.2 $</p>
* <p> License: see License.txt</p>
*/
public class Td extends XHtmlTagHandler
{
protected HTML.Tag tag;
/** Creates a new instance of Td */
public Td( HTML.Tag t )
{
tag = t;
}
/**
* Create a new instance of this object
* @param builder the html builder and processor for the document
* @param parent the parent handler
* @return the new handler
*/
public XHtmlTagHandler newInstance( XHtmlBuilder builder, XHtmlTagHandler parent )
{
Td i = new Td( tag );
i.setParent( parent );
i.setBuilder( builder );
return i;
}
/**
* Process the opening html Img tag/element. Adds a panel for TD elements
* @param builder the xui builder instance that is processing the html file
* @param cf the component factory to use for the creation of individual components
* @param as the attributes of this html tag.
*/
public void startProcessing( XHtmlBuilder builder, XComponentFactory cf, MutableAttributeSet as )
{
super.startProcessing( builder, cf, as );
if ( tag.toString().equals( "td" )) {
comp = (JComponent)cf.constructComponent( "panel", "" );
comp.setOpaque( false );
cf.setParentComponent( comp );
comp.setLayout( new XHtmlFormLayout( builder ));
}
}
/**
* The closing tag has been parsed and now the element can calulate its complete setup
* should it be dependant on its children for any information. In the case of a table,
* the table determines the row and column count from the child elements and
* cannot calculate its layout till all the children have been initially processed.
* @param cf the component factory to use for the creation of individual components
*/
public void endProcessing( XComponentFactory cf )
{
super.endProcessing( cf );
Enumeration attribNames = attribSet.getAttributeNames();
while ( attribNames.hasMoreElements()) {
Object key = attribNames.nextElement();
String attribName = key.toString();
Object attribValue = attribSet.getAttribute( key );
if ( attribValue != null )
processCommonAttributes( attribName, attribValue );
}
cf.setParentComponent( parentComponent );
}
/**
* Find the parent table
* @return the table handler
*/
protected Table getTable()
{
XHtmlTagHandler t = parent;
while ( !( t instanceof Table ))
t = t.getParent();
return (Table)t;
}
/**
* Get the number of table columns represented by this COL element
* @return the number of columns defined by the span attribute or 1 if a span attribute is not present
*/
public int getNumCols()
{
int numCols = 0;
ArrayList< XHtmlTagHandler > kids = children;
if ( kids != null ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Td ) {
Td td = (Td)handler;
// Only process the td elements
if ( "td".equals( td.tag.toString())) {
numCols += td.getNumCols();
}
}
}
}
if ( numCols == 0 ) {
Object obj = attribSet.getAttribute( HTML.Attribute.COLSPAN );
if ( obj != null )
numCols = Integer.parseInt( obj.toString());
}
return Math.max( 1, numCols );
}
/**
* Add the children of the table element
* @param table the table being filled
* @param tableLayout the layout being used by the table
* @param rowSpans an array of rowspan values
* @param rowIdx the current row index
*/
protected void addChildren( JPanel table, TableLayout tableLayout, int[] rowSpans, int rowIdx )
{
int colIdx = 0;
ArrayList< XHtmlTagHandler > kids = children;
if ( kids != null ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Td ) {
Td td = (Td)handler;
// Only process the td elements
if ( "td".indexOf( td.tag.toString()) >= 0 ) {
int colSpan = td.addContent( table, tableLayout, rowSpans, rowIdx, colIdx++ );
colIdx += colSpan;
}
}
}
}
// Decrement the row span counter for any unoccupied cells
for ( int i = colIdx; i < rowSpans.length; i++ ) {
if ( rowSpans[ i ] > 0 )
rowSpans[ i ]--;
}
}
/**
* Add the content of the table element
* @param table the table being filled
* @param tableLayout the layout being used by the table
* @param rowSpans an array of rowspan values
* @param rowIdx the current row index
* @param colIdx the current column
*/
protected int addContent( JPanel table, TableLayout tableLayout, int[] rowSpans, int rowIdx, int colIdx )
{
if ( getTable().getBorderWidth() > 0 )
comp.setBorder( new LineBorder( Color.black ));
int colSpan = 0;
int insertCol = colIdx;
// Check for colspans remaining from prior rows
int rowSpan = rowSpans[ colIdx ];
while ( rowSpan > 0 ) {
// Decrement the rowspan count as one more row has been used up
rowSpans[ insertCol ]--;
// Move a column forward
insertCol++;
// Check the next column for a row span
if ( insertCol < rowSpans.length )
rowSpan = rowSpans[ insertCol ];
else
rowSpan = 0;
}
Object obj = attribSet.getAttribute( HTML.Attribute.COLSPAN );
if ( obj != null )
colSpan = Integer.parseInt( obj.toString()) - 1;
obj = attribSet.getAttribute( HTML.Attribute.ROWSPAN );
if ( obj != null )
rowSpan = Integer.parseInt( obj.toString()) - 1;
// Rows and columns are 1 based
if (( content != null ) && ( content.length() > 0 ) && !content.equals( " " )) {
XLabel label = new XLabel();
if ( !content.startsWith( "<html>" ))
content = "<html>" + getTextStyleAttributes( label, true ) + content + getTextStyleAttributes( label, false ) + "</html>";
label.setText( content );
if ( XHtmlBuilder.isDebugLayout())
label.setBorder( new LineBorder( Color.green, 2 ));
comp.add( label, 0 );
}
if ( XHtmlBuilder.isDebugLayout())
comp.setBorder( new LineBorder( Color.red, 2 ));
if ( comp.getComponentCount() > 0 ) {
TableLayoutConstraints constraints = new TableLayoutConstraints( insertCol, rowIdx, insertCol + colSpan, rowIdx + rowSpan );
// Object align = attribSet.getAttribute( HTML.Attribute.ALIGN );
// if (( align != null ) && align.toString().equals( "center" ))
// constraints.hAlign = TableLayoutConstraints.CENTER;
// Attempt to force the centering
// Object id = attribSet.getAttribute( HTML.Attribute.ID );
// if (( id != null ) && id.toString().equals( "foobar" ))
// constraints.hAlign = TableLayoutConstraints.CENTER;
table.add( comp, constraints );
}
double width = getLength((String)attribSet.getAttribute( HTML.Attribute.WIDTH ));
if ( width > 0.0 ) {
if ( width == 1.0 )
width = 0.99999;
tableLayout.setColumn( insertCol, width );
}
double height = getLength((String)attribSet.getAttribute( HTML.Attribute.HEIGHT ));
if ( height > 0.0 )
tableLayout.setRow( rowIdx, height );
// Store the row span attribute, if any
if ( rowSpan > 0 ) {
rowSpans[ insertCol ] = rowSpan;
// If the entry also spans columns subsequent rowspan entries need to be filled
for ( int i = 0; i < colSpan; i++ )
rowSpans[ insertCol + 1 + i ] = rowSpan;
}
return colSpan + ( insertCol - colIdx );
}
/**
* Does this tag break the flow?
* @return true if the flow is broken, otherwsie false
*/
public boolean breaksFlow()
{
return tag.breaksFlow();
}
}