See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401] [Versions 401 and 402] [Versions 401 and 403]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 /** 18 * ODS file writer. 19 * The xml used here is derived from output of LibreOffice 3.6.4 20 * 21 * The design is based on Excel writer abstraction by Eloy Lafuente and others. 22 * 23 * @package core 24 * @copyright 2006 Petr Skoda {@link http://skodak.org} 25 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 26 */ 27 28 defined('MOODLE_INTERNAL') || die(); 29 30 31 /** 32 * ODS workbook abstraction. 33 * 34 * @package core 35 * @copyright 2006 Petr Skoda {@link http://skodak.org} 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class MoodleODSWorkbook { 39 protected $worksheets = array(); 40 protected $filename; 41 42 public function __construct($filename) { 43 $this->filename = $filename; 44 } 45 46 /** 47 * Create one Moodle Worksheet. 48 * 49 * @param string $name Name of the sheet 50 * @return MoodleODSWorksheet 51 */ 52 public function add_worksheet($name = '') { 53 $ws = new MoodleODSWorksheet($name, $this->worksheets); 54 $this->worksheets[] = $ws; 55 return $ws; 56 } 57 58 /** 59 * Create one Moodle Format. 60 * 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! 65 * @return MoodleODSFormat 66 */ 67 public function add_format($properties = array()) { 68 return new MoodleODSFormat($properties); 69 } 70 71 /** 72 * Close the Moodle Workbook. 73 */ 74 public function close() { 75 global $CFG; 76 require_once($CFG->libdir . '/filelib.php'); 77 78 $writer = new MoodleODSWriter($this->worksheets); 79 $contents = $writer->get_file_content(); 80 81 send_file($contents, $this->filename, 0, 0, true, true, $writer->get_ods_mimetype()); 82 } 83 84 /** 85 * Not required to use. 86 * @param string $filename Name of the downloaded file 87 */ 88 public function send($filename) { 89 $this->filename = $filename; 90 } 91 92 } 93 94 95 /** 96 * ODS Cell abstraction. 97 * 98 * @package core 99 * @copyright 2013 Petr Skoda {@link http://skodak.org} 100 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 101 */ 102 class MoodleODSCell { 103 public $value; 104 public $type; 105 public $format; 106 public $formula; 107 } 108 109 110 /** 111 * ODS Worksheet abstraction. 112 * 113 * @package core 114 * @copyright 2006 Petr Skoda {@link http://skodak.org} 115 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 116 */ 117 class MoodleODSWorksheet { 118 public $data = array(); 119 public $columns = array(); 120 public $rows = array(); 121 public $showgrid = true; 122 public $name; 123 124 /** 125 * Constructs one Moodle Worksheet. 126 * 127 * @param string $name The name of the file 128 * @param array $worksheets existing worksheets 129 */ 130 public function __construct($name, array $worksheets) { 131 // Replace any characters in the name that Excel cannot cope with. 132 $name = strtr($name, '[]*/\?:', ' '); 133 134 if ($name === '') { 135 // Name is required! 136 $name = 'Sheet'.(count($worksheets)+1); 137 } 138 139 $this->name = $name; 140 } 141 142 /** 143 * Write one string somewhere in the worksheet. 144 * 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 149 */ 150 public function write_string($row, $col, $str, $format = null) { 151 if (!isset($this->data[$row][$col])) { 152 $this->data[$row][$col] = new MoodleODSCell(); 153 } 154 if (is_array($format)) { 155 $format = new MoodleODSFormat($format); 156 } 157 $this->data[$row][$col]->value = $str; 158 $this->data[$row][$col]->type = 'string'; 159 $this->data[$row][$col]->format = $format; 160 $this->data[$row][$col]->formula = null; 161 } 162 163 /** 164 * Write one number somewhere in the worksheet. 165 * 166 * @param integer $row Zero indexed row 167 * @param integer $col Zero indexed column 168 * @param float $num The number to write 169 * @param mixed $format The XF format for the cell 170 */ 171 public function write_number($row, $col, $num, $format = null) { 172 if (!isset($this->data[$row][$col])) { 173 $this->data[$row][$col] = new MoodleODSCell(); 174 } 175 if (is_array($format)) { 176 $format = new MoodleODSFormat($format); 177 } 178 $this->data[$row][$col]->value = $num; 179 $this->data[$row][$col]->type = 'float'; 180 $this->data[$row][$col]->format = $format; 181 $this->data[$row][$col]->formula = null; 182 } 183 184 /** 185 * Write one url somewhere in the worksheet. 186 * 187 * @param integer $row Zero indexed row 188 * @param integer $col Zero indexed column 189 * @param string $url The url to write 190 * @param mixed $format The XF format for the cell 191 */ 192 public function write_url($row, $col, $url, $format = null) { 193 if (!isset($this->data[$row][$col])) { 194 $this->data[$row][$col] = new MoodleODSCell(); 195 } 196 if (is_array($format)) { 197 $format = new MoodleODSFormat($format); 198 } 199 $this->data[$row][$col]->value = $url; 200 $this->data[$row][$col]->type = 'string'; 201 $this->data[$row][$col]->format = $format; 202 $this->data[$row][$col]->formula = null; 203 } 204 205 /** 206 * Write one date somewhere in the worksheet. 207 * 208 * @param integer $row Zero indexed row 209 * @param integer $col Zero indexed column 210 * @param string $date The url to write 211 * @param mixed $format The XF format for the cell 212 */ 213 public function write_date($row, $col, $date, $format = null) { 214 if (!isset($this->data[$row][$col])) { 215 $this->data[$row][$col] = new MoodleODSCell(); 216 } 217 if (is_array($format)) { 218 $format = new MoodleODSFormat($format); 219 } 220 $this->data[$row][$col]->value = $date; 221 $this->data[$row][$col]->type = 'date'; 222 $this->data[$row][$col]->format = $format; 223 $this->data[$row][$col]->formula = null; 224 } 225 226 /** 227 * Write one formula somewhere in the worksheet. 228 * 229 * @param integer $row Zero indexed row 230 * @param integer $col Zero indexed column 231 * @param string $formula The formula to write 232 * @param mixed $format The XF format for the cell 233 */ 234 public function write_formula($row, $col, $formula, $format = null) { 235 if (!isset($this->data[$row][$col])) { 236 $this->data[$row][$col] = new MoodleODSCell(); 237 } 238 if (is_array($format)) { 239 $format = new MoodleODSFormat($format); 240 } 241 $this->data[$row][$col]->formula = $formula; 242 $this->data[$row][$col]->format = $format; 243 $this->data[$row][$col]->value = null; 244 $this->data[$row][$col]->format = null; 245 } 246 247 /** 248 * Write one blank somewhere in the worksheet. 249 * 250 * @param integer $row Zero indexed row 251 * @param integer $col Zero indexed column 252 * @param mixed $format The XF format for the cell 253 */ 254 public function write_blank($row, $col, $format = null) { 255 if (is_array($format)) { 256 $format = new MoodleODSFormat($format); 257 } 258 $this->write_string($row, $col, '', $format); 259 } 260 261 /** 262 * Write anything somewhere in the worksheet, 263 * type will be automatically detected. 264 * 265 * @param integer $row Zero indexed row 266 * @param integer $col Zero indexed column 267 * @param mixed $token What we are writing 268 * @param mixed $format The XF format for the cell 269 */ 270 public function write($row, $col, $token, $format = null) { 271 // Analyse what are we trying to send. 272 if (preg_match("/^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/", $token)) { 273 // Match number 274 return $this->write_number($row, $col, $token, $format); 275 } elseif (preg_match("/^[fh]tt?p:\/\//", $token)) { 276 // Match http or ftp URL 277 return $this->write_url($row, $col, $token, '', $format); 278 } elseif (preg_match("/^mailto:/", $token)) { 279 // Match mailto: 280 return $this->write_url($row, $col, $token, '', $format); 281 } elseif (preg_match("/^(?:in|ex)ternal:/", $token)) { 282 // Match internal or external sheet link 283 return $this->write_url($row, $col, $token, '', $format); 284 } elseif (preg_match("/^=/", $token)) { 285 // Match formula 286 return $this->write_formula($row, $col, $token, $format); 287 } elseif (preg_match("/^@/", $token)) { 288 // Match formula 289 return $this->write_formula($row, $col, $token, $format); 290 } elseif ($token == '') { 291 // Match blank 292 return $this->write_blank($row, $col, $format); 293 } else { 294 // Default: match string 295 return $this->write_string($row, $col, $token, $format); 296 } 297 } 298 299 /** 300 * Sets the height (and other settings) of one row. 301 * 302 * @param integer $row The row to set 303 * @param integer $height Height we are giving to the row (null to set just format without setting the height) 304 * @param mixed $format The optional format we are giving to the row 305 * @param bool $hidden The optional hidden attribute 306 * @param integer $level The optional outline level (0-7) 307 */ 308 public function set_row($row, $height, $format = null, $hidden = false, $level = 0) { 309 if (is_array($format)) { 310 $format = new MoodleODSFormat($format); 311 } 312 if ($level < 0) { 313 $level = 0; 314 } else if ($level > 7) { 315 $level = 7; 316 } 317 if (!isset($this->rows[$row])) { 318 $this->rows[$row] = new stdClass(); 319 } 320 if (isset($height)) { 321 $this->rows[$row]->height = $height; 322 } 323 $this->rows[$row]->format = $format; 324 $this->rows[$row]->hidden = $hidden; 325 $this->rows[$row]->level = $level; 326 } 327 328 /** 329 * Sets the width (and other settings) of one column. 330 * 331 * @param integer $firstcol first column on the range 332 * @param integer $lastcol last column on the range 333 * @param integer $width width to set (null to set just format without setting the width) 334 * @param mixed $format The optional format to apply to the columns 335 * @param bool $hidden The optional hidden attribute 336 * @param integer $level The optional outline level (0-7) 337 */ 338 public function set_column($firstcol, $lastcol, $width, $format = null, $hidden = false, $level = 0) { 339 if (is_array($format)) { 340 $format = new MoodleODSFormat($format); 341 } 342 if ($level < 0) { 343 $level = 0; 344 } else if ($level > 7) { 345 $level = 7; 346 } 347 for($i=$firstcol; $i<=$lastcol; $i++) { 348 if (!isset($this->columns[$i])) { 349 $this->columns[$i] = new stdClass(); 350 } 351 if (isset($width)) { 352 $this->columns[$i]->width = $width*6.15; // 6.15 is a magic constant here! 353 } 354 $this->columns[$i]->format = $format; 355 $this->columns[$i]->hidden = $hidden; 356 $this->columns[$i]->level = $level; 357 } 358 } 359 360 /** 361 * Set the option to hide gridlines on the printed page. 362 */ 363 public function hide_gridlines() { 364 // Not implemented - always off. 365 } 366 367 /** 368 * Set the option to hide gridlines on the worksheet (as seen on the screen). 369 */ 370 public function hide_screen_gridlines() { 371 $this->showgrid = false; 372 } 373 374 /** 375 * Insert a 24bit bitmap image in a worksheet. 376 * 377 * @param integer $row The row we are going to insert the bitmap into 378 * @param integer $col The column we are going to insert the bitmap into 379 * @param string $bitmap The bitmap filename 380 * @param integer $x The horizontal position (offset) of the image inside the cell. 381 * @param integer $y The vertical position (offset) of the image inside the cell. 382 * @param integer $scale_x The horizontal scale 383 * @param integer $scale_y The vertical scale 384 */ 385 public function insert_bitmap($row, $col, $bitmap, $x = 0, $y = 0, $scale_x = 1, $scale_y = 1) { 386 // Not implemented. 387 } 388 389 /** 390 * Merges the area given by its arguments. 391 * 392 * @param integer $first_row First row of the area to merge 393 * @param integer $first_col First column of the area to merge 394 * @param integer $last_row Last row of the area to merge 395 * @param integer $last_col Last column of the area to merge 396 */ 397 public function merge_cells($first_row, $first_col, $last_row, $last_col) { 398 if ($first_row > $last_row or $first_col > $last_col) { 399 return; 400 } 401 402 if (!isset($this->data[$first_row][$first_col])) { 403 $this->data[$first_row][$first_col] = new MoodleODSCell(); 404 } 405 406 $this->data[$first_row][$first_col]->merge = array('rows'=>($last_row-$first_row+1), 'columns'=>($last_col-$first_col+1)); 407 } 408 } 409 410 411 /** 412 * ODS cell format abstraction. 413 * 414 * @package core 415 * @copyright 2006 Petr Skoda {@link http://skodak.org} 416 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 417 */ 418 class MoodleODSFormat { 419 public $id; 420 public $properties = array(); 421 422 /** 423 * Constructs one Moodle Format. 424 * 425 * @param array $properties 426 */ 427 public function __construct($properties = array()) { 428 static $fid = 1; 429 430 $this->id = $fid++; 431 432 foreach($properties as $property => $value) { 433 if (method_exists($this, "set_$property")) { 434 $aux = 'set_'.$property; 435 $this->$aux($value); 436 } 437 } 438 } 439 440 /** 441 * Set the size of the text in the format (in pixels). 442 * By default all texts in generated sheets are 10pt. 443 * 444 * @param integer $size Size of the text (in points) 445 */ 446 public function set_size($size) { 447 $this->properties['size'] = $size; 448 } 449 450 /** 451 * Set weight of the format. 452 * 453 * @param integer $weight Weight for the text, 0 maps to 400 (normal text), 454 * 1 maps to 700 (bold text). Valid range is: 100-1000. 455 * It's Optional, default is 1 (bold). 456 */ 457 public function set_bold($weight = 1) { 458 if ($weight == 1) { 459 $weight = 700; 460 } 461 $this->properties['bold'] = ($weight > 400); 462 } 463 464 /** 465 * Set underline of the format. 466 * 467 * @param integer $underline The value for underline. Possible values are: 468 * 1 => underline, 2 => double underline 469 */ 470 public function set_underline($underline = 1) { 471 if ($underline == 1) { 472 $this->properties['underline'] = 1; 473 } else if ($underline == 2) { 474 $this->properties['underline'] = 2; 475 } else { 476 unset($this->properties['underline']); 477 } 478 } 479 480 /** 481 * Set italic of the format. 482 */ 483 public function set_italic() { 484 $this->properties['italic'] = true; 485 } 486 487 /** 488 * Set strikeout of the format 489 */ 490 public function set_strikeout() { 491 $this->properties['strikeout'] = true; 492 } 493 494 /** 495 * Set outlining of the format. 496 */ 497 public function set_outline() { 498 // Not implemented. 499 } 500 501 /** 502 * Set shadow of the format. 503 */ 504 public function set_shadow() { 505 // Not implemented. 506 } 507 508 /** 509 * Set the script of the text. 510 * 511 * @param integer $script The value for script type. Possible values are: 512 * 1 => superscript, 2 => subscript 513 */ 514 public function set_script($script) { 515 if ($script == 1) { 516 $this->properties['super_script'] = true; 517 unset($this->properties['sub_script']); 518 519 } else if ($script == 2) { 520 $this->properties['sub_script'] = true; 521 unset($this->properties['super_script']); 522 523 } else { 524 unset($this->properties['sub_script']); 525 unset($this->properties['super_script']); 526 } 527 } 528 529 /** 530 * Set color of the format. 531 * 532 * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]) 533 */ 534 public function set_color($color) { 535 $this->properties['color'] = $this->parse_color($color); 536 } 537 538 /** 539 * Not used. 540 * 541 * @param mixed $color 542 */ 543 public function set_fg_color($color) { 544 // Not implemented. 545 } 546 547 /** 548 * Set background color of the cell. 549 * 550 * @param mixed $color either a string (like 'blue'), or an integer (range is [8...63]) 551 */ 552 public function set_bg_color($color) { 553 $this->properties['bg_color'] = $this->parse_color($color); 554 } 555 556 /** 557 * Set the cell fill pattern. 558 * 559 * @deprecated use set_bg_color() instead. 560 * @param integer 561 */ 562 public function set_pattern($pattern=1) { 563 if ($pattern > 0) { 564 if (!isset($this->properties['bg_color'])) { 565 $this->properties['bg_color'] = $this->parse_color('black'); 566 } 567 } else { 568 unset($this->properties['bg_color']); 569 } 570 571 } 572 573 /** 574 * Set text wrap of the format 575 */ 576 public function set_text_wrap() { 577 $this->properties['wrap'] = true; 578 } 579 580 /** 581 * Set the cell alignment of the format. 582 * 583 * @param string $location alignment for the cell ('left', 'right', 'justify', etc...) 584 */ 585 public function set_align($location) { 586 if (in_array($location, array('left', 'centre', 'center', 'right', 'fill', 'merge', 'justify', 'equal_space'))) { 587 $this->set_h_align($location); 588 589 } else if (in_array($location, array('top', 'vcentre', 'vcenter', 'bottom', 'vjustify', 'vequal_space'))) { 590 $this->set_v_align($location); 591 } 592 } 593 594 /** 595 * Set the cell horizontal alignment of the format. 596 * 597 * @param string $location alignment for the cell ('left', 'right', 'justify', etc...) 598 */ 599 public function set_h_align($location) { 600 switch ($location) { 601 case 'left': 602 $this->properties['align'] = 'start'; 603 break; 604 case 'center': 605 case 'centre': 606 $this->properties['align'] = 'center'; 607 break; 608 case 'right': 609 $this->properties['align'] = 'end'; 610 break; 611 } 612 } 613 614 /** 615 * Set the cell vertical alignment of the format. 616 * 617 * @param string $location alignment for the cell ('top', 'bottom', 'center', 'justify') 618 */ 619 public function set_v_align($location) { 620 switch ($location) { 621 case 'top': 622 $this->properties['v_align'] = 'top'; 623 break; 624 case 'vcentre': 625 case 'vcenter': 626 case 'centre': 627 case 'center': 628 $this->properties['v_align'] = 'middle'; 629 break; 630 default: 631 $this->properties['v_align'] = 'bottom'; 632 } 633 } 634 635 /** 636 * Set the top border of the format. 637 * 638 * @param integer $style style for the cell. 1 => thin, 2 => thick 639 */ 640 public function set_top($style) { 641 if ($style == 1) { 642 $style = 0.2; 643 } else if ($style == 2) { 644 $style = 0.5; 645 } else { 646 return; 647 } 648 $this->properties['border_top'] = $style; 649 } 650 651 /** 652 * Set the bottom border of the format. 653 * 654 * @param integer $style style for the cell. 1 => thin, 2 => thick 655 */ 656 public function set_bottom($style) { 657 if ($style == 1) { 658 $style = 0.2; 659 } else if ($style == 2) { 660 $style = 0.5; 661 } else { 662 return; 663 } 664 $this->properties['border_bottom'] = $style; 665 } 666 667 /** 668 * Set the left border of the format. 669 * 670 * @param integer $style style for the cell. 1 => thin, 2 => thick 671 */ 672 public function set_left($style) { 673 if ($style == 1) { 674 $style = 0.2; 675 } else if ($style == 2) { 676 $style = 0.5; 677 } else { 678 return; 679 } 680 $this->properties['border_left'] = $style; 681 } 682 683 /** 684 * Set the right border of the format. 685 * 686 * @param integer $style style for the cell. 1 => thin, 2 => thick 687 */ 688 public function set_right($style) { 689 if ($style == 1) { 690 $style = 0.2; 691 } else if ($style == 2) { 692 $style = 0.5; 693 } else { 694 return; 695 } 696 $this->properties['border_right'] = $style; 697 } 698 699 /** 700 * Set cells borders to the same style 701 * @param integer $style style to apply for all cell borders. 1 => thin, 2 => thick. 702 */ 703 public function set_border($style) { 704 $this->set_top($style); 705 $this->set_bottom($style); 706 $this->set_left($style); 707 $this->set_right($style); 708 } 709 710 /** 711 * Set the numerical format of the format. 712 * It can be date, time, currency, etc... 713 * 714 * @param mixed $num_format The numeric format 715 */ 716 public function set_num_format($num_format) { 717 718 $numbers = array(); 719 720 $numbers[1] = '0'; 721 $numbers[2] = '0.00'; 722 $numbers[3] = '#,##0'; 723 $numbers[4] = '#,##0.00'; 724 $numbers[11] = '0.00E+00'; 725 $numbers[12] = '# ?/?'; 726 $numbers[13] = '# ??/??'; 727 $numbers[14] = 'mm-dd-yy'; 728 $numbers[15] = 'd-mmm-yy'; 729 $numbers[16] = 'd-mmm'; 730 $numbers[17] = 'mmm-yy'; 731 $numbers[22] = 'm/d/yy h:mm'; 732 $numbers[49] = '@'; 733 734 if ($num_format !== 0 and in_array($num_format, $numbers)) { 735 $flipped = array_flip($numbers); 736 $this->properties['num_format'] = $flipped[$num_format]; 737 } 738 if (!isset($numbers[$num_format])) { 739 return; 740 } 741 742 $this->properties['num_format'] = $num_format; 743 } 744 745 /** 746 * Standardise colour name. 747 * 748 * @param mixed $color name of the color (i.e.: 'blue', 'red', etc..), or an integer (range is [8...63]). 749 * @return string the RGB color value 750 */ 751 protected function parse_color($color) { 752 if (strpos($color, '#') === 0) { 753 // No conversion should be needed. 754 return $color; 755 } 756 757 if ($color > 7 and $color < 53) { 758 $numbers = array( 759 8 => 'black', 760 12 => 'blue', 761 16 => 'brown', 762 15 => 'cyan', 763 23 => 'gray', 764 17 => 'green', 765 11 => 'lime', 766 14 => 'magenta', 767 18 => 'navy', 768 53 => 'orange', 769 33 => 'pink', 770 20 => 'purple', 771 10 => 'red', 772 22 => 'silver', 773 9 => 'white', 774 13 => 'yellow', 775 ); 776 if (isset($numbers[$color])) { 777 $color = $numbers[$color]; 778 } else { 779 $color = 'black'; 780 } 781 } 782 783 $colors = array( 784 'aqua' => '00FFFF', 785 'black' => '000000', 786 'blue' => '0000FF', 787 'brown' => 'A52A2A', 788 'cyan' => '00FFFF', 789 'fuchsia' => 'FF00FF', 790 'gray' => '808080', 791 'grey' => '808080', 792 'green' => '00FF00', 793 'lime' => '00FF00', 794 'magenta' => 'FF00FF', 795 'maroon' => '800000', 796 'navy' => '000080', 797 'orange' => 'FFA500', 798 'olive' => '808000', 799 'pink' => 'FAAFBE', 800 'purple' => '800080', 801 'red' => 'FF0000', 802 'silver' => 'C0C0C0', 803 'teal' => '008080', 804 'white' => 'FFFFFF', 805 'yellow' => 'FFFF00', 806 ); 807 808 if (isset($colors[$color])) { 809 return('#'.$colors[$color]); 810 } 811 812 return('#'.$colors['black']); 813 } 814 } 815 816 817 /** 818 * ODS file writer. 819 * 820 * @package core 821 * @copyright 2013 Petr Skoda {@link http://skodak.org} 822 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 823 */ 824 class MoodleODSWriter { 825 protected $worksheets; 826 827 public function __construct(array $worksheets) { 828 $this->worksheets = $worksheets; 829 } 830 831 /** 832 * Fetch the file ocntnet for the ODS. 833 * 834 * @return string 835 */ 836 public function get_file_content() { 837 $dir = make_request_directory(); 838 $filename = $dir . '/result.ods'; 839 840 $files = [ 841 'mimetype' => [$this->get_ods_mimetype()], 842 'content.xml' => [$this->get_ods_content($this->worksheets)], 843 'meta.xml' => [$this->get_ods_meta()], 844 'styles.xml' => [$this->get_ods_styles()], 845 'settings.xml' => [$this->get_ods_settings()], 846 'META-INF/manifest.xml' => [$this->get_ods_manifest()], 847 ]; 848 849 $packer = get_file_packer('application/zip'); 850 $packer->archive_to_pathname($files, $filename); 851 852 $contents = file_get_contents($filename); 853 854 remove_dir($dir); 855 return $contents; 856 } 857 858 protected function get_ods_content() { 859 860 // Find out the size of worksheets and used styles. 861 $formats = array(); 862 $formatstyles = ''; 863 $rowstyles = ''; 864 $colstyles = ''; 865 866 foreach($this->worksheets as $wsnum=>$ws) { 867 $this->worksheets[$wsnum]->maxr = 0; 868 $this->worksheets[$wsnum]->maxc = 0; 869 foreach($ws->data as $rnum=>$row) { 870 if ($rnum > $this->worksheets[$wsnum]->maxr) { 871 $this->worksheets[$wsnum]->maxr = $rnum; 872 } 873 foreach($row as $cnum=>$cell) { 874 if ($cnum > $this->worksheets[$wsnum]->maxc) { 875 $this->worksheets[$wsnum]->maxc = $cnum; 876 } 877 if (!empty($cell->format)) { 878 if (!array_key_exists($cell->format->id, $formats)) { 879 $formats[$cell->format->id] = $cell->format; 880 } 881 } 882 } 883 } 884 885 foreach($ws->rows as $rnum=>$row) { 886 if (!empty($row->format)) { 887 if (!array_key_exists($row->format->id, $formats)) { 888 $formats[$row->format->id] = $row->format; 889 } 890 } 891 if ($rnum > $this->worksheets[$wsnum]->maxr) { 892 $this->worksheets[$wsnum]->maxr = $rnum; 893 } 894 // Define all column styles. 895 if (!empty($ws->rows[$rnum])) { 896 $rowstyles .= '<style:style style:name="ws'.$wsnum.'ro'.$rnum.'" style:family="table-row">'; 897 if (isset($row->height)) { 898 $rowstyles .= '<style:table-row-properties style:row-height="'.$row->height.'pt"/>'; 899 } 900 $rowstyles .= '</style:style>'; 901 } 902 } 903 904 foreach($ws->columns as $cnum=>$col) { 905 if (!empty($col->format)) { 906 if (!array_key_exists($col->format->id, $formats)) { 907 $formats[$col->format->id] = $col->format; 908 } 909 } 910 if ($cnum > $this->worksheets[$wsnum]->maxc) { 911 $this->worksheets[$wsnum]->maxc = $cnum; 912 } 913 // Define all column styles. 914 if (!empty($ws->columns[$cnum])) { 915 $colstyles .= '<style:style style:name="ws'.$wsnum.'co'.$cnum.'" style:family="table-column">'; 916 if (isset($col->width)) { 917 $colstyles .= '<style:table-column-properties style:column-width="'.$col->width.'pt"/>'; 918 } 919 $colstyles .= '</style:style>'; 920 } 921 } 922 } 923 924 foreach($formats as $format) { 925 $textprop = ''; 926 $cellprop = ''; 927 $parprop = ''; 928 $dataformat = ''; 929 foreach($format->properties as $pname=>$pvalue) { 930 switch ($pname) { 931 case 'size': 932 if (!empty($pvalue)) { 933 $textprop .= ' fo:font-size="'.$pvalue.'pt"'; 934 } 935 break; 936 case 'bold': 937 if (!empty($pvalue)) { 938 $textprop .= ' fo:font-weight="bold"'; 939 } 940 break; 941 case 'italic': 942 if (!empty($pvalue)) { 943 $textprop .= ' fo:font-style="italic"'; 944 } 945 break; 946 case 'underline': 947 if (!empty($pvalue)) { 948 $textprop .= ' style:text-underline-color="font-color" style:text-underline-style="solid" style:text-underline-width="auto"'; 949 if ($pvalue == 2) { 950 $textprop .= ' style:text-underline-type="double"'; 951 } 952 } 953 break; 954 case 'strikeout': 955 if (!empty($pvalue)) { 956 $textprop .= ' style:text-line-through-style="solid"'; 957 } 958 break; 959 case 'color': 960 if ($pvalue !== false) { 961 $textprop .= ' fo:color="'.$pvalue.'"'; 962 } 963 break; 964 case 'bg_color': 965 if ($pvalue !== false) { 966 $cellprop .= ' fo:background-color="'.$pvalue.'"'; 967 } 968 break; 969 case 'align': 970 $parprop .= ' fo:text-align="'.$pvalue.'"'; 971 break; 972 case 'v_align': 973 $cellprop .= ' style:vertical-align="'.$pvalue.'"'; 974 break; 975 case 'wrap': 976 if ($pvalue) { 977 $cellprop .= ' fo:wrap-option="wrap"'; 978 } 979 break; 980 case 'border_top': 981 $cellprop .= ' fo:border-top="'.$pvalue.'pt solid #000000"'; 982 break; 983 case 'border_left': 984 $cellprop .= ' fo:border-left="'.$pvalue.'pt solid #000000"'; 985 break; 986 case 'border_bottom': 987 $cellprop .= ' fo:border-bottom="'.$pvalue.'pt solid #000000"'; 988 break; 989 case 'border_right': 990 $cellprop .= ' fo:border-right="'.$pvalue.'pt solid #000000"'; 991 break; 992 case 'num_format': 993 $dataformat = ' style:data-style-name="NUM'.$pvalue.'"'; 994 break; 995 } 996 } 997 if (!empty($textprop)) { 998 $textprop = ' 999 <style:text-properties'.$textprop.'/>'; 1000 } 1001 1002 if (!empty($cellprop)) { 1003 $cellprop = ' 1004 <style:table-cell-properties'.$cellprop.'/>'; 1005 } 1006 1007 if (!empty($parprop)) { 1008 $parprop = ' 1009 <style:paragraph-properties'.$parprop.'/>'; 1010 } 1011 1012 $formatstyles .= ' 1013 <style:style style:name="format'.$format->id.'" style:family="table-cell"'.$dataformat.'>'.$textprop.$cellprop.$parprop.' 1014 </style:style>'; 1015 } 1016 1017 // The text styles may be breaking older ODF validators. 1018 $scriptstyles =' 1019 <style:style style:name="T1" style:family="text"> 1020 <style:text-properties style:text-position="33% 58%"/> 1021 </style:style> 1022 <style:style style:name="T2" style:family="text"> 1023 <style:text-properties style:text-position="-33% 58%"/> 1024 </style:style> 1025 '; 1026 // Header. 1027 $buffer = 1028 '<?xml version="1.0" encoding="UTF-8"?> 1029 <office:document-content xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 1030 xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 1031 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 1032 xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 1033 xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 1034 xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 1035 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" 1036 xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 1037 xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 1038 xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 1039 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 1040 xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 1041 xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 1042 xmlns:math="http://www.w3.org/1998/Math/MathML" 1043 xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 1044 xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 1045 xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" 1046 xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" 1047 xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" 1048 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 1049 xmlns:rpt="http://openoffice.org/2005/report" 1050 xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 1051 xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" 1052 xmlns:tableooo="http://openoffice.org/2009/table" 1053 xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 1054 xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" 1055 xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" 1056 xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> 1057 <office:scripts/> 1058 <office:font-face-decls> 1059 <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" 1060 style:font-pitch="variable"/> 1061 <style:font-face style:name="Arial Unicode MS" svg:font-family="'Arial Unicode MS'" 1062 style:font-family-generic="system" style:font-pitch="variable"/> 1063 <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" 1064 style:font-pitch="variable"/> 1065 </office:font-face-decls> 1066 <office:automatic-styles>'; 1067 $buffer .= $this->get_num_styles(); 1068 $buffer .= ' 1069 <style:style style:name="ta1" style:family="table" style:master-page-name="Standard1"> 1070 <style:table-properties table:display="true"/> 1071 </style:style>'; 1072 1073 $buffer .= $formatstyles; 1074 $buffer .= $rowstyles; 1075 $buffer .= $colstyles; 1076 $buffer .= $scriptstyles; 1077 1078 $buffer .= ' 1079 </office:automatic-styles> 1080 <office:body> 1081 <office:spreadsheet> 1082 '; 1083 1084 foreach($this->worksheets as $wsnum=>$ws) { 1085 1086 // Worksheet header. 1087 $buffer .= '<table:table table:name="' . htmlspecialchars($ws->name, ENT_QUOTES, 'utf-8') . '" table:style-name="ta1">'."\n"; 1088 1089 // Define column properties. 1090 $level = 0; 1091 for($c=0; $c<=$ws->maxc; $c++) { 1092 if (array_key_exists($c, $ws->columns)) { 1093 $column = $ws->columns[$c]; 1094 if ($column->level > $level) { 1095 while ($column->level > $level) { 1096 $buffer .= '<table:table-column-group>'; 1097 $level++; 1098 } 1099 } else if ($column->level < $level) { 1100 while ($column->level < $level) { 1101 $buffer .= '</table:table-column-group>'; 1102 $level--; 1103 } 1104 } 1105 $extra = ''; 1106 if (!empty($column->format)) { 1107 $extra .= ' table:default-cell-style-name="format'.$column->format->id.'"'; 1108 } 1109 if ($column->hidden) { 1110 $extra .= ' table:visibility="collapse"'; 1111 } 1112 $buffer .= '<table:table-column table:style-name="ws'.$wsnum.'co'.$c.'"'.$extra.'/>'."\n"; 1113 } else { 1114 while ($level > 0) { 1115 $buffer .= '</table:table-column-group>'; 1116 $level--; 1117 } 1118 $buffer .= '<table:table-column/>'."\n"; 1119 } 1120 } 1121 while ($level > 0) { 1122 $buffer .= '</table:table-column-group>'; 1123 $level--; 1124 } 1125 1126 // Print all rows. 1127 $level = 0; 1128 for($r=0; $r<=$ws->maxr; $r++) { 1129 if (array_key_exists($r, $ws->rows)) { 1130 $row = $ws->rows[$r]; 1131 if ($row->level > $level) { 1132 while ($row->level > $level) { 1133 $buffer .= '<table:table-row-group>'; 1134 $level++; 1135 } 1136 } else if ($row->level < $level) { 1137 while ($row->level < $level) { 1138 $buffer .= '</table:table-row-group>'; 1139 $level--; 1140 } 1141 } 1142 $extra = ''; 1143 if (!empty($row->format)) { 1144 $extra .= ' table:default-cell-style-name="format'.$row->format->id.'"'; 1145 } 1146 if ($row->hidden) { 1147 $extra .= ' table:visibility="collapse"'; 1148 } 1149 $buffer .= '<table:table-row table:style-name="ws'.$wsnum.'ro'.$r.'"'.$extra.'>'."\n"; 1150 } else { 1151 while ($level > 0) { 1152 $buffer .= '</table:table-row-group>'; 1153 $level--; 1154 } 1155 $buffer .= '<table:table-row>'."\n"; 1156 } 1157 for($c=0; $c<=$ws->maxc; $c++) { 1158 if (isset($ws->data[$r][$c])) { 1159 $cell = $ws->data[$r][$c]; 1160 $extra = ''; 1161 if (!empty($cell->format)) { 1162 $extra .= ' table:style-name="format'.$cell->format->id.'"'; 1163 } 1164 if (!empty($cell->merge)) { 1165 $extra .= ' table:number-columns-spanned="'.$cell->merge['columns'].'" table:number-rows-spanned="'.$cell->merge['rows'].'"'; 1166 } 1167 $pretext = '<text:p>'; 1168 $posttext = '</text:p>'; 1169 if (!empty($cell->format->properties['sub_script'])) { 1170 $pretext = $pretext.'<text:span text:style-name="T2">'; 1171 $posttext = '</text:span>'.$posttext; 1172 } else if (!empty($cell->format->properties['super_script'])) { 1173 $pretext = $pretext.'<text:span text:style-name="T1">'; 1174 $posttext = '</text:span>'.$posttext; 1175 } 1176 1177 if (isset($cell->formula)) { 1178 $buffer .= '<table:table-cell table:formula="of:'.$cell->formula.'"'.$extra.'></table:table-cell>'."\n"; 1179 } else if ($cell->type == 'date') { 1180 $buffer .= '<table:table-cell office:value-type="date" office:date-value="' . date("Y-m-d\\TH:i:s", $cell->value) . '"'.$extra.'>' 1181 . $pretext . date("Y-m-d\\TH:i:s", $cell->value) . $posttext 1182 . '</table:table-cell>'."\n"; 1183 } else if ($cell->type == 'float') { 1184 $buffer .= '<table:table-cell office:value-type="float" office:value="' . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . '"'.$extra.'>' 1185 . $pretext . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . $posttext 1186 . '</table:table-cell>'."\n"; 1187 } else if ($cell->type == 'string') { 1188 $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>' 1189 . $pretext . htmlspecialchars($cell->value, ENT_QUOTES, 'utf-8') . $posttext 1190 . '</table:table-cell>'."\n"; 1191 } else { 1192 $buffer .= '<table:table-cell office:value-type="string"'.$extra.'>' 1193 . $pretext . '!!Error - unknown type!!' . $posttext 1194 . '</table:table-cell>'."\n"; 1195 } 1196 } else { 1197 $buffer .= '<table:table-cell/>'."\n"; 1198 } 1199 } 1200 $buffer .= '</table:table-row>'."\n"; 1201 } 1202 while ($level > 0) { 1203 $buffer .= '</table:table-row-group>'; 1204 $level--; 1205 } 1206 $buffer .= '</table:table>'."\n"; 1207 1208 } 1209 1210 // Footer. 1211 $buffer .= ' 1212 </office:spreadsheet> 1213 </office:body> 1214 </office:document-content>'; 1215 1216 return $buffer; 1217 } 1218 1219 public function get_ods_mimetype() { 1220 return 'application/vnd.oasis.opendocument.spreadsheet'; 1221 } 1222 1223 protected function get_ods_settings() { 1224 $buffer = 1225 '<?xml version="1.0" encoding="UTF-8"?> 1226 <office:document-settings xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 1227 xmlns:xlink="http://www.w3.org/1999/xlink" 1228 xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" 1229 xmlns:ooo="http://openoffice.org/2004/office" office:version="1.2"> 1230 <office:settings> 1231 <config:config-item-set config:name="ooo:view-settings"> 1232 <config:config-item config:name="VisibleAreaTop" config:type="int">0</config:config-item> 1233 <config:config-item config:name="VisibleAreaLeft" config:type="int">0</config:config-item> 1234 <config:config-item-map-indexed config:name="Views"> 1235 <config:config-item-map-entry> 1236 <config:config-item config:name="ViewId" config:type="string">view1</config:config-item> 1237 <config:config-item-map-named config:name="Tables"> 1238 '; 1239 foreach ($this->worksheets as $ws) { 1240 $buffer .= ' <config:config-item-map-entry config:name="'.htmlspecialchars($ws->name, ENT_QUOTES, 'utf-8').'">'."\n"; 1241 $buffer .= ' <config:config-item config:name="ShowGrid" config:type="boolean">'.($ws->showgrid ? 'true' : 'false').'</config:config-item>'."\n"; 1242 $buffer .= ' </config:config-item-map-entry>."\n"'; 1243 } 1244 $buffer .= 1245 ' </config:config-item-map-named> 1246 </config:config-item-map-entry> 1247 </config:config-item-map-indexed> 1248 </config:config-item-set> 1249 <config:config-item-set config:name="ooo:configuration-settings"> 1250 <config:config-item config:name="ShowGrid" config:type="boolean">true</config:config-item> 1251 </config:config-item-set> 1252 </office:settings> 1253 </office:document-settings>'; 1254 1255 return $buffer; 1256 } 1257 protected function get_ods_meta() { 1258 global $CFG, $USER; 1259 1260 return 1261 '<?xml version="1.0" encoding="UTF-8"?> 1262 <office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 1263 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" 1264 xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 1265 xmlns:ooo="http://openoffice.org/2004/office" xmlns:grddl="http://www.w3.org/2003/g/data-view#" 1266 office:version="1.2"> 1267 <office:meta> 1268 <meta:generator>Moodle '.$CFG->release.'</meta:generator> 1269 <meta:initial-creator>' . htmlspecialchars(fullname($USER, true), ENT_QUOTES, 'utf-8') . '</meta:initial-creator> 1270 <meta:creation-date>'.date("Y-m-d\\TH:i:s").'</meta:creation-date> 1271 <meta:document-statistic meta:table-count="1" meta:cell-count="0" meta:object-count="0"/> 1272 </office:meta> 1273 </office:document-meta>'; 1274 } 1275 1276 protected function get_ods_styles() { 1277 return 1278 '<?xml version="1.0" encoding="UTF-8"?> 1279 <office:document-styles xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" 1280 xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" 1281 xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" 1282 xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" 1283 xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" 1284 xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" 1285 xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" 1286 xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" 1287 xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" 1288 xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" 1289 xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" 1290 xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" 1291 xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" 1292 xmlns:math="http://www.w3.org/1998/Math/MathML" 1293 xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" 1294 xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" 1295 xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" 1296 xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" 1297 xmlns:rpt="http://openoffice.org/2005/report" 1298 xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" 1299 xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" 1300 xmlns:tableooo="http://openoffice.org/2009/table" 1301 xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" 1302 xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2"> 1303 <office:font-face-decls> 1304 <style:font-face style:name="Arial" svg:font-family="Arial" style:font-family-generic="swiss" 1305 style:font-pitch="variable"/> 1306 <style:font-face style:name="Arial Unicode MS" svg:font-family="'Arial Unicode MS'" 1307 style:font-family-generic="system" style:font-pitch="variable"/> 1308 <style:font-face style:name="Tahoma" svg:font-family="Tahoma" style:font-family-generic="system" 1309 style:font-pitch="variable"/> 1310 </office:font-face-decls> 1311 <office:styles> 1312 <style:default-style style:family="table-cell"> 1313 <style:paragraph-properties style:tab-stop-distance="1.25cm"/> 1314 </style:default-style> 1315 <number:number-style style:name="N0"> 1316 <number:number number:min-integer-digits="1"/> 1317 </number:number-style> 1318 <style:style style:name="Default" style:family="table-cell"> 1319 <style:text-properties style:font-name-asian="Arial Unicode MS" style:font-name-complex="Arial Unicode MS"/> 1320 </style:style> 1321 <style:style style:name="Result" style:family="table-cell" style:parent-style-name="Default"> 1322 <style:text-properties fo:font-style="italic" style:text-underline-style="solid" 1323 style:text-underline-width="auto" style:text-underline-color="font-color" 1324 fo:font-weight="bold"/> 1325 </style:style> 1326 <style:style style:name="Result2" style:family="table-cell" style:parent-style-name="Result" 1327 style:data-style-name="N104"/> 1328 <style:style style:name="Heading" style:family="table-cell" style:parent-style-name="Default"> 1329 <style:table-cell-properties style:text-align-source="fix" style:repeat-content="false"/> 1330 <style:paragraph-properties fo:text-align="center"/> 1331 <style:text-properties fo:font-size="16pt" fo:font-style="italic" fo:font-weight="bold"/> 1332 </style:style> 1333 <style:style style:name="Heading1" style:family="table-cell" style:parent-style-name="Heading"> 1334 <style:table-cell-properties style:rotation-angle="90"/> 1335 </style:style> 1336 </office:styles> 1337 <office:automatic-styles> 1338 <style:page-layout style:name="Mpm1"> 1339 <style:page-layout-properties style:writing-mode="lr-tb"/> 1340 <style:header-style> 1341 <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm" 1342 fo:margin-bottom="0.25cm"/> 1343 </style:header-style> 1344 <style:footer-style> 1345 <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm" 1346 fo:margin-top="0.25cm"/> 1347 </style:footer-style> 1348 </style:page-layout> 1349 <style:page-layout style:name="Mpm2"> 1350 <style:page-layout-properties style:writing-mode="lr-tb"/> 1351 <style:header-style> 1352 <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm" 1353 fo:margin-bottom="0.25cm" fo:border="2.49pt solid #000000" 1354 fo:padding="0.018cm" fo:background-color="#c0c0c0"> 1355 <style:background-image/> 1356 </style:header-footer-properties> 1357 </style:header-style> 1358 <style:footer-style> 1359 <style:header-footer-properties fo:min-height="0.75cm" fo:margin-left="0cm" fo:margin-right="0cm" 1360 fo:margin-top="0.25cm" fo:border="2.49pt solid #000000" 1361 fo:padding="0.018cm" fo:background-color="#c0c0c0"> 1362 <style:background-image/> 1363 </style:header-footer-properties> 1364 </style:footer-style> 1365 </style:page-layout> 1366 </office:automatic-styles> 1367 <office:master-styles> 1368 <style:master-page style:name="Default" style:page-layout-name="Mpm1"> 1369 <style:header> 1370 <text:p> 1371 <text:sheet-name>???</text:sheet-name> 1372 </text:p> 1373 </style:header> 1374 <style:header-left style:display="false"/> 1375 <style:footer> 1376 <text:p>Page 1377 <text:page-number>1</text:page-number> 1378 </text:p> 1379 </style:footer> 1380 <style:footer-left style:display="false"/> 1381 </style:master-page> 1382 <style:master-page style:name="Report" style:page-layout-name="Mpm2"> 1383 <style:header> 1384 <style:region-left> 1385 <text:p> 1386 <text:sheet-name>???</text:sheet-name> 1387 (<text:title>???</text:title>) 1388 </text:p> 1389 </style:region-left> 1390 <style:region-right> 1391 <text:p><text:date style:data-style-name="N2" text:date-value="2013-01-05">00.00.0000</text:date>, 1392 <text:time>00:00:00</text:time> 1393 </text:p> 1394 </style:region-right> 1395 </style:header> 1396 <style:header-left style:display="false"/> 1397 <style:footer> 1398 <text:p>Page 1399 <text:page-number>1</text:page-number> 1400 / 1401 <text:page-count>99</text:page-count> 1402 </text:p> 1403 </style:footer> 1404 <style:footer-left style:display="false"/> 1405 </style:master-page> 1406 </office:master-styles> 1407 </office:document-styles>'; 1408 } 1409 1410 protected function get_ods_manifest() { 1411 return 1412 '<?xml version="1.0" encoding="UTF-8"?> 1413 <manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2"> 1414 <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/> 1415 <manifest:file-entry manifest:full-path="meta.xml" manifest:media-type="text/xml"/> 1416 <manifest:file-entry manifest:full-path="content.xml" manifest:media-type="text/xml"/> 1417 <manifest:file-entry manifest:full-path="styles.xml" manifest:media-type="text/xml"/> 1418 <manifest:file-entry manifest:full-path="settings.xml" manifest:media-type="text/xml"/> 1419 </manifest:manifest>'; 1420 } 1421 1422 protected function get_num_styles() { 1423 return ' 1424 <number:number-style style:name="NUM1"> 1425 <number:number number:decimal-places="0" number:min-integer-digits="1"/> 1426 </number:number-style> 1427 <number:number-style style:name="NUM2"> 1428 <number:number number:decimal-places="2" number:min-integer-digits="1"/> 1429 </number:number-style> 1430 <number:number-style style:name="NUM3"> 1431 <number:number number:decimal-places="0" number:min-integer-digits="1" number:grouping="true"/> 1432 </number:number-style> 1433 <number:number-style style:name="NUM4"> 1434 <number:number number:decimal-places="2" number:min-integer-digits="1" number:grouping="true"/> 1435 </number:number-style> 1436 <number:number-style style:name="NUM11"> 1437 <number:scientific-number number:decimal-places="2" number:min-integer-digits="1" 1438 number:min-exponent-digits="2"/> 1439 </number:number-style> 1440 <number:number-style style:name="NUM12"> 1441 <number:fraction number:min-integer-digits="0" number:min-numerator-digits="1" 1442 number:min-denominator-digits="1"/> 1443 </number:number-style> 1444 <number:number-style style:name="NUM13"> 1445 <number:fraction number:min-integer-digits="0" number:min-numerator-digits="2" 1446 number:min-denominator-digits="2"/> 1447 </number:number-style> 1448 <number:date-style style:name="NUM14" number:automatic-order="true"> 1449 <number:month number:style="long"/> 1450 <number:text>/</number:text> 1451 <number:day number:style="long"/> 1452 <number:text>/</number:text> 1453 <number:year/> 1454 </number:date-style> 1455 <number:date-style style:name="NUM15"> 1456 <number:day/> 1457 <number:text>.</number:text> 1458 <number:month number:textual="true"/> 1459 <number:text>.</number:text> 1460 <number:year number:style="long"/> 1461 </number:date-style> 1462 <number:date-style style:name="NUM16" number:automatic-order="true"> 1463 <number:month number:textual="true"/> 1464 <number:text></number:text> 1465 <number:day number:style="long"/> 1466 </number:date-style> 1467 <number:date-style style:name="NUM17"> 1468 <number:month number:style="long"/> 1469 <number:text>-</number:text> 1470 <number:day number:style="long"/> 1471 </number:date-style> 1472 <number:date-style style:name="NUM22" number:automatic-order="true" 1473 number:format-source="language"> 1474 <number:month/> 1475 <number:text>/</number:text> 1476 <number:day/> 1477 <number:text>/</number:text> 1478 <number:year/> 1479 <number:text></number:text> 1480 <number:hours number:style="long"/> 1481 <number:text>:</number:text> 1482 <number:minutes number:style="long"/> 1483 <number:text></number:text> 1484 <number:am-pm/> 1485 </number:date-style> 1486 <number:text-style style:name="NUM49"> 1487 <number:text-content/> 1488 </number:text-style> 1489 '; 1490 } 1491 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body