package net.xoetrope.builder.w3c.html.tags;
import net.xoetrope.builder.w3c.html.XHtmlBuilder;
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.border.LineBorder;
import javax.swing.text.MutableAttributeSet;
import javax.swing.text.html.HTML;
import net.xoetrope.swing.XPanel;
import net.xoetrope.xui.XComponentFactory;
/**
* Processing for the html table element
* <p> Copyright (c) Xoetrope Ltd., 2002-2006</p>
* <p> $Revision: 1.2 $</p>
* <p> License: see License.txt</p>
*/
public class Table extends XHtmlTagHandler
{
protected String alignment;
protected double cellSpacing, cellPadding, width;
protected int numRows, numCols, border;
/**
* Creates a new instance of Table
*/
public Table()
{
alignment = "left";
width = 1.0;
cellSpacing = cellPadding = 0.0;
}
/**
* 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 )
{
Table i = new Table();
i.setParent( parent );
i.setBuilder( builder );
return i;
}
/**
* Process the opening html table tag/element
* @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 );
comp = (JComponent)cf.addComponent( "panel", null, "" );
comp.setOpaque( false );
cf.setParentComponent( comp );
}
/**
* 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 );
numRows = numCols = 0;
numCols = Math.max( 1, getNumCols( this ));
numRows = Math.max( 1, getNumRows());
Enumeration attribNames = attribSet.getAttributeNames();
while ( attribNames.hasMoreElements()) {
Object key = attribNames.nextElement();
String attribName = key.toString();
Object attribValue = attribSet.getAttribute( key );
if ( attribValue != null ) {
if ( attribName.equals( "align" ))
alignment = (String)attribValue;
else if ( attribName.equals( "width" ))
width = getLength( (String)attribValue );
else if ( attribName.equals( "cellspacing" ))
cellSpacing = getLength( (String)attribValue );
else if ( attribName.equals( "cellspacing" ))
cellPadding = getLength( (String)attribValue );
else if ( attribName.equals( "border" )) {
border = Integer.parseInt( (String)attribValue );
if ( border > 0 ) {
//Color c = getColor( attribSet.getAttribute( HTML.Attribute.BORDER_COLOR ));
Color c = Color.darkGray;
Object colorAttrib = attribSet.getAttribute( "bordercolor" );
if ( colorAttrib != null )
c = builder.getColor( (String)colorAttrib );
comp.setBorder( new LineBorder( c, border ));
}
}
else
processCommonAttributes( attribName, attribValue );
}
}
// Setup the layout
TableLayout tableLayout = new TableLayout();
int spacing = getWidth( comp.getSize(), cellSpacing );
tableLayout.setHGap( spacing );
tableLayout.setVGap( spacing );
int i = 0;
// Use a preferred layout unless otherwise stated
for ( ; i < numRows; i++ )
tableLayout.insertRow( i, TableLayout.PREFERRED );
for ( i = 0; i < numCols; i++ )
tableLayout.insertColumn( i, TableLayout.FILL );
comp.setLayout( tableLayout );
// Insets in = comp.getInsets();
// Now populate the table
int[] rowSpans = new int[ numCols ];
addChildren( (XPanel)comp, tableLayout, rowSpans );
// Adjust the constraints if necessary
int numChildren = comp.getComponentCount();
for ( i = 0; i < numChildren; i++ ) {
JComponent c = (JComponent)comp.getComponent( i );
TableLayoutConstraints constraints = tableLayout.getConstraints( c );
// If the row has more than one component make the last column the preferred size.
int numCells = c.getComponentCount();
if ( numCells > 1 )
tableLayout.setColumn( constraints.col1, TableLayout.FILL );
}
if ( XHtmlBuilder.isDebugLayout())
comp.setBorder( new LineBorder( Color.blue, 2 ));
// Reset the parent component to its state prior to this call
cf.setParentComponent( parentComponent );
}
/**
* Calculate the number of columns in the table.
*/
protected int getNumCols( XHtmlTagHandler parent )
{
int colCount = 0;
ArrayList< XHtmlTagHandler > kids = parent.getChildren();
// Check for Col and ColGroup tags
if ( kids != null ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Col ) {
Col c = (Col)handler;
if ( c.tag.equals( "col" ))
colCount += c.getNumCols();
else { // A ColGroup element
int numChildCols = getNumCols( c );
// If there are no child col elements check the span attribute of this colgroup
if ( numChildCols == 0 )
numChildCols = c.getNumCols();
colCount += numChildCols;
}
}
}
// If no columns were specified find the maximum number of cells in a row
if ( colCount == 0 ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Td )
colCount = Math.max( colCount, ((Td)handler).getNumCols());
}
}
}
return Math.max( 1, colCount );
}
/**
* Calculate the number of rows in the table.
*/
protected int getNumRows()
{
ArrayList< XHtmlTagHandler > kids = children;
if ( kids != null ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Td ) {
Td td = (Td)handler;
// Ignore the td elements
if ( "thtr".indexOf( td.tag.toString()) >= 0 )
numRows++;
}
}
}
return numRows;
}
/**
* Get the horizontal padding to add to cells
* @return the padding in pixels
*/
public int getHorizontalPadding()
{
return getWidth( comp.getSize(), cellPadding );
}
/**
* Get the vertical padding to add to cells
* @return the padding in pixels
*/
public int getVerticalPadding()
{
return getHeight( comp.getSize(), cellPadding );
}
/**
* Get the border width/size
* @param the border size in pixels
*/
public int getBorderWidth()
{
return border;
}
/**
* 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
*/
protected void addChildren( XPanel table, TableLayout tableLayout, int[] rowSpans )
{
int row = 0;
ArrayList< XHtmlTagHandler > kids = children;
if ( kids != null ) {
for ( XHtmlTagHandler handler : kids ) {
if ( handler instanceof Td ) {
Td td = (Td)handler;
// Ignore the td elements
if ( "thtr".indexOf( td.tag.toString()) >= 0 )
td.addChildren( table, tableLayout, rowSpans, row++ );
}
}
}
}
/**
* Does this tag break the flow?
* @return true if the flow is broken, otherwsie false
*/
public boolean breaksFlow()
{
return HTML.Tag.TABLE.breaksFlow();
}
}