<?php
/*
Tables.php, provides functions for building tables
Copyright (C) 2004 Arend van Beelen, Auton Rijnsburg
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
This program is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
For any questions, comments or whatever, you may mail me at: hide@address.com
*/
require_once('Widgets.php');
/**
* @brief Class that provides functions for building and displaying tables.
*/
class Table extends Container
{
/**
* Constructor. Creates an empty table.
*
* @param parent Parent widget to add the table to.
*/
public function __construct(Container $parent)
{
parent::__construct($parent);
$this->width = 0;
$this->header = false;
$this->footer = false;
$this->lastRow = false;
}
/**
* Sets whether rows should alternate. This provides a quick way to let
* rows alternate in color by setting the CSS class 'alternate' on every
* second row.
*
* @param rowsAlternate Set to @p true to indicate rows should alternate,
* @p false otherwise.
*
* @sa rowsAlternate()
*/
public function setRowsAlternate($rowsAlternate)
{
$this->rowsAlternate = $rowsAlternate;
}
/**
* Returns whether the rows in this table alternate.
*
* @return @p true if this table's rows alternate, @p false otherwise.
*
* @sa setRowsAlternate()
*/
public function rowsAlternate()
{
return $this->rowsAlternate;
}
/**
* Sets whether columns should alternate. This provides a quick way to
* let columns alternate in color by setting the CSS class 'alternate'
* on every second column.
*
* @param columnsAlternate Set to @p true to indicate columns should
* alternate, @p false otherwise.
*
* @sa columnsAlternate()
*/
public function setColumnsAlternate($columnsAlternate)
{
$this->columnsAlternate = $columnsAlternate;
}
/**
* Returns whether the columns in this table alternate.
*
* @return @p true if this table's columns alternate, @p false otherwise.
*
* @sa setColumnsAlternate()
*/
public function columnsAlternate()
{
return $this->columnsAlternate;
}
/**
* Adds a widget to the children list.
*
* Only TableRow can be added to a Table.
*
* @note You shouldn't have to call this function directly as the
* constructor of widgets will already call this function for you.
*
* @param widget The widget to add to the children list.
*/
public function addWidget(TableRow $widget)
{
parent::addWidget($widget);
$this->lastRow = $widget;
}
/**
* Sets the width of the table in the number of columns. By default, the
* number of columns is determined by the row with the highest number of
* columns.
*
* @param width The number of columns the table should be wide.
*/
public function setWidth($width)
{
$this->width = $width;
}
/**
* Returns the number of columns of the table.
*
* @return The number of columns the table is wide.
*/
public function width()
{
return $this->width;
}
/**
* Returns the last row added to the table.
*
* @return The row last added to the table, or @p false if no rows have
* been added yet.
*/
public function lastRow()
{
return $this->lastRow;
}
/**
* Returns a given TableCell from this table.
*
* @param row The row number from to which the cell belongs, starting from
* 0.
* @param column The column number of the cell, starting from 0.
* @return A TableCell instance, or @p NULL if this cell does not exist.
*/
public function cell($row, $column)
{
return $this->children[$row]->cell($column);
}
/**
* Shows the table.
*/
public function show()
{
Output::write('<table'.$this->parentProperties().'>');
foreach($this->children as $child)
{
if($child->width() > $this->width)
{
$this->width = $child->width();
}
}
Output::write('<columns>');
for($i = 0; $i < $this->width; $i++)
{
Output::write('<column/>');
}
Output::write('</columns>'.
'<rows>');
$i = 0;
foreach($this->children as $child)
{
if($this->rowsAlternate)
{
$alternate = (($i = ($i + 1) % 2) == 0);
}
else
{
$alternate = false;
}
$child->show($alternate, $this->columnsAlternate);
}
Output::write('</rows>'.
'</table>');
}
private $width;
private $rowsAlternate;
private $columnsAlternate;
private $header;
private $footer;
private $lastRow;
}
/**
* @brief A table row.
*/
class TableRow extends Container
{
/**
* Constructor. Creates an empty table row.
*
* @param parent Table to add the row to.
*/
public function __construct(Table $parent)
{
$previousRow = $parent->lastRow();
parent::__construct($parent);
if($previousRow !== false)
{
$rowSpans = $previousRow->rowSpans();
$this->width = sizeof($rowSpans);
for($i = 0; $i < $this->width; $i++)
{
$rowSpans[$i]--;
if($rowSpans[$i] == 0)
{
unset($rowSpans[$i]);
}
}
$this->rowSpans = $rowSpans;
}
else
{
$this->width = 0;
$this->rowSpans = array();
}
}
public function addWidget(Widget $widget)
{
if(!is_a($widget, 'TableCell'))
{
die('Can only add TableCell to a TableRow.');
}
parent::addWidget($widget);
$this->width += $widget->columnSpan();
if($widget->rowSpan() > 1)
{
$this->rowSpans[] = $widget->rowSpan() - 1;
}
}
/**
* Returns the number of columns of the row.
*
* @return The number of columns the row is wide.
*/
public function width()
{
return $this->width;
}
/**
* Returns a given TableCell from this row.
*
* @param n The cell number to return, starting from 0.
* @return A TableCell instance, or @p NULL if this cell does not exist.
*/
public function cell($n)
{
return $this->children[$n];
}
/**
* Shows the table row.
*
* @param alternate Boolean determining whether this row is an
* alternate row.
* @param columnsAlternate Boolean determining whether the columns in this
* header should alternate.
*/
public function show($alternate = false, $columnsAlternate = false)
{
if($this->cssClass == '' && $alternate)
{
$this->setCssClass('alternate');
}
$this->showMissingColumns();
Output::write('<row'.$this->parentProperties().'>');
$i = 0;
foreach($this->children as $child)
{
$alternate = ($columnsAlternate ? (($i = ($i + 1) % 2) == 0) : false);
$child->show($alternate);
}
Output::write('</row>');
}
/**
* @internal
*/
public function adjustColumnSpan($adjustment)
{
$this->width += $adjustment;
}
/**
* Shows any missing columns in this row.
*/
protected function showMissingColumns()
{
if($this->width < $this->parent->width())
{
$missingColumns = $this->parent->width() - $this->width;
while($missingColumns > 0)
{
new TableCell($this);
$missingColumns--;
}
}
}
/**
* @internal
*/
private function rowSpans()
{
return $this->rowSpans;
}
protected $children;
protected $cssClass;
protected $parent;
/**
* Number of cells this row contains.
*/
protected $width;
private $rowSpans;
}
/**
* @brief A table cell.
*/
class TableCell extends RawContainer
{
/**
* Constructor. Creates a table cell.
*
* @param parent Table row to add the cell to.
* @param text Optional text to show in the cell.
*/
public function __construct(TableRow $parent, $text = '')
{
$this->colspan = 1;
$this->rowspan = 1;
parent::__construct($parent, $text);
}
/**
* Sets the column span of the cell.
*
* @param columnSpan The number of columns the cell will span.
*/
public function setColumnSpan($columnSpan)
{
$this->parent->adjustColumnSpan($columnSpan - $this->colspan);
$this->colspan = $columnSpan;
}
/**
* Returns the column span of the cell.
*
* @return The number of columns the cell will span.
*/
public function columnSpan()
{
return $this->colspan;
}
/**
* Sets the row span of the cell.
*
* @param rowSpan The number of rows the cell will span.
*/
public function setRowSpan($rowSpan)
{
$this->rowspan = $rowSpan;
}
/**
* Returns the row span of the cell.
*
* @return The number of rows the cell will span.
*/
public function rowSpan()
{
return $this->rowspan;
}
/**
* Shows the table cell.
*/
public function show($alternate = false)
{
if($this->cssClass == '' && $alternate)
{
$this->setCssClass('alternate');
}
$colspanProperty = ($this->colspan == '1' ? '' : " columnspan=\"{$this->colspan}\"");
$rowspanProperty = ($this->rowspan == '1' ? '' : " rowspan=\"{$this->rowspan}\"");
Output::write('<cell'.$this->parentProperties()."$colspanProperty$rowspanProperty>");
parent::show();
Output::write('</cell>');
}
protected $cssClass;
protected $parent;
private $colspan;
private $rowspan;
}
/**
* @brief A grid used to layout widgets.
*
* A grid layout provides an easy way to align widgets in a grid. A grid by
* default is not visible itself, only the child widgets are visible.
*
* Grids work by setting up a maximum number of columns and adding all child
* widgets in rows with this number of columns beneith each other. So if you
* create a grid with a width of 3 columns and you add 9 widgets, the 1st, 4th
* and 7th widgets will be aligned below each other. The same applies for the
* 2nd, 5th and 8th widgets and for the 3rd, 6th and 9th widgets.
*
* The Table functions setRowsAlternate() and setColumnsAlternate() are
* normally available for this class.
*/
class GridLayout extends Table
{
/**
* Constructor. Creates an empty grid layout.
*
* @param parent Parent widget to add the table to.
* @param columns The number of columns the layout should be wide.
*/
public function __construct(Container $parent, $columns)
{
parent::__construct($parent);
$this->columns = $columns;
$this->currentColumn = $columns;
$this->columnWidths = array();
$this->addCssStyle('border: 0px');
}
/**
* Applies widths to the grid's columns.
*
* Use this function to determine the width of the grid's columns.
*
* Example, if you have a grid layout with 3 columns, you can set widths like
* this:
*
* @code
* $gridLayout->setColumnWidths(array('45%', '10%', '45%'));
* @endcode
*
* @note Call this function before adding widgets to the grid.
*
* @param widths An array containing widths for the respective columns. Use
* CSS units like percentages or pixels to set the widths.
*/
public function setColumnWidths($widths)
{
$this->columnWidths = $widths;
}
public function addWidget(Widget $widget)
{
if(is_a($widget, 'TableRow'))
{
parent::addWidget($widget);
}
else
{
if($this->currentColumn >= $this->columns)
{
$this->currentRow = new TableRow($this);
$this->currentColumn = 0;
}
$cell = new TableCell($this->currentRow);
$cell->addWidget($widget);
if(isset($this->columnWidths[$this->currentColumn]))
{
$cell->addCssStyle("width: {$this->columnWidths[$this->currentColumn]}");
}
$this->currentColumn++;
}
}
private $columns;
private $currentColumn;
private $currentRow;
private $columnWidths;
}
?>