Index: lib/tablelib.php
===================================================================
RCS file: /cvsroot/moodle/moodle/lib/tablelib.php,v
retrieving revision 1.24.2.5
diff -u -r1.24.2.5 tablelib.php
--- lib/tablelib.php 22 May 2008 02:33:56 -0000 1.24.2.5
+++ lib/tablelib.php 3 Jun 2008 09:05:37 -0000
@@ -7,6 +7,10 @@
define('TABLE_VAR_ILAST', 5);
define('TABLE_VAR_PAGE', 6);
+define('TABLE_P_TOP', 1);
+define('TABLE_P_BOTTOM', 2);
+
+
class flexible_table {
var $uniqueid = NULL;
@@ -35,6 +39,37 @@
var $sort_default_order = SORT_ASC;
/**
+ * Array of positions in which to display download controls.
+ */
+ var $showdownloadbuttonsat= array(TABLE_P_TOP);
+
+ /**
+ * @var string which download plugin to use. Default '' means none - print
+ * html table with paging. Property set by is_downloading which typically
+ * passes in cleaned data from $
+ */
+ var $download = '';
+
+ /**
+ * @var boolean whether data is downloadable from table. Determines whether
+ * to display download buttons. Set by method downloadable().
+ */
+ var $downloadable = false;
+
+ /**
+ * @var string which download plugin to use. Default '' means none - print
+ * html table with paging.
+ */
+ var $defaultdownloadformat = 'csv';
+
+ /**
+ * @var boolean Has start output been called yet?
+ */
+ var $started_output = false;
+
+ var $exportclass = null;
+
+ /**
* Constructor
* @param int $uniqueid
* @todo Document properly
@@ -50,6 +85,58 @@
TABLE_VAR_PAGE => 'page'
);
}
+
+ /**
+ * Call this to pass the download type. Use :
+ * $download = optional_param('download', '', PARAM_ALPHA);
+ * To get the download type. We assume that if you call this function with
+ * params that this table's data is downloadable, so we call is_downloadable
+ * for you (even if the param is '', which means no download this time.
+ * Also you can call this method with no params to get the current set
+ * download type.
+ * @param string $download download type. One of csv, tsv, xhtml, ods, etc
+ * @param string $filename filename for downloads without file extension.
+ * @param string $sheettitle title for downloaded data.
+ * @return string download type. One of csv, tsv, xhtml, ods, etc
+ */
+ function is_downloading($download = null, $filename='', $sheettitle=''){
+ if ($download!==null){
+ $this->filename = clean_filename($filename);
+ $this->sheettitle = $sheettitle;
+ $this->is_downloadable(true);
+ $this->download = $download;
+ if (!empty($download)){
+ $classname = 'table_'.$download.'_export_format';
+ $this->exportclass = new $classname($this);
+ }
+ }
+ return $this->download;
+ }
+ /**
+ * Probably don't need to call this directly. Calling is_downloading with a
+ * param automatically sets table as downloadable.
+ *
+ * @param boolean $downloadable optional param to set whether data from
+ * table is downloadable. If ommitted this function can be used to get
+ * current state of table.
+ * @return boolean whether table data is set to be downloadable.
+ */
+ function is_downloadable($downloadable = null){
+ if ($downloadable !== null){
+ $this->downloadable = $downloadable;
+ }
+ return $this->downloadable;
+ }
+
+ /**
+ * Where to show download buttons.
+ * @param array $showat array of postions in which to show download buttons.
+ * Containing TABLE_P_TOP and/or TABLE_P_BOTTOM
+ */
+ function show_download_buttons_at($showat){
+ $this->showdownloadbuttonsat = $showat;
+ }
+
/**
* Sets the is_sortable variable to the given boolean, sort_default_column to
@@ -87,7 +174,6 @@
}
return !in_array($column, $this->column_nosort);
}
-
/**
* Sets the is_collapsible variable to the given boolean.
* @param bool $bool
@@ -153,7 +239,7 @@
}
/**
- * I think that what this method does is set the column so that if the same data appears in
+ * What this method does is set the column so that if the same data appears in
* consecutive rows, then it is not repeated.
*
* For example, in the quiz overview report, the fullname column is set to be suppressed, so
@@ -193,7 +279,7 @@
}
/**
- * Sets all columns of the given $property to the given $value in $this->column_style.
+ * Sets all columns' $propertys to the given $value in $this->column_style.
* @param integer $property
* @param string $value
* @return void
@@ -206,8 +292,7 @@
/**
* Sets $this->reseturl to the given $url, and $this->baseurl to the given $url plus ? or &
- * @param type? $url
- * @return type?
+ * @param string $url the url with params needed to call up this page
*/
function define_baseurl($url) {
$this->reseturl = $url;
@@ -220,8 +305,8 @@
}
/**
- * @todo Document
- * @return type?
+ * @param array $columns an array of identifying names for columns. If
+ * columns are sorted then column names must correspond to a field in sql.
*/
function define_columns($columns) {
$this->columns = array();
@@ -238,49 +323,19 @@
}
/**
- * @todo Document
- * @return type?
+ * @param array $headers numerical keyed array of displayed string titles
+ * for each column.
*/
function define_headers($headers) {
$this->headers = $headers;
}
+
- /**
- * @todo Document
- * @return type?
- */
- function make_styles_string(&$styles) {
- if(empty($styles)) {
- return '';
- }
-
- $string = ' style="';
- foreach($styles as $property => $value) {
- $string .= $property.':'.$value.';';
- }
- $string .= '"';
- return $string;
- }
-
- /**
- * @todo Document
- * @return type?
- */
- function make_attributes_string(&$attributes) {
- if(empty($attributes)) {
- return '';
- }
-
- $string = ' ';
- foreach($attributes as $attr => $value) {
- $string .= ($attr.'="'.$value.'" ');
- }
- return $string;
- }
/**
- * @todo Document
+ * Must be called after table is defined. Use methods above first. Cannot
+ * use functions below till after calling this method.
* @return type?
*/
function setup() {
@@ -351,10 +406,7 @@
}
// If we didn't sort just now, then use the default sort order if one is defined and the column exists
- if(empty($this->sess->sortby) && !empty($this->sort_default_column) && (isset($this->columns[$this->sort_default_column])
- || (in_array('fullname',$this->columns)
- && in_array($this->sort_default_column,
- array('firstname','lastname'))))) {
+ if(empty($this->sess->sortby) && !empty($this->sort_default_column)) {
$this->sess->sortby = array ($this->sort_default_column => ($this->sort_default_order == SORT_DESC ? SORT_DESC : SORT_ASC));
}
@@ -428,8 +480,10 @@
}
/**
- * @todo Document
- * @return type?
+ * @param string $uniqueid used to identify the table you want the sql sort
+ * string for when method is called as a static method.
+ * @return string sql to put after ORDER BY or empty string if there is
+ * none.
*/
function get_sql_sort($uniqueid = NULL) {
if($uniqueid === NULL) {
@@ -462,8 +516,7 @@
}
/**
- * @todo Document
- * @return type?
+ * @return integer the offset for LIMIT clause of SQL
*/
function get_page_start() {
if(!$this->use_pages) {
@@ -473,8 +526,7 @@
}
/**
- * @todo Document
- * @return type?
+ * @return integer the pagesize for LIMIT clause of SQL
*/
function get_page_size() {
if(!$this->use_pages) {
@@ -484,8 +536,7 @@
}
/**
- * @todo Document
- * @return type?
+ * @return string sql to add to where statement.
*/
function get_sql_where() {
if(!isset($this->columns['fullname'])) {
@@ -507,8 +558,103 @@
}
/**
- * @todo Document
- * @return type?
+ * Add a row of data to the table. This function takes an array with
+ * column names as keys.
+ * It ignores any elements with keys that are not defined as columns. It
+ * puts in empty strings into the row when there is no element in the passed
+ * array corresponding to a column in the table. It puts the row elements in
+ * the proper order.
+ * @param $rowwithkeys array
+ *
+ */
+ function add_data_keyed($rowwithkeys){
+ $this->add_data($this->get_row_from_keyed($rowwithkeys));
+ }
+
+ /**
+ * Add a seperator line to table.
+ */
+ function add_separator() {
+ if(!$this->setup) {
+ return false;
+ }
+ $this->add_data(NULL);
+ }
+
+ /**
+ * This method actually directly echoes the row passed to it now or adds it
+ * to the download. If this is the first row and start_output has not
+ * already been called this method also calls start_output to open the table
+ * or send headers for the downloaded.
+ * Can be used as before. print_html now calls finish_html to close table.
+ *
+ * @param array $row a numerically keyed row of data to add to the table.
+ * @return boolean success.
+ */
+ function add_data($row) {
+ if(!$this->setup) {
+ return false;
+ }
+ if (!$this->started_output){
+ $this->start_output();
+ }
+ if ($this->exportclass!==null){
+ if ($row === null){
+ $this->exportclass->add_seperator();
+ } else {
+ $this->exportclass->add_data($row);
+ }
+ } else {
+ $this->print_row($row);
+ }
+ return true;
+ }
+
+
+
+ /**
+ * You should call this to finish outputting the table data after adding
+ * data to the table with add_data or add_data_keyed.
+ *
+ */
+ function finish_output(){
+ if ($this->exportclass!==null){
+ $this->exportclass->finish_output();
+ }else{
+ $this->finish_html();
+ }
+ }
+
+ /**
+ * Hook that can be overridden in child classes to wrap a table in a form
+ * for example. Called only when there is data to display and not
+ * downloading.
+ */
+ function wrap_html_start(){
+ }
+
+ /**
+ * Hook that can be overridden in child classes to wrap a table in a form
+ * for example. Called only when there is data to display and not
+ * downloading.
+ */
+ function wrap_html_finish(){
+ }
+
+ /**
+ * This method is deprecated although the old api is still supported.
+ * @deprecated 1.9.2 - Jun 2, 2008
+ */
+ function print_html() {
+ if(!$this->setup) {
+ return false;
+ }
+ $this->finish_html();
+ }
+
+ /**
+ * This function is not part of the public api.
+ * @return string initial of first name we are currently filtering by
*/
function get_initial_first() {
if(!$this->use_initials) {
@@ -519,8 +665,8 @@
}
/**
- * @todo Document
- * @return type?
+ * This function is not part of the public api.
+ * @return string initial of last name we are currently filtering by
*/
function get_initial_last() {
if(!$this->use_initials) {
@@ -529,27 +675,16 @@
return $this->sess->i_last;
}
-
+
/**
- * @todo Document
- * @return type?
+ * This function is not part of the public api.
*/
- function print_html() {
- global $CFG;
-
- if(!$this->setup) {
- return false;
- }
-
- $colcount = count($this->columns);
-
- // Do we need to print initial bars?
-
+ function print_initials_bar(){
if($this->use_initials && isset($this->columns['fullname'])) {
-
+
$strall = get_string('all');
$alpha = explode(',', get_string('alphabet'));
-
+
// Bar of first initials
echo '
'.get_string('firstname').' : ';
@@ -566,9 +701,9 @@
}
}
echo '
';
-
+
// Bar of last initials
-
+
echo ''.get_string('lastname').' : ';
if(!empty($this->sess->i_last)) {
echo '
'.$strall.'';
@@ -583,27 +718,152 @@
}
}
echo '
';
+
+ }
+ }
+ /**
+ * This function is not part of the public api.
+ */
+ function print_nothing_to_display(){
+ if ($this->get_initial_first()||$this->get_initial_last()){
+ // Do we need to print initial bars?
+ $this->print_initials_bar();
}
- // End of initial bars code
+ print_heading(get_string('nothingtodisplay'));
+ }
- // Paging bar
- if($this->use_pages) {
- print_paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl, $this->request[TABLE_VAR_PAGE]);
+ /**
+ * This function is not part of the public api.
+ */
+ function get_row_from_keyed($rowwithkeys){
+ if (is_object($rowwithkeys)){
+ $rowwithkeys = (array)$rowwithkeys;
}
+ foreach (array_keys($this->columns) as $column){
+ if (isset($rowwithkeys[$column])){
+ $row [] = $rowwithkeys[$column];
+ } else {
+ $row[] ='';
+ }
+ }
+ return $row;
+ }
+ /**
+ * This function is not part of the public api.
+ */
+ function get_download_menu(){
+ $allclasses= get_declared_classes();
+ $exportclasses = array();
+ foreach ($allclasses as $class){
+ $matches = array();
+ if (preg_match('/^table\_([a-z]+)\_export\_format$/', $class, $matches)){
+ $type = $matches[1];
+ $exportclasses[$type]= get_string("download$type", 'table');
+ }
+ }
+ return $exportclasses;
+ }
+
+ /**
+ * This function is not part of the public api.
+ */
+ function download_buttons(){
+ if ($this->is_downloadable() && !$this->is_downloading()){
+ $downloadoptions = $this->get_download_menu();
+ $html = '';
- if (empty($this->data)) {
- print_heading(get_string('nothingtodisplay'));
- return true;
+ return $html;
+ } else {
+ return '';
+ }
+ }
+ /**
+ * This function is not part of the public api.
+ * You don't normally need to call this. It is called automatically when
+ * needed when you start adding data to the table.
+ *
+ */
+ function start_output(){
+ $this->started_output = true;
+ if ($this->exportclass!==null){
+ $this->exportclass->start_output($this->filename, $this->sheettitle);
+ $this->exportclass->output_headers($this->headers);
+ } else {
+ $this->start_html();
+ $this->print_headers();
}
+ }
+ /**
+ * This function is not part of the public api.
+ */
+ function print_row($row){
+ static $suppress_lastrow = NULL;
+ static $oddeven = 1;
+ $colcount = count($this->columns);
+ $colbyindex = array_flip($this->columns);
+ echo '';
+ // If we have a separator, print it
+ if($row === NULL && $colcount) {
+ echo ' | ';
+ }
+ else {
+ foreach($row as $index => $data) {
+ $column = $colbyindex[$index];
+ echo 'make_styles_string($this->column_style[$column]).'>';
+ if(empty($this->sess->collapse[$column])) {
+ if($this->column_suppress[$column] && $suppress_lastrow !== NULL && $suppress_lastrow[$index] === $data) {
+ echo ' ';
+ }
+ else {
+ echo $data;
+ }
+ }
+ else {
+ echo ' ';
+ }
+ echo ' | ';
+ }
+ }
+ echo '
';
+ $oddeven = $oddeven ? 0 : 1;
$suppress_enabled = array_sum($this->column_suppress);
- $suppress_lastrow = NULL;
- // Start of main data table
-
- echo 'make_attributes_string($this->attributes).'>';
+ if($suppress_enabled) {
+ $suppress_lastrow = $row;
+ }
+ }
+ /**
+ * This function is not part of the public api.
+ */
+ function finish_html(){
+ if (!$this->started_output) {
+ //no data has been added to the table.
+ $this->print_nothing_to_display();
+ } else {
+ echo '
';
+ $this->wrap_html_finish();
+ // Paging bar
+ if(in_array(TABLE_P_BOTTOM, $this->showdownloadbuttonsat)) {
+ echo $this->download_buttons();
+ }
+ if($this->use_pages) {
+ print_paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl, $this->request[TABLE_VAR_PAGE]);
+ }
+ }
+ }
+ /**
+ * This function is not part of the public api.
+ */
+ function print_headers(){
+ global $CFG;
echo '';
foreach($this->columns as $column => $index) {
@@ -705,97 +965,493 @@
}
echo '
';
-
- if(!empty($this->data)) {
- $oddeven = 1;
- $colbyindex = array_flip($this->columns);
- foreach($this->data as $row) {
- $oddeven = $oddeven ? 0 : 1;
- echo '';
-
- // If we have a separator, print it
- if($row === NULL && $colcount) {
- echo ' | ';
- }
- else {
- foreach($row as $index => $data) {
- if($index >= $colcount) {
- break;
- }
- $column = $colbyindex[$index];
- echo 'make_styles_string($this->column_style[$column]).'>';
- if(empty($this->sess->collapse[$column])) {
- if($this->column_suppress[$column] && $suppress_lastrow !== NULL && $suppress_lastrow[$index] === $data) {
- echo ' ';
- }
- else {
- echo $data;
- }
- }
- else {
- echo ' ';
- }
- echo ' | ';
- }
- }
- echo '
';
- if($suppress_enabled) {
- $suppress_lastrow = $row;
- }
- }
- }
-
- echo '';
+ }
+
+ /**
+ * This function is not part of the public api.
+ */
+ function start_html(){
+
+ // Do we need to print initial bars?
+ $this->print_initials_bar();
// Paging bar
if($this->use_pages) {
print_paging_bar($this->totalrows, $this->currpage, $this->pagesize, $this->baseurl, $this->request[TABLE_VAR_PAGE]);
}
+
+ if(in_array(TABLE_P_TOP, $this->showdownloadbuttonsat)) {
+ echo $this->download_buttons();
+ }
+
+ $this->wrap_html_start();
+ // Start of main data table
+
+ echo 'make_attributes_string($this->attributes).'>';
+
}
/**
+ * This function is not part of the public api.
* @todo Document
* @return type?
*/
- function add_data($row) {
- if(!$this->setup) {
- return false;
+ function make_styles_string(&$styles) {
+ if(empty($styles)) {
+ return '';
+ }
+
+ $string = ' style="';
+ foreach($styles as $property => $value) {
+ $string .= $property.':'.$value.';';
}
- $this->data[] = $row;
+ $string .= '"';
+ return $string;
}
/**
+ * This function is not part of the public api.
* @todo Document
* @return type?
*/
- function add_separator() {
- if(!$this->setup) {
- return false;
+ function make_attributes_string(&$attributes) {
+ if(empty($attributes)) {
+ return '';
+ }
+
+ $string = ' ';
+ foreach($attributes as $attr => $value) {
+ $string .= ($attr.'="'.$value.'" ');
}
- $this->data[] = NULL;
+
+ return $string;
+ }
+}
+
+class table_sql extends flexible_table{
+
+ var $countsql = NULL;
+ /**
+ * @var object sql for querying db. Has fields 'fields', 'from', 'where'.
+ */
+ var $sql = NULL;
+ /**
+ * @var array Data fetched from the db.
+ */
+ var $rawdata = NULL;
+
+ /**
+ * @var boolean Overriding default for this.
+ */
+ var $is_sortable = true;
+ /**
+ * @var boolean Overriding default for this.
+ */
+ var $is_collapsible = true;
+
+ /**
+ * @var string Key of field returned by db query that is the id field of the
+ * user table or equivalent.
+ */
+ var $useridfield = 'id';
+
+
+ /**
+ * @param string $uniqueid a string identifying this table.Used as a key in
+ * session vars.
+ */
+ function table_sql($uniqueid){
+ parent::flexible_table($uniqueid);
+ // some sensible defaults
+ $this->set_attribute('cellspacing', '0');
+ $this->set_attribute('class', 'generaltable generalbox');
}
/**
- * Add a row of data to the table. This function takes an array with
- * column names as keys.
- * It ignores any elements with keys that are not defined as columns. It
- * puts in empty strings into the row when there is no element in the passed
- * array corresponding to a column in the table. It puts the row elements in
- * the proper order.
- * @param $rowwithkeys array
*
+ * @param array $row row of data from db used to make one row of the table.
+ * @return array one row for the table, added using add_data_keyed method.
*/
- function add_data_keyed($rowwithkeys){
+ function format_row($row){
+ $formattedrow = array();
foreach (array_keys($this->columns) as $column){
- if (isset($rowwithkeys[$column])){
- $row [] = $rowwithkeys[$column];
+ $colmethodname = 'col_'.$column;
+ if (method_exists($this, $colmethodname)){
+ $formattedcolumn = $this->$colmethodname($row);
} else {
- $row[] ='';
+ $formattedcolumn = $this->other_cols($column, $row);
+ if ($formattedcolumn===NULL){
+ $formattedcolumn = $row->$column;
+ }
}
+ $formattedrow[$column] = $formattedcolumn;
}
- $this->add_data($row);
+ return $formattedrow;
}
+
+ /**
+ * Fullname is treated as a special columname in tablelib and should always
+ * be treated the same as the fullname of a user.
+ * @uses $this->useridfield if the userid field is not expected to be id
+ * then you need to override $this->useridfield to point at the correct
+ * field for the user id.
+ *
+ */
+ function col_fullname($row){
+ global $COURSE, $CFG;
+ if (!$this->download){
+
+ return ''.fullname($row).'';
+ } else {
+ return fullname($row);
+ }
+ }
+
+ /**
+ * You can override this method in a child class. See the description of
+ * build_table which calls this method.
+ */
+ function other_cols($column, $row){
+ return NULL;
+ }
+
+ /**
+ * Take the data returned from the db_query and go through all the rows
+ * processing each col using either col_{columnname} method or other_cols
+ * method or if other_cols returns NULL then put the data straight into the
+ * table.
+ */
+ function build_table(){
+ if ($this->rawdata){
+ foreach($this->rawdata as $row){
+ $formattedrow = $this->format_row($row);
+ $this->add_data_keyed($formattedrow);
+ }
+ }
+ }
+
+
+ /**
+ * This is only needed if you want to use different sql to count rows.
+ * Used for example when perhaps all db JOINS are not needed when counting
+ * records. You don't need to call this function the count_sql
+ * will be generated automatically.
+ *
+ * We need to count rows returned by the db seperately to the query itself
+ * as we need to know how many pages of data we have to display.
+ */
+ function set_count_sql($sql){
+ $this->countsql = $sql;
+ }
+
+ /**
+ * Set the sql to query the db. Query will be :
+ * SELECT $fields FROM $from WHERE $where
+ * Of course you can use sub-queries, JOINS etc. by putting them in the
+ * appropriate clause of the query.
+ */
+ function set_sql($fields, $from, $where){
+ $this->sql = new object();
+ $this->sql->fields = $fields;
+ $this->sql->from = $from;
+ $this->sql->where = $where;
+ }
+
+ /**
+ * Query the db. Store results in the table object for use by build_table.
+ *
+ * @param integer $pagesize size of page for paginated displayed table.
+ * @param boolean $useinitialsbar do you want to use the initials bar. Bar
+ * will only be used if there is a fullname column defined for the table.
+ */
+ function query_db($pagesize, $useinitialsbar=true){
+ if (!$this->is_downloading()) {
+ if ($this->countsql === NULL){
+ $this->countsql = 'SELECT COUNT(1) FROM '.$this->sql->from.' WHERE '.$this->sql->where;
+ }
+ if ($useinitialsbar && !$this->is_downloading()) {
+ $totalinitials = count_records_sql($this->countsql);
+ $this->initialbars($totalinitials>$pagesize);
+ }
+
+ if ($this->get_sql_where()) {
+ $this->countsql .= ' AND '.$this->get_sql_where();
+ $this->sql->where .= ' AND '.$this->get_sql_where();
+ }
+ $total = count_records_sql($this->countsql);
+
+
+ $this->pagesize($pagesize, $total);
+ }
+
+ // Fetch the attempts
+ $sort = $this->get_sql_sort();
+ $sort = $sort?" ORDER BY {$sort}":'';
+ $sql = "SELECT {$this->sql->fields} FROM {$this->sql->from} WHERE {$this->sql->where}{$sort}";
+ if (!$this->is_downloading()) {
+ $this->rawdata = get_records_sql($sql, $this->get_page_start(), $this->get_page_size());
+ } else {
+ $this->rawdata = get_records_sql($sql);
+ }
+ }
+
+
+ /**
+ * Convenience method to call a number of methods for you to display the
+ * table.
+ */
+ function out($pagesize, $useinitialsbar, $downloadhelpbutton=''){
+ if (!$this->columns){
+ $onerow = get_record_sql("SELECT {$this->sql->fields} FROM {$this->sql->from} WHERE {$this->sql->where}", true);
+ //if columns is not set then define columns as the keys of the rows returned
+ //from the db.
+ $this->define_columns(array_keys((array)$onerow));
+ $this->define_headers(array_keys((array)$onerow));
+ }
+ $this->setup();
+ $this->query_db($pagesize, $useinitialsbar);
+ $this->build_table();
+ $this->finish_output();
+ }
+}
+
+class table_default_export_format_parent{
+ /**
+ * @var flexible_table or child class reference pointing to table class
+ * object from which to export data.
+ */
+ var $table;
+ function table_default_export_format_parent(&$table){
+ $this->table =& $table;
+ }
+
+ function add_data($row) {
+ return false;
+ }
+ function add_seperator() {
+ return false;
+ }
+ function finish_output(){
+ }
+}
+
+class table_spreadsheet_export_format_parent extends table_default_export_format_parent{
+ var $rownum;
+ var $workbook;
+ var $worksheet;
+ /**
+ * @var object format object - format for normal table cells
+ */
+ var $formatnormal;
+ /**
+ * @var object format object - format for header table cells
+ */
+ var $formatheaders;
+ /**
+ * should be overriden in child class.
+ */
+ var $fileextension;
+
+ /**
+ * This method will be overridden in the child class.
+ */
+ function define_workbook(){
+ }
+ function start_output($filename, $sheettitle){
+ $this->filename = $filename.'.'.$this->fileextension;
+ $this->define_workbook();
+ // Creating the first worksheet
+ $this->worksheet =& $this->workbook->add_worksheet();
+ // format types
+ $this->formatnormal =& $this->workbook->add_format();
+ $this->formatnormal->set_bold(0);
+ $this->formatheaders =& $this->workbook->add_format();
+ $this->formatheaders->set_bold(1);
+ $this->formatheaders->set_align('center');
+
+ // Sending HTTP headers
+ $this->workbook->send($this->filename);
+ // Creating the first worksheet
+
+ $this->rownum=0;
+ }
+ function output_headers($headers){
+ $colnum = 0;
+ foreach ($headers as $item) {
+ $this->worksheet->write($this->rownum,$colnum,$item,$this->formatheaders);
+ $colnum++;
+ }
+ $this->rownum++;
+ }
+ function add_data($row){
+ $colnum = 0;
+ foreach($row as $item){
+ $this->worksheet->write($this->rownum,$colnum,$item,$this->formatnormal);
+ $colnum++;
+ }
+ $this->rownum++;
+ return true;
+ }
+ function add_seperator() {
+ $this->rownum++;
+ return true;
+ }
+ function finish_output(){
+ $this->workbook->close();
+ exit;
+ }
+}
+
+class table_excel_export_format extends table_spreadsheet_export_format_parent{
+ var $fileextension = 'xls';
+
+ function define_workbook(){
+ global $CFG;
+ require_once("$CFG->libdir/excellib.class.php");
+ // Creating a workbook
+ $this->workbook = new MoodleExcelWorkbook("-");
+ }
+
+}
+
+class table_ods_export_format extends table_spreadsheet_export_format_parent{
+ var $fileextension = 'ods';
+ function define_workbook(){
+ global $CFG;
+ require_once("$CFG->libdir/odslib.class.php");
+ // Creating a workbook
+ $this->workbook = new MoodleODSWorkbook("-");
+ }
+}
+
+class table_text_export_format_parent extends table_default_export_format_parent{
+ var $seperator = "\t";
+ function start_output($filename, $sheettitle){
+ $this->filename = $filename.".txt";
+
+ header("Content-Type: application/download\n");
+ header("Content-Disposition: attachment; filename=\"$this->filename\"");
+ header("Expires: 0");
+ header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
+ header("Pragma: public");
+ }
+ function output_headers($headers){
+ echo implode($this->seperator, $headers)." \n";
+ }
+ function add_data($row){
+ echo implode($this->seperator, $row)." \n";
+ return true;
+ }
+ function finish_output(){
+ exit;
+ }
}
+class table_tsv_export_format extends table_text_export_format_parent{
+ var $seperator = "\t";
+
+}
+
+class table_csv_export_format extends table_text_export_format_parent{
+ var $seperator = ",";
+
+}
+
+class table_xhtml_export_format extends table_default_export_format_parent{
+ var $seperator = "\t";
+ function start_output($filename, $sheettitle){
+ $this->table->sortable(false);
+ $this->table->collapsible(false);
+ $this->filename = $filename.".html";
+
+ header("Content-Type: application/download\n");
+ header("Content-Disposition: attachment; filename=\"$this->filename\"");
+ header("Expires: 0");
+ header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
+ header("Pragma: public");
+
+ //html headers
+
+ echo <<
+
+
+
+
+
+ $sheettitle
+
+
+$sheettitle
+EOF;
+ $this->table->start_html();
+ }
+ function output_headers($headers){
+ $this->table->print_headers();
+ }
+ function add_data($row){
+ $this->table->print_row($row);
+ return true;
+ }
+ function add_seperator() {
+ $this->table->print_row(NULL);
+ return true;
+ }
+ function finish_output(){
+ $this->table->finish_html();
+ echo '';
+ exit;
+ }
+}
?>
Index: lang/en_utf8/help/tableexportformats.html
===================================================================
RCS file: lang/en_utf8/help/tableexportformats.html
diff -N lang/en_utf8/help/tableexportformats.html
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lang/en_utf8/help/tableexportformats.html 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,32 @@
+Downloading Table Data
+
+You may want to download the data displayed in the on-screen
+table for further analysis. You can choose between the many file
+formats for downloaded data shown below.
+
In each case data will be
+presented as a table with appropriate column titles, as on the screen.
+The downloaded table is :
+- not paged, all data for all pages will be downloaded in a
+single file.
+- not filtered by username initials. (Some on screen tables of data about users allows you to
+select to only display data for users with selected first / last name initials).
+- not affected by sorting by columns that a user can do on the on screen table.
+
+
+Microsoft Excel Spreadsheet format.
+You will get an .xls spreadsheet document.
+OpenDocument Spreadsheet (ODS) format.
+You will get an .ods spreadsheet document. This format
+can be opened with OpenOffice.org, KOffice, Google Docs,
+NeoOffice, Zoho, IBM Lotus Symphony and Corel WordPerfect Office X4.
+A tab seperated values text file
+In this case, you will get a
+regular text file. A line for each row in the table with data
+separated by tabstops. Can be opened by many different apps.
+A comma seperated values text file
+In this case, you will get a
+regular text file. A line for each row in the table with data
+separated by commas. Can be opened by many different apps.
+An unpaged XHTML document
+In this case, you will get a saveable, printable xhtml document without the headers
+and footers that you have on a normal Moodle page.
Index: lang/en_utf8/table.php
===================================================================
RCS file: lang/en_utf8/table.php
diff -N lang/en_utf8/table.php
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ lang/en_utf8/table.php 1 Jan 1970 00:00:00 -0000
@@ -0,0 +1,9 @@
+