* @copyright 2001-2007 VIKO team and contributors * @license http://www.gnu.org/licenses/gpl.html GPL 2.0 */ /** * This class simplifies the usage of PEAR class HTML_Table */ require_once 'HTML/Table.php'; /** * This class uses HTML class for creating abbrevation elements */ require_once 'HTML.php'; /** * Footer type EMPTY */ define('CONTENT_TABLE_EMPTY', 0); /** * Footer type SUM */ define('CONTENT_TABLE_SUM', 1); /** * Cell type NORMAL */ define('CONTENT_TABLE_NORMAL', 0); /** * Cell type NUMERIC */ define('CONTENT_TABLE_NUMERIC', 1); /** * Cell type DELETE */ define('CONTENT_TABLE_FILESIZE', 2); /** * Cell type DELETE */ define('CONTENT_TABLE_DELETE', 3); /** * Manages creation of HTML data tables for VIKO environment */ class ContentTable { /** * Reference to the table object * * @access private */ var $_table; /** * Reference to the table header object * * @access private */ var $_thead; /** * Reference to the table body object * * @access private */ var $_tbody; /** * Reference to the table footer object * * @access private */ var $_tfoot; /** * The schema (columns description) of the table * * @access private */ var $_schema; /** * The content of the table (list of rows) * * @access private */ var $_data; /** * Constructs new ContentTable instance * * The $schema must be an array consisting of column name * and column description pairs. Column name is simply a unique * value identifying the column. Column description is an * array consisting of attributes, that describe that column. * * In each description-array, the "title" attribute is required, * all others are optional. Here are all the possible attributes: * *
     * $schema = array(
     *     "name" => array(
     *         "title" => _("School name"),
     *         "footer" => _("Total"),
     *     ),
     *     "courses" => array(
     *         "title" => _("Nr of Courses"),
     *         "type" => CONTENT_TABLE_NUMERIC,
     *         "footer" => CONTENT_TABLE_SUM,
     *     ),
     *     "filesize" => array(
     *         "title" => _("Size of files"),
     *         "type" => CONTENT_TABLE_NUMERIC,
     *         "footer" => CONTENT_TABLE_FILESIZE,
     *     ),
     *     "delete" => array(
     *         "title" => _("Delete school"),
     *         "type" => CONTENT_TABLE_DELETE,
     *     ),
     * );
     * 
     *
     * @access public
     * @param array $schema an array describing the columns in this table
     */
    function ContentTable( $schema )
    {
        $this->_schema = $schema;
        // initialize the encapsulated table object
        $this->_table =& new HTML_Table();
        $this->_thead =& $this->_table->getHeader();
        $this->_tbody =& $this->_table->getBody();
        $this->_tfoot =& $this->_table->getFooter();
    }
    /**
     * Loads the table with data
     *
     * $data must contain two-dimensional array with the following structure:
     *
     * 
     * $data = array(
     *     array("first column content", "second column content", ...),  // first row
     *     array("first column content", "second column content", ...),  // second row
     *     array("first column content", "second column content", ...),  // third row
     *     ...
     * )
     * 
     *
     * Alternatively the fields in a row might also be given explicit
     * association with columns by giving the column name as an index.
     * In that way, the ordering of fields doesn't matter and empty
     * fields may just be skipped, like in the following example:
     *
     * 
     * $row = array(
     *     "first_column_name" => "first column content",
     *     "third_column_name" => "third column content",
     *     ...
     * )
     * 
     *
     * @access public
     * @param array $data all the rows of a table
     */
    function PopulateWithData( $data )
    {
        $this->_data = $data;
    }
    /**
     * Converts the table into HTML
     *
     * @access public
     * @return string HTML table element
     */
    function toHTML()
    {
        $this->createTableHead();
        $this->createTableBody();
        $this->createTableFoot();
        $this->setTableAttributes();
        return $this->_table->toHTML();
    }
    function createTableHead()
    {
        // create table head
        $col_index=0;
        foreach ( $this->_schema as $col_name => $column ) {
            $this->_thead->setHeaderContents( 0, $col_index, $column['title'] );
            $col_index++;
        }
    }
    function createTableBody()
    {
        // fill table body with data
        for ( $row_index=0; $row_index < count($this->_data); $row_index++ ) {
            $row = $this->_data[$row_index];
            for ( $col_index=0; $col_index < count($row); $col_index++ ) {
                $cell = $this->createCellContents( $row[$col_index] );
                $this->_tbody->setCellContents( $row_index, $col_index, $cell );
            }
        }
    }
    function createCellContents($content)
    {
        if ( is_array($content) ) {
            return HTML::a( $content[0], $content[1] );
        }
        else {
            return $content;
        }
    }
    function createTextualCellContent($content)
    {
        if ( is_array($content) ) {
            return $content[1];
        }
        else {
            return $content;
        }
    }
    function createTableFoot()
    {
        $col_index=0;
        foreach ( $this->_schema as $col_name => $column ) {
            // when the footer type is defined, set the footer
            if ( isset($column['footer']) && $column['footer'] !== CONTENT_TABLE_EMPTY ) {
                $footer_cell = $this->createFooterCell( $column['footer'], $col_index );
                $this->_tfoot->setCellContents( 0, $col_index, $footer_cell );
            }
            $col_index++;
        }
    }
    /**
     * Creates a footer cell value for a particular type of footer
     */
    function createFooterCell($footer_type, $col_index)
    {
        if ( $footer_type === CONTENT_TABLE_SUM ) {
            return $this->columnSum($col_index);
        }
        else {
            // anything else is considered a literal text of footer
            return $footer_type;
        }
    }
    /**
     * Calculates the sum of values in a column with specified index.
     *
     * If the data doesn't consist entirely of numbers, the sum
     * will result in "not a number".
     */
    function columnSum($col_index)
    {
        $sum = 0;
        foreach ( $this->_data as $row ) {
            if ( !is_numeric($row[$col_index]) ) {
                return 'not a number';
            }
            $sum+= $row[$col_index];
        }
        return $sum;
    }
    /**
     * Sets all kinds of table attributes, like column types and
     * marking odd and even rows.
     */
    function setTableAttributes()
    {
        $this->createStripes($this->_tbody);
        // set attributes for columns
        $col_index=0;
        foreach ( $this->_schema as $column ) {
            if ( isset($column['type']) && $column['type'] !== CONTENT_TABLE_NORMAL ) {
                $this->setColumnType($column['type'], $col_index);
            }
            $col_index++;
        }
    }
    function setColumnType($column_type, $col_index)
    {
        if ( $column_type === CONTENT_TABLE_NUMERIC ) {
            // numeric type applies class "nr" only to the body and footer
            $attr = array('class' => 'nr');
            $this->_tfoot->setColAttributes($col_index, $attr);
            $this->_tbody->setColAttributes($col_index, $attr);
        }
        elseif ( $column_type === CONTENT_TABLE_FILESIZE ) {
            // filesize type applies class "nr" only to the body and footer
            $attr = array('class' => 'nr');
            $this->_tfoot->setColAttributes($col_index, $attr);
            $this->_tbody->setColAttributes($col_index, $attr);
            // the fields themselves also have to be converted
            for ( $i = 0; $i < count($this->_data); $i++ ) {
                $size = $this->_data[$i][$col_index];
                $formatted_size = $this->makeHumanReadableFilesize($size);
                $this->_tbody->setCellContents($i, $col_index, $formatted_size);
            }
            // and the footer too
            $size = $this->_tfoot->getCellContents(0, $col_index);
            $formatted_size = $this->makeHumanReadableFilesize($size);
            $this->_tfoot->setCellContents(0, $col_index, $formatted_size);
        }
        elseif ( $column_type === CONTENT_TABLE_DELETE ) {
            // delete type applies class 'delete' only to the body and header
            $attr = array('class' => 'delete');
            $this->_thead->setColAttributes($col_index, $attr);
            $this->_tbody->setColAttributes($col_index, $attr);
            // the header must be converted into abbrevation element
            $title = $this->_thead->getCellContents(0, $col_index);
            $abbr = HTML::abbr('X', $title);
            $this->_thead->setHeaderContents(0, $col_index, $abbr);
            // the data cells containing URI's have to be converted to links.
            for ( $i = 0; $i < count($this->_data); $i++ ) {
                // delete-cells contain URI's
                $uri = $this->_data[$i][$col_index];
                // contents of first column will be contained inside title
                $first_cell = $this->createTextualCellContent( $this->_data[$i][0] );
                $title = sprintf( _('delete %s'), $first_cell );
                $link = HTML::a($uri, 'X', $title);
                $this->_tbody->setCellContents($i, $col_index, $link);
            }
        }
        else {
            // anything else is considered a literal CSS class name
            $attr = array('class' => $column_type );
            // CSS class is applied to all parts of the table
            $this->_thead->setColAttributes($col_index, $attr);
            $this->_tfoot->setColAttributes($col_index, $attr);
            $this->_tbody->setColAttributes($col_index, $attr);
        }
    }
    function createStripes(&$table_section)
    {
        $odd_row = array('class' => 'odd');
        $even_row = array('class' => 'even');
        $table_section->altRowAttributes(0, $odd_row, $even_row, true);
    }
    /**
     * Returns the size of the file in human-readable format
     *
     * Mutch like the -h option in many UNIX utilities.
     * If the size is >= 1024 bytes, it is represented in KB,
     * if size is >= 1024 KB, it's given in MB.
     *
     * The unit B, KB, MB or GB is appended to the returned string.
     * If the value is a fraction, only one place after the comma is shown.
     *
     * @static
     * @param int $size file size in bytes
     * @return string file size
     */
    function makeHumanReadableFilesize( $size )
    {
        if ( $size < 1024 ) {
            return $size . " B";
        }
        elseif ( $size < 1024*1024 ) {
            return round($size/1024, 1) . " KB";
        }
        elseif ( $size < 1024*1024*1024 ) {
            return round($size/1024/1024, 1) . " MB";
        }
        else {
            return round($size/1024/1024/1024, 1) . " GB";
        }
    }
}
?>