Merge branch 'MDL-33441' of git://github.com/danpoltawski/moodle
[moodle.git] / lib / odslib.class.php
blobbe1a5d9d6e2922eaaacf3d9e324327a796dceeb8
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * Major Contributors:
20 * - Eloy Lafuente (stronk7) {@link http://contiento.com}
21 * - Petr Skoda (skodak)
23 * @package core
24 * @subpackage lib
25 * @copyright (C) 2001-3001 Eloy Lafuente (stronk7) {@link http://contiento.com}
26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
29 defined('MOODLE_INTERNAL') || die();
31 /**
32 * The xml used here is derived from output of KSpread 1.6.1
34 * Known problems:
35 * - missing formatting
36 * - write_date() works fine in OOo, but it does not work in KOffice - it knows only date or time but not both :-(
38 * @package moodlecore
39 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
40 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
42 class MoodleODSWorkbook {
43 var $worksheets = array();
44 var $filename;
46 function MoodleODSWorkbook($filename) {
47 $this->filename = $filename;
50 /* Create one Moodle Worksheet
51 * @param string $name Name of the sheet
53 function &add_worksheet($name = '') {
54 /// Create the Moodle Worksheet. Returns one pointer to it
55 $ws = new MoodleODSWorksheet($name);
56 $this->worksheets[] =& $ws;
57 return $ws;
60 /* Create one Moodle Format
61 * @param array $properties array of properties [name]=value;
62 * valid names are set_XXXX existing
63 * functions without the set_ part
64 * i.e: [bold]=1 for set_bold(1)...Optional!
66 function &add_format($properties = array()) {
67 $format = new MoodleODSFormat($properties);
68 return $format;;
71 /* Close the Moodle Workbook
73 function close() {
74 global $CFG;
75 require_once($CFG->libdir.'/filelib.php');
77 $dir = 'ods/'.time();
78 make_temp_directory($dir);
79 make_temp_directory($dir.'/META-INF');
80 $dir = "$CFG->tempdir/$dir";
81 $files = array();
83 $handle = fopen("$dir/mimetype", 'w');
84 fwrite($handle, get_ods_mimetype());
85 $files[] = "$dir/mimetype";
87 $handle = fopen("$dir/content.xml", 'w');
88 fwrite($handle, get_ods_content($this->worksheets));
89 $files[] = "$dir/content.xml";
91 $handle = fopen("$dir/meta.xml", 'w');
92 fwrite($handle, get_ods_meta());
93 $files[] = "$dir/meta.xml";
95 $handle = fopen("$dir/styles.xml", 'w');
96 fwrite($handle, get_ods_styles());
97 $files[] = "$dir/styles.xml";
99 $handle = fopen("$dir/META-INF/manifest.xml", 'w');
100 fwrite($handle, get_ods_manifest());
101 $files[] = "$dir/META-INF";
103 $filename = "$dir/result.ods";
104 zip_files($files, $filename);
106 $handle = fopen($filename, 'rb');
107 $contents = fread($handle, filesize($filename));
108 fclose($handle);
110 remove_dir($dir); // cleanup the temp directory
112 send_file($contents, $this->filename, 0, 0, true, true, 'application/vnd.oasis.opendocument.spreadsheet');
115 /* Not required to use
116 * @param string $name Name of the downloaded file
118 function send($filename) {
119 $this->filename = $filename;
126 * @package moodlecore
127 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
128 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
130 class MoodleODSWorksheet {
131 var $data = array();
132 var $columns = array();
133 var $rows = array();
134 var $name;
137 /* Constructs one Moodle Worksheet.
138 * @param string $filename The name of the file
140 function MoodleODSWorksheet($name) {
141 $this->name = $name;
144 /* Write one string somewhere in the worksheet
145 * @param integer $row Zero indexed row
146 * @param integer $col Zero indexed column
147 * @param string $str The string to write
148 * @param mixed $format The XF format for the cell
150 function write_string($row, $col, $str, $format=0) {
151 if (!array_key_exists($row, $this->data)) {
152 $this->data[$row] = array();
154 $this->data[$row][$col] = new stdClass();
155 $this->data[$row][$col]->value = $str;
156 $this->data[$row][$col]->type = 'string';
157 $this->data[$row][$col]->format = $format;
160 /* Write one number somewhere in the worksheet
161 * @param integer $row Zero indexed row
162 * @param integer $col Zero indexed column
163 * @param float $num The number to write
164 * @param mixed $format The XF format for the cell
166 function write_number($row, $col, $num, $format=0) {
167 if (!array_key_exists($row, $this->data)) {
168 $this->data[$row] = array();
170 $this->data[$row][$col] = new stdClass();
171 $this->data[$row][$col]->value = $num;
172 $this->data[$row][$col]->type = 'float';
173 $this->data[$row][$col]->format = $format;
176 /* Write one url somewhere in the worksheet
177 * @param integer $row Zero indexed row
178 * @param integer $col Zero indexed column
179 * @param string $url The url to write
180 * @param mixed $format The XF format for the cell
182 function write_url($row, $col, $url, $format=0) {
183 if (!array_key_exists($row, $this->data)) {
184 $this->data[$row] = array();
186 $this->data[$row][$col] = new stdClass();
187 $this->data[$row][$col]->value = $url;
188 $this->data[$row][$col]->type = 'string';
189 $this->data[$row][$col]->format = $format;
192 /* Write one date somewhere in the worksheet
193 * @param integer $row Zero indexed row
194 * @param integer $col Zero indexed column
195 * @param string $url The url to write
196 * @param mixed $format The XF format for the cell
198 function write_date($row, $col, $date, $format=0) {
199 if (!array_key_exists($row, $this->data)) {
200 $this->data[$row] = array();
202 $this->data[$row][$col] = new stdClass();
203 $this->data[$row][$col]->value = $date;
204 $this->data[$row][$col]->type = 'date';
205 $this->data[$row][$col]->format = $format;
209 * Write one formula somewhere in the worksheet
211 * @param integer $row Zero indexed row
212 * @param integer $col Zero indexed column
213 * @param string $formula The formula to write
214 * @param mixed $format The XF format for the cell
216 function write_formula($row, $col, $formula, $format=null) {
217 // not implement
220 /* Write one blanck somewhere in the worksheet
221 * @param integer $row Zero indexed row
222 * @param integer $col Zero indexed column
223 * @param mixed $format The XF format for the cell
225 function write_blank($row, $col, $format=0) {
226 if (array_key_exists($row, $this->data)) {
227 unset($this->data[$row][$col]);
231 /* Write anything somewhere in the worksheet
232 * Type will be automatically detected
233 * @param integer $row Zero indexed row
234 * @param integer $col Zero indexed column
235 * @param mixed $token What we are writing
236 * @param mixed $format The XF format for the cell
238 function write($row, $col, $token, $format=0) {
240 /// Analyse what are we trying to send
241 if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) {
242 /// Match number
243 return $this->write_number($row, $col, $token, $format);
244 } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) {
245 /// Match http or ftp URL
246 return $this->write_url($row, $col, $token, '', $format);
247 } elseif (preg_match("/^mailto:/", $token)) {
248 /// Match mailto:
249 return $this->write_url($row, $col, $token, '', $format);
250 } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) {
251 /// Match internal or external sheet link
252 return $this->write_url($row, $col, $token, '', $format);
253 } elseif (preg_match("/^=/", $token)) {
254 /// Match formula
255 return $this->write_formula($row, $col, $token, $format);
256 } elseif (preg_match("/^@/", $token)) {
257 /// Match formula
258 return $this->write_formula($row, $col, $token, $format);
259 } elseif ($token == '') {
260 /// Match blank
261 return $this->write_blank($row, $col, $format);
262 } else {
263 /// Default: match string
264 return $this->write_string($row, $col, $token, $format);
268 /* Sets the height (and other settings) of one row
269 * @param integer $row The row to set
270 * @param integer $height Height we are giving to the row (null to set just format withouth setting the height)
271 * @param mixed $format The optional XF format we are giving to the row
272 * @param bool $hidden The optional hidden attribute
273 * @param integer $level The optional outline level (0-7)
275 function set_row($row, $height, $format = 0, $hidden = false, $level = 0) {
276 $this->rows[$row] = new stdClass();
277 $this->rows[$row]->height = $height;
278 //$this->rows[$row]->format = $format; // TODO: fix and enable
279 $this->rows[$row]->hidden = $hidden;
282 /* Sets the width (and other settings) of one column
283 * @param integer $firstcol first column on the range
284 * @param integer $lastcol last column on the range
285 * @param integer $width width to set
286 * @param mixed $format The optional XF format to apply to the columns
287 * @param integer $hidden The optional hidden atribute
288 * @param integer $level The optional outline level (0-7)
290 function set_column($firstcol, $lastcol, $width, $format = 0, $hidden = false, $level = 0) {
291 for($i=$firstcol; $i<=$lastcol; $i++) {
292 $this->columns[$i] = new stdClass();
293 $this->columns[$i]->width = $width;
294 //$this->columns[$i]->format = $format; // TODO: fix and enable
295 $this->columns[$i]->hidden = $hidden;
301 * Set the option to hide gridlines on the printed page.
303 * @access public
305 function hide_gridlines() {
306 // not implement
310 * Set the option to hide gridlines on the worksheet (as seen on the screen).
312 * @access public
314 function hide_screen_gridlines() {
315 // not implement
319 * Insert a 24bit bitmap image in a worksheet.
321 * @access public
322 * @param integer $row The row we are going to insert the bitmap into
323 * @param integer $col The column we are going to insert the bitmap into
324 * @param string $bitmap The bitmap filename
325 * @param integer $x The horizontal position (offset) of the image inside the cell.
326 * @param integer $y The vertical position (offset) of the image inside the cell.
327 * @param integer $scale_x The horizontal scale
328 * @param integer $scale_y The vertical scale
330 function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) {
331 // not implement
334 * Merges the area given by its arguments.
335 * merging than the normal setAlign('merge').
337 * @access public
338 * @param integer $first_row First row of the area to merge
339 * @param integer $first_col First column of the area to merge
340 * @param integer $last_row Last row of the area to merge
341 * @param integer $last_col Last column of the area to merge
343 function merge_cells($first_row, $first_col, $last_row, $last_col) {
344 // not implement
348 * Define and operate over one Format.
350 * @package moodlecore
351 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
352 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
354 class MoodleODSFormat {
355 var $id;
356 var $properties;
358 /* Constructs one Moodle Format.
359 * @param object $workbook The internal PEAR Workbook onject we are creating
361 function MoodleODSFormat($properties = array()) {
362 static $fid = 1;
364 $this->id = $fid++;
366 foreach($properties as $property => $value) {
367 if(method_exists($this,"set_$property")) {
368 $aux = 'set_'.$property;
369 $this->$aux($value);
374 /* Set weight of the format
375 * @param integer $weight Weight for the text, 0 maps to 400 (normal text),
376 * 1 maps to 700 (bold text). Valid range is: 100-1000.
377 * It's Optional, default is 1 (bold).
379 function set_bold($weight = 1) {
380 $this->properties['bold'] = $weight;
383 /* Set underline of the format
384 * @param integer $underline The value for underline. Possible values are:
385 * 1 => underline, 2 => double underline
387 function set_underline($underline = 1) {
388 $this->properties['underline'] = $underline;
391 /* Set italic of the format
393 function set_italic() {
394 $this->properties['italic'] = true;
397 /* Set strikeout of the format
399 function set_strikeout() {
400 $this->properties['strikeout'] = true;
403 /* Set outlining of the format
405 function set_outline() {
408 /* Set shadow of the format
410 function set_shadow() {
413 /* Set the script of the text
414 * @param integer $script The value for script type. Possible values are:
415 * 1 => superscript, 2 => subscript
417 function set_script($script) {
420 /* Set color of the format
421 * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
423 function set_color($color) {
424 $this->properties['color'] = $this->_get_color($color);
427 /* Set foreground color of the format
428 * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
430 function set_fg_color($color) {
433 /* Set background color of the format
434 * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63])
436 function set_bg_color($color) {
437 $this->properties['bg_color'] = $this->_get_color($color);
440 /* Set the fill pattern of the format
441 * @param integer Optional. Defaults to 1. Meaningful values are: 0-18
442 * 0 meaning no background.
444 function set_pattern($pattern=1) {
447 /* Set text wrap of the format
449 function set_text_wrap() {
452 /* Set the cell alignment of the format
453 * @param string $location alignment for the cell ('left', 'right', etc...)
455 function set_align($location) {
456 switch ($location) {
457 case 'start':
458 case 'left':
459 $this->properties['align'] = 'start';
460 break;
461 case 'center':
462 $this->properties['align'] = 'center';
463 break;
464 case 'end':
465 case 'right':
466 $this->properties['align'] = 'end';
467 break;
468 default:
469 //ignore the rest == start
473 /* Set the cell horizontal alignment of the format
474 * @param string $location alignment for the cell ('left', 'right', etc...)
476 function set_h_align($location) {
477 $this->set_align($location);
480 /* Set the cell vertical alignment of the format
481 * @param string $location alignment for the cell ('top', 'vleft', etc...)
483 function set_v_align($location) {
484 switch ($location) {
485 case 'top':
486 $this->properties['v_align'] = 'top';
487 break;
488 case 'bottom':
489 $this->properties['v_align'] = 'bottom';
490 break;
491 default:
492 //ignore the rest == middle
496 /* Set the top border of the format
497 * @param integer $style style for the cell. 1 => thin, 2 => thick
499 function set_top($style) {
502 /* Set the bottom border of the format
503 * @param integer $style style for the cell. 1 => thin, 2 => thick
505 function set_bottom($style) {
508 /* Set the left border of the format
509 * @param integer $style style for the cell. 1 => thin, 2 => thick
511 function set_left($style) {
514 /* Set the right border of the format
515 * @param integer $style style for the cell. 1 => thin, 2 => thick
517 function set_right($style) {
521 * Set cells borders to the same style
522 * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick.
524 function set_border($style) {
527 /* Set the numerical format of the format
528 * It can be date, time, currency, etc...
529 /* Set the numerical format of the format
530 * It can be date, time, currency, etc...
531 * @param integer $num_format The numeric format
533 function set_num_format($num_format) {
536 function _get_color($name_color = '') {
537 if (strpos($name_color, '#') === 0) {
538 return $name_color; // no conversion needed
541 $colors = array('aqua' => '#00FFFF',
542 'cyan' => '#00FFFF',
543 'black' => '#FFFFFF',
544 'blue' => '#0000FF',
545 'brown' => '#A52A2A',
546 'magenta' => '#FF00FF',
547 'fuchsia' => '#FF00FF',
548 'gray' => '#A0A0A0',
549 'grey' => '#A0A0A0',
550 'green' => '#00FF00',
551 'lime' => '#00FF00',
552 'navy' => '#000080',
553 'orange' => '#FF8000',
554 'purple' => '#800080',
555 'red' => '#FF0000',
556 'silver' => '#DCDCDC',
557 'white' => '#FFFFFF',
558 'yellow' => '#FFFF00');
560 if(array_key_exists($name_color, $colors)) {
561 return $colors[$name_color];
562 } else {
563 return false;
569 //=============================
570 // OpenDocument XML functions
571 //=============================
572 function get_ods_content(&$worksheets) {
575 // find out the size of worksheets and used styles
576 $formats = array();
577 $formatstyles = '';
578 $rowstyles = '';
579 $colstyles = '';
581 foreach($worksheets as $wsnum=>$ws) {
582 $worksheets[$wsnum]->maxr = 0;
583 $worksheets[$wsnum]->maxc = 0;
584 foreach($ws->data as $rnum=>$row) {
585 if ($rnum > $worksheets[$wsnum]->maxr) {
586 $worksheets[$wsnum]->maxr = $rnum;
588 foreach($row as $cnum=>$cell) {
589 if ($cnum > $worksheets[$wsnum]->maxc) {
590 $worksheets[$wsnum]->maxc = $cnum;
592 if (!empty($cell->format)) {
593 if (!array_key_exists($cell->format->id, $formats)) {
594 $formats[$cell->format->id] = $cell->format;
600 foreach($ws->rows as $rnum=>$row) {
601 if (!empty($row->format)) {
602 if (!array_key_exists($row->format->id, $formats)) {
603 $formats[$row->format->id] = $row->format;
606 if ($rnum > $worksheets[$wsnum]->maxr) {
607 $worksheets[$wsnum]->maxr = $rnum;
609 //define all column styles
610 if (!empty($ws->rows[$rnum])) {
611 $rowstyles .= '
612 <style:style style:name="ws'.$wsnum.'ro'.$rnum.'" style:family="table-row">
613 <style:table-row-properties style:row-height="'.$row->height.'pt"/>
614 </style:style>';
618 foreach($ws->columns as $cnum=>$col) {
619 if (!empty($col->format)) {
620 if (!array_key_exists($col->format->id, $formats)) {
621 $formats[$col->format->id] = $col->format;
624 if ($cnum > $worksheets[$wsnum]->maxc) {
625 $worksheets[$wsnum]->maxc = $cnum;
627 //define all column styles
628 if (!empty($ws->columns[$cnum])) {
629 $colstyles .= '
630 <style:style style:name="ws'.$wsnum.'co'.$cnum.'" style:family="table-column">
631 <style:table-column-properties style:column-width="'.$col->width.'pt"/>
632 </style:style>';
637 foreach($formats as $format) {
638 $textprop = '';
639 $cellprop = '';
640 $parprop = '';
641 foreach($format->properties as $pname=>$pvalue) {
642 switch ($pname) {
643 case 'bold':
644 if (!empty($pvalue)) {
645 $textprop .= ' fo:font-weight="bold"';
647 break;
648 case 'italic':
649 if (!empty($pvalue)) {
650 $textprop .= ' fo:font-style="italic"';
652 break;
653 case 'underline':
654 if (!empty($pvalue)) {
655 $textprop .= ' style:text-underline-color="font-color" style:text-underline-style="solid" style:text-underline-width="auto"';
657 break;
658 case 'strikeout':
659 if (!empty($pvalue)) {
660 $textprop .= ' style:text-line-through-style="solid"';
662 break;
663 case 'color':
664 if ($pvalue !== false) {
665 $textprop .= ' fo:color="'.$pvalue.'"';
667 break;
668 case 'bg_color':
669 if ($pvalue !== false) {
670 $cellprop .= ' fo:background-color="'.$pvalue.'"';
672 break;
673 case 'align':
674 $parprop .= ' fo:text-align="'.$pvalue.'"';
675 break;
676 case 'v_align':
677 $cellprop .= ' style:vertical-align="'.$pvalue.'"';
678 break;
681 if (!empty($textprop)) {
682 $textprop = '
683 <style:text-properties'.$textprop.'/>';
686 if (!empty($cellprop)) {
687 $cellprop = '
688 <style:table-cell-properties'.$cellprop.'/>';
691 if (!empty($parprop)) {
692 $parprop = '
693 <style:paragraph-properties'.$parprop.'/>';
696 $formatstyles .= '
697 <style:style style:name="format'.$format->id.'" style:family="table-cell">'.$textprop.$cellprop.$parprop.'
698 </style:style>';
701 /// header
702 $buffer =
703 '<?xml version="1.0" encoding="UTF-8"?>
704 <office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
705 <office:automatic-styles>
706 <style:style style:name="ta1" style:family="table" style:master-page-name="Standard1">
707 <style:table-properties table:display="true"/>
708 </style:style>
709 <style:style style:name="date0" style:family="table-cell"/>';
711 $buffer .= $formatstyles;
712 $buffer .= $rowstyles;
713 $buffer .= $colstyles;
715 $buffer .= '
716 </office:automatic-styles>
717 <office:body>
718 <office:spreadsheet>
721 foreach($worksheets as $wsnum=>$ws) {
723 /// worksheet header
724 $buffer .= '<table:table table:name="' . htmlspecialchars($ws->name) . '" table:style-name="ta1">'."\n";
726 // define column properties
727 for($c=0; $c<=$ws->maxc; $c++) {
728 if (array_key_exists($c, $ws->columns)) {
729 $extra = '';
730 if (!empty($ws->columns[$c]->format)) {
731 $extra .= ' table:default-cell-style-name="format'.$ws->columns[$c]->format->id.'"';
733 if ($ws->columns[$c]->hidden) {
734 $extra .= ' table:visibility="collapse"';
736 $buffer .= '<table:table-column table:style-name="ws'.$wsnum.'co'.$c.'"'.$extra.'/>'."\n";
737 } else {
738 $buffer .= '<table:table-column/>'."\n";
742 // print all rows
743 for($r=0; $r<=$ws->maxr; $r++) {
744 if (array_key_exists($r, $ws->rows)) {
745 $extra = '';
746 if (!empty($ws->rows[$r]->format)) {
747 $extra .= ' table:default-cell-style-name="format'.$ws->rows[$r]->format->id.'"';
749 if ($ws->rows[$r]->hidden) {
750 $extra .= ' table:visibility="collapse"';
752 $buffer .= '<table:table-row table:style-name="ws'.$wsnum.'ro'.$r.'"'.$extra.'>'."\n";
753 } else {
754 $buffer .= '<table:table-row>'."\n";
756 for($c=0; $c<=$ws->maxc; $c++) {
757 if (isset($ws->data[$r][$c])) {
758 $cell = $ws->data[$r][$c];
759 $extra = ' ';
760 if (!empty($cell->format)) {
761 $extra = ' table:style-name="format'.$cell->format->id.'"';
763 if ($cell->type == 'date') {
764 $buffer .= '<table:table-cell office:value-type="date" table:style-name="date0" office:date-value="' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . '"'.$extra.'>'
765 . '<text:p>' . strftime('%Y-%m-%dT%H:%M:%S', $cell->value) . '</text:p>'
766 . '</table:table-cell>'."\n";
767 } else if ($cell->type == 'float') {
768 $buffer .= '<table:table-cell office:value-type="float" office:value="' . htmlspecialchars($cell->value) . '"'.$extra.'>'
769 . '<text:p>' . htmlspecialchars($cell->value) . '</text:p>'
770 . '</table:table-cell>'."\n";
771 } else if ($cell->type == 'string') {
772 $buffer .= '<table:table-cell office:value-type="string" office:string-value="' . htmlspecialchars($cell->value) . '"'.$extra.'>'
773 . '<text:p>' . htmlspecialchars($cell->value) . '</text:p>'
774 . '</table:table-cell>'."\n";
775 } else {
776 $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>'
777 . '<text:p>!!Error - unknown type!!</text:p>'
778 . '</table:table-cell>'."\n";
780 } else {
781 $buffer .= '<table:table-cell/>'."\n";
784 $buffer .= '</table:table-row>'."\n";
786 /// worksheet footer
787 $buffer .= '</table:table>'."\n";
791 /// footer
792 $buffer .=
793 ' </office:spreadsheet>
794 </office:body>
795 </office:document-content>';
797 return $buffer;
800 function get_ods_mimetype() {
801 return 'application/vnd.oasis.opendocument.spreadsheet';
804 function get_ods_meta() {
805 global $CFG, $USER;
807 return
808 '<?xml version="1.0" encoding="UTF-8"?>
809 <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
810 <office:meta>
811 <meta:generator>Moodle '.$CFG->version.'</meta:generator>
812 <meta:initial-creator>'.fullname($USER, true).'</meta:initial-creator>
813 <meta:editing-cycles>1</meta:editing-cycles>
814 <meta:creation-date>'.strftime('%Y-%m-%dT%H:%M:%S').'</meta:creation-date>
815 <dc:date>'.strftime('%Y-%m-%dT%H:%M:%S').'</dc:date>
816 <dc:creator>'.fullname($USER, true).'</dc:creator>
817 </office:meta>
818 </office:document-meta>';
821 function get_ods_styles() {
822 return
823 '<?xml version="1.0" encoding="UTF-8"?>
824 <office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink">
825 <office:styles>
826 <style:default-style style:family="table-column">
827 <style:table-column-properties style:column-width="75pt"/>
828 </style:default-style>
829 <style:default-style style:family="table-row">
830 <style:table-row-properties style:row-height="15pt"/>
831 </style:default-style>
832 <style:default-style style:family="table-cell">
833 <style:table-cell-properties fo:background-color="#ffffff" style:cell-protect="protected" style:vertical-align="middle"/>
834 <style:text-properties fo:color="#000000" fo:font-family="Arial" fo:font-size="12pt"/>
835 </style:default-style>
836 </office:styles>
837 <office:automatic-styles>
838 <style:page-layout style:name="pm1">
839 <style:page-layout-properties fo:margin-bottom="56.6930116pt" fo:margin-left="56.6930116pt" fo:margin-right="56.6930116pt" fo:margin-top="56.6930116pt" fo:page-height="841.89122226pt" fo:page-width="595.2766218pt" style:print="objects charts drawings zero-values" style:print-orientation="portrait"/>
840 </style:page-layout>
841 </office:automatic-styles>
842 <office:master-styles>
843 <style:master-page style:name="Standard1" style:page-layout-name="pm1">
844 <style:header>
845 <text:p>
846 <text:sheet-name>???</text:sheet-name>
847 </text:p>
848 </style:header><style:footer>
849 <text:p>
850 <text:sheet-name>Page </text:sheet-name>
851 <text:page-number>1</text:page-number>
852 </text:p>
853 </style:footer>
854 </style:master-page>
855 </office:master-styles>
856 </office:document-styles>
860 function get_ods_manifest() {
861 return
862 '<?xml version="1.0" encoding="UTF-8"?>
863 <manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0">
864 <manifest:file-entry manifest:media-type="application/vnd.oasis.opendocument.spreadsheet" manifest:full-path="/"/>
865 <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
866 <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>
867 <manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/>
868 </manifest:manifest>';