1<?php 2 3require_once DOKU_PLUGIN . 'odt/ODT/ODTState.php'; 4require_once DOKU_PLUGIN . 'odt/ODT/ODTUtility.php'; 5require_once DOKU_PLUGIN . 'odt/ODT/ODTList.php'; 6require_once DOKU_PLUGIN . 'odt/ODT/ODTFootnote.php'; 7require_once DOKU_PLUGIN . 'odt/ODT/ODTHeading.php'; 8require_once DOKU_PLUGIN . 'odt/ODT/ODTParagraph.php'; 9require_once DOKU_PLUGIN . 'odt/ODT/ODTTable.php'; 10require_once DOKU_PLUGIN . 'odt/ODT/ODTFrame.php'; 11require_once DOKU_PLUGIN . 'odt/ODT/ODTImage.php'; 12require_once DOKU_PLUGIN . 'odt/ODT/ODTSpan.php'; 13require_once DOKU_PLUGIN . 'odt/ODT/ODTIndex.php'; 14require_once DOKU_PLUGIN . 'odt/ODT/ODTUnits.php'; 15require_once DOKU_PLUGIN . 'odt/ODT/ODTmeta.php'; 16require_once DOKU_PLUGIN . 'odt/ODT/ODTmanifest.php'; 17require_once DOKU_PLUGIN . 'odt/ODT/css/cssimportnew.php'; 18require_once DOKU_PLUGIN . 'odt/ODT/ODTImport.php'; 19require_once DOKU_PLUGIN . 'odt/ODT/ODTExport.php'; 20 21// Siple class as storage for internal parameters passed to other 22// classes to prevent to long parameter lines. 23class ODTInternalParams 24{ 25 public $document = NULL; 26 public $htmlStack = NULL; 27 public $import = NULL; 28 public $units = NULL; 29 public $content = NULL; 30 public $elementObj = NULL; 31 public $ZIP = NULL; 32 public $manifest = NULL; 33 public $styleset = NULL; 34} 35 36/** 37 * Main class/API for creating an ODTDocument. 38 * 39 * Work in progress!!! Goals: 40 * 41 * - Move all pure ODT specific code away from the ODT-DokuWiki 42 * renderer class in page.php/book.php 43 * 44 * - Make the ODT DokuWiki renderer classes only call functions in this 45 * class directly to have a single class only which is seen/used by 46 * the renderer classes 47 * 48 * @license GPL 2 (http://www.gnu.org/licenses/gpl.html) 49 * @author LarsDW223 50 */ 51class ODTDocument 52{ 53 // Public for now. 54 // Will become protected as soon as all stuff using state 55 // has been moved. 56 public $state; 57 public $div_z_index = 0; 58 /** @var Debug string */ 59 public $trace_dump = ''; 60 61 /** @var has any text content been added yet (excluding whitespace)? */ 62 protected $text_empty = true; 63 /** @var array store the table of contents */ 64 protected $toc = array(); 65 /** @var ODTMeta */ 66 protected $meta; 67 /** @var helper_plugin_odt_units */ 68 protected $units = null; 69 /** @var Current pageFormat */ 70 protected $page = null; 71 /** @var changePageFormat */ 72 protected $changePageFormat = NULL; 73 /** @var indexesData */ 74 protected $indexesData = array(); 75 /** @var Array of used page styles. Will stay empty if only A4-portrait is used */ 76 protected $pageStyles = array (); 77 /** @var Array of paragraph style names that prevent an empty paragraph from being deleted */ 78 protected $preventDeletetionStyles = array (); 79 /** @var pagebreak */ 80 protected $pagebreak = false; 81 /** @var headers */ 82 protected $headers = array(); 83 /** @var refIDCount */ 84 protected $refIDCount = 0; 85 /** @var pageBookmark */ 86 protected $pageBookmark = NULL; 87 /** @var array store the bookmarks */ 88 protected $bookmarks = array(); 89 /** @var string temporary storage of xml-content */ 90 public $store = ''; 91 /** @var array */ 92 public $footnotes = array(); 93 protected $quote_depth = 0; 94 protected $linksEnabled = true; 95 // Used by Fields Plugin 96 protected $fields = array(); 97 // The document content 98 protected $content = ''; 99 /** @var cssimportnew */ 100 protected $importnew = null; 101 /** @var cssdocument */ 102 protected $htmlStack = null; 103 protected $CSSUsage = 'off'; 104 protected $params = NULL; 105 protected $manifest = NULL; 106 protected $ZIP = NULL; 107 protected $styleset = NULL; 108 protected $registrations = array(); 109 110 /** 111 * Constructor: 112 * - initializes the state 113 */ 114 public function __construct() { 115 // Initialize state 116 $this->state = new ODTState(); 117 118 // Initialize HTML state 119 $this->htmlStack = new cssdocument(); 120 121 // Create default styles/styles storage. 122 $this->styleset = new ODTDefaultStyles(); 123 $this->styleset->import(); 124 125 // Set standard page format: A4, portrait, 2cm margins 126 $this->page = new pageFormat(); 127 $this->setStartPageFormat ('A4', 'portrait', 2, 2, 2, 2); 128 129 // Create units object and set default values 130 $this->units = new ODTUnits(); 131 $this->units->setPixelPerEm(16); 132 $this->units->setTwipsPerPixelX(16); 133 $this->units->setTwipsPerPixelY(20); 134 135 // Setup meta data store/handler 136 $this->meta = new ODTMeta(); 137 138 // Setup manifest data 139 $this->manifest = new ODTManifest(); 140 141 // Prepare the zipper 142 // (This instance is only for our to-be-created ODT-ZIP-Archive 143 // - NOT to be used for extracting any ODT-Templates!) 144 if (class_exists('\splitbrain\PHPArchive\Zip')) 145 { 146 $this->ZIP = new \splitbrain\PHPArchive\Zip(); 147 $this->ZIP->create(); 148 } 149 150 $this->params = new ODTInternalParams(); 151 } 152 153 /** 154 * Initialize the document. 155 */ 156 public function initialize () { 157 $this->state->setDocument($this); 158 159 $this->params->document = $this; 160 $this->params->htmlStack = $this->htmlStack; 161 $this->params->units = $this->units; 162 $this->params->content = &$this->content; 163 $this->params->ZIP = $this->ZIP; 164 $this->params->manifest = $this->manifest; 165 $this->params->styleset = $this->styleset; 166 167 if (!isset($this->ZIP)) { 168 return false; 169 } 170 return true; 171 } 172 173 /** 174 * Set CSS usage. 175 * 176 * @param string $usage 177 */ 178 public function setCSSUsage ($usage) { 179 switch (strtolower($usage)) { 180 case 'basic': 181 case 'full': 182 $this->CSSUsage = $usage; 183 break; 184 default: 185 $this->CSSUsage = 'off'; 186 break; 187 } 188 } 189 190 protected function setupImport() { 191 if (!isset($this->importnew)) { 192 // No CSS imported yet. Create object. 193 $this->importnew = new cssimportnew(); 194 if (!isset($this->importnew)) { 195 return; 196 } 197 } 198 $this->params->import = $this->importnew; 199 } 200 201 /** 202 * Set commom CSS media selector. 203 * 204 * @param string $mediaSel 205 */ 206 public function setMediaSelector ($mediaSel) { 207 if (!isset($this->importnew)) { 208 $this->setupImport(); 209 } 210 $this->importnew->setMedia ($mediaSel); 211 } 212 213 /** 214 * Callback function which adjusts all CSS length values to point. 215 * 216 * @param $property The name of the current CSS property, e.g. 'border-left' 217 * @param $value The current value from the original CSS code 218 * @param $type There are 3 possible values: 219 * - LengthValueXAxis: the property represents a value on the X axis 220 * - LengthValueYAxis: the property represents a value on the Y axis 221 * - CSSValueType::StrokeOrBorderWidth: the property represents a stroke 222 * or border width 223 * @return string The new, adjusted value for the property 224 */ 225 public function adjustLengthCallback ($property, $value, $type, $rule) { 226 // Get the digits and unit 227 $digits = ODTUnits::getDigits($value); 228 $unit = ODTUnits::stripDigits($value); 229 230 if ( $unit == 'px' ) { 231 // Replace px with pt (px does not seem to be supported by ODT) 232 switch ($type) { 233 case CSSValueType::LengthValueXAxis: 234 $adjusted = $this->toPoints($value, 'x'); 235 break; 236 237 case CSSValueType::StrokeOrBorderWidth: 238 switch ($property) { 239 case 'border': 240 case 'border-left': 241 case 'border-right': 242 case 'border-top': 243 case 'border-bottom': 244 // border in ODT spans does not support 'px' units, so we convert it. 245 $adjusted = $this->toPoints($value, 'y'); 246 break; 247 248 default: 249 $adjusted = $value; 250 break; 251 } 252 break; 253 254 case CSSValueType::LengthValueYAxis: 255 default: 256 switch ($property) { 257 case 'line-height': 258 $adjusted = $this->toPoints($value, 'y'); 259 break; 260 default: 261 $adjusted = $this->toPoints($value, 'y'); 262 break; 263 } 264 break; 265 } 266 return $adjusted; 267 } else { 268 if ($property == 'line-height' && $value != 'normal') { 269 if ($unit == '%' || empty($unit)) { 270 // Relative values must be handled later 271 return $value; 272 } 273 $adjusted = $this->toPoints($value, 'y'); 274 return $adjusted; 275 } 276 return $value; 277 } 278 279 return $value; 280 } 281 282 public function replaceURLPrefixes ($callback) { 283 if (isset($this->importnew)) { 284 $this->importnew->replaceURLPrefixes ($callback); 285 } 286 } 287 288 public function enableLinks () { 289 $this->linksEnabled = true; 290 } 291 292 public function disableLinks () { 293 $this->linksEnabled = false; 294 } 295 296 // Functions generating content for now will have to be passed 297 // $renderer->doc. Later this will be removed and an internal doc 298 // variable will be maintained. This will break backwards compatibility 299 // with plugins writing to $renderer->doc directly (instead of calling cdata). 300 301 /** 302 * Render plain text data 303 * 304 * @param string $text 305 */ 306 function addPlainText($text) { 307 // Check if there is some content in the text. 308 // Only insert bookmark/pagebreak/format change if text is not empty. 309 // Otherwise a empty paragraph/line would be created! 310 if ( !empty($text) && !ctype_space($text) ) { 311 // Insert page bookmark if requested and not done yet. 312 $this->insertPendingPageBookmark(); 313 314 // Insert pagebreak or page format change if still pending. 315 // Attention: NOT if $text is empty. This would lead to empty lines before headings 316 // right after a pagebreak! 317 $in_paragraph = $this->state->getInParagraph(); 318 if ( ($this->pagebreakIsPending() || $this->pageFormatChangeIsPending()) || 319 !$in_paragraph ) { 320 $this->paragraphOpen(); 321 } 322 } 323 $this->content .= $this->replaceXMLEntities($text); 324 if ($this->text_empty && !ctype_space($text)) { 325 $this->text_empty = false; 326 } 327 } 328 329 /** 330 * Open a text span. 331 * 332 * @param string $styleName The style to use. 333 * @see ODTSpan::spanOpen for detailed documentation 334 */ 335 function spanOpen($styleName, $element=NULL, $attributes=NULL){ 336 $in_paragraph = $this->state->getInParagraph(); 337 if ( !$in_paragraph ) { 338 $this->paragraphOpen(); 339 } 340 unset($this->params->elementObj); 341 ODTSpan::spanOpen($this->params, $styleName, $element, $attributes); 342 } 343 344 /** 345 * Open a text span using CSS. 346 * 347 * @see ODTSpan::spanOpenUseCSS for detailed documentation 348 */ 349 function spanOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 350 $in_paragraph = $this->state->getInParagraph(); 351 if ( !$in_paragraph ) { 352 $this->paragraphOpen(); 353 } 354 if (!isset($import)) { 355 $import = $this->importnew; 356 } 357 if (!isset($element)) { 358 $element = 'span'; 359 } 360 unset($this->params->elementObj); 361 $this->params->import = $import; 362 ODTSpan::spanOpenUseCSS($this->params, $element, $attributes); 363 $this->params->import = $this->importnew; 364 } 365 366 /** 367 * Open a text span using properties. 368 * 369 * @see ODTSpan::spanOpenUseProperties for detailed documentation 370 */ 371 function spanOpenUseProperties($properties){ 372 $in_paragraph = $this->state->getInParagraph(); 373 if ( !$in_paragraph ) { 374 $this->paragraphOpen(); 375 } 376 ODTUtility::adjustValuesForODT($properties, $this->units); 377 unset($this->params->elementObj); 378 ODTSpan::spanOpenUseProperties($this->params, $properties); 379 } 380 381 /** 382 * Close a text span. 383 * 384 * @param string $style_name The style to use. 385 * @see ODTSpan::spanClose for detailed documentation 386 */ 387 function spanClose() { 388 unset($this->params->elementObj); 389 ODTSpan::spanClose($this->params); 390 } 391 392 /** 393 * Automatically generate ODT format for $HTMLCode 394 * including text spans. 395 * 396 * @param string $style_name The style to use. 397 * @see ODTSpan::generateSpansfromHTMLCode for detailed documentation 398 */ 399 function generateSpansfromHTMLCode($HTMLCode){ 400 ODTSpan::generateSpansfromHTMLCode($this->params, $HTMLCode); 401 } 402 403 /** 404 * Open a paragraph 405 * 406 * @param string $styleName The style to use. 407 * @see ODTParagraph::paragraphOpen for detailed documentation 408 */ 409 function paragraphOpen($styleName=NULL, $element=NULL, $attributes=NULL){ 410 unset($this->params->elementObj); 411 ODTParagraph::paragraphOpen($this->params, $styleName, $element, $attributes); 412 } 413 414 /** 415 * Close a paragraph 416 * 417 * @see ODTParagraph::paragraphClose for detailed documentation 418 */ 419 function paragraphClose(){ 420 unset($this->params->elementObj); 421 ODTParagraph::paragraphClose($this->params); 422 } 423 424 /** 425 * Open a paragraph using CSS. 426 * 427 * @see ODTParagraph::paragraphOpenUseCSS for detailed documentation 428 */ 429 function paragraphOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 430 if (!isset($import)) { 431 $import = $this->importnew; 432 } 433 if (!isset($element)) { 434 $element = 'p'; 435 } 436 unset($this->params->elementObj); 437 $this->params->import = $import; 438 ODTParagraph::paragraphOpenUseCSS($this->params, $element, $attributes); 439 $this->params->import = $this->importnew; 440 } 441 442 /** 443 * Open a paragraph using properties. 444 * 445 * @see ODTParagraph::paragraphOpenUseProperties for detailed documentation 446 */ 447 function paragraphOpenUseProperties($properties){ 448 ODTUtility::adjustValuesForODT($properties, $this->units); 449 unset($this->params->elementObj); 450 ODTParagraph::paragraphOpenUseProperties($this->params, $properties); 451 } 452 453 /** 454 * Insert a horizontal rule 455 */ 456 function horizontalRule() { 457 $this->paragraphClose(); 458 $styleName = $this->getStyleName('horizontal line'); 459 $this->paragraphOpen($styleName); 460 $this->paragraphClose(); 461 462 // Save paragraph style name in 'Do not delete array'! 463 $this->preventDeletetionStyles [] = $styleName; 464 } 465 466 /** 467 * static call back to replace spaces 468 * 469 * @param array $matches 470 * @return string 471 */ 472 function _preserveSpace($matches){ 473 $spaces = $matches[1]; 474 $len = strlen($spaces); 475 return '<text:s text:c="'.$len.'"/>'; 476 } 477 478 /** 479 * @param string $text 480 * @param string $style 481 * @param bool $notescaped 482 */ 483 function addPreformattedText($text, $style=null, $notescaped=true) { 484 if (empty($style)) { 485 $style = $this->getStyleName('preformatted'); 486 } 487 if ($notescaped) { 488 $text = $this->replaceXMLEntities($text); 489 } 490 491 // Check newline at start 492 $first_newline = strpos($text, "\n"); 493 if ($first_newline !== FALSE and $first_newline == 0) { 494 // text starts with a newline, remove it 495 $text = substr($text,1); 496 } 497 498 // Check newline at end 499 $length = strlen($text); 500 if ($text[$length-1] == "\n") { 501 $text = substr($text, 0, $length-1); 502 } 503 504 $text = str_replace("\n",'<text:line-break/>',$text); 505 $text = str_replace("\t",'<text:tab/>',$text); 506 $text = preg_replace_callback('/( +)/',array($this,'_preserveSpace'),$text); 507 508 $list_item = $this->state->getCurrentListItem(); 509 if (isset($list_item)) { 510 // if we're in a list item, we must close the <text:p> tag 511 $this->paragraphClose(); 512 $this->paragraphOpen($style); 513 $this->content .= $text; 514 $this->paragraphClose(); 515 // FIXME: query previous style before preformatted text was opened and re-use it here 516 $this->paragraphOpen(); 517 } else { 518 $this->paragraphClose(); 519 $this->paragraphOpen($style); 520 $this->content .= $text; 521 $this->paragraphClose(); 522 } 523 } 524 525 /** 526 * Add a linebreak 527 */ 528 function linebreak() { 529 $this->content .= '<text:line-break/>'; 530 } 531 532 /** 533 * Add a pagebreak 534 */ 535 function pagebreak() { 536 // Only set marker to insert a pagebreak on "next occasion". 537 // The pagebreak will then be inserted in the next call to p_open() or header(). 538 // The style will be a "pagebreak" style with the paragraph or header style as the parent. 539 // This prevents extra empty lines after the pagebreak. 540 $this->paragraphClose(); 541 $this->pagebreak = true; 542 } 543 544 /** 545 * Check if a pagebreak is pending 546 * 547 * @return bool 548 */ 549 function pagebreakIsPending() { 550 return $this->pagebreak; 551 } 552 553 /** 554 * Check if a page format change is pending 555 * 556 * @return bool 557 */ 558 function pageFormatChangeIsPending() { 559 if (isset($this->changePageFormat)) { 560 return true; 561 } 562 return false; 563 } 564 565 /** 566 * Set pagebreak pending. 567 * 568 * @return bool 569 */ 570 function setPagebreakPending($value) { 571 return $this->pagebreak = $value; 572 } 573 574 /** 575 * Check if a header with $title exists. 576 * 577 * @return bool 578 */ 579 function headerExists($title) { 580 return in_array($title, $this->headers); 581 } 582 583 /** 584 * Add $title to headers. 585 * 586 * @return bool 587 */ 588 function addHeader($title) { 589 $this->headers[] = $title; 590 } 591 592 /** 593 * Insert an index into the document using the parameters in $settings. 594 * 595 * @see ODTIndex::insertIndex for detailed documentation 596 */ 597 function insertIndex($type='toc', array $settings=NULL) { 598 ODTIndex::insertIndex($this->params, $this->indexesData, $type, $settings); 599 } 600 601 /** 602 * Creates a reference ID for the TOC 603 * 604 * @param string $title The headline/item title 605 * @return string 606 * 607 * @author LarsDW223 608 */ 609 public function buildTOCReferenceID($title) { 610 // FIXME: not DokuWiki dependant function woud be nicer... 611 $title = str_replace(':','',cleanID($title)); 612 $title = ltrim($title,'0123456789._-'); 613 if(empty($title)) { 614 $title='NoTitle'; 615 } 616 617 $this->refIDCount++; 618 619 // The reference ID needs to start with '__RefHeading___'. 620 // Otherwise LibreOffice will display $ref instead of the heading 621 // name when moving the mouse over the link in the TOC. 622 $ref = '__RefHeading___'.$title.'_'.$this->refIDCount; 623 return $ref; 624 } 625 626 /** 627 * Add an item to the TOC 628 * 629 * @param string $refID the reference ID 630 * @param string $hid the hash link 631 * @param string $text the text to display 632 * @param int $level the nesting level 633 */ 634 function tocAddItemInternal($refID, $hid, $text, $level) { 635 $item = $refID.','.$hid.','.$text.','. $level; 636 $this->toc[] = $item; 637 } 638 639 /** 640 * Set bookmark for the start of the page. This just saves the title temporarily. 641 * It is then to be inserted in the first header or paragraph. 642 * 643 * @param string $id ID of the bookmark 644 */ 645 function setPageBookmark($id){ 646 $inParagraph = $this->state->getInParagraph(); 647 if ($inParagraph) { 648 $this->insertBookmarkInternal($id, true); 649 } else { 650 $this->pageBookmark = $id; 651 } 652 } 653 654 /** 655 * Insert a bookmark. If $now is true then the bookmark will be created 656 * immediately. This eventually causes a paragraph to be opened. 657 * If $now is false then the bookmark will be inserted with the next 658 * cdata text. 659 * 660 * @param string $id ID of the bookmark 661 * @param string $now Insert bookmark immediately? 662 */ 663 public function insertBookmark($id, $now) { 664 if ($now) { 665 $this->insertBookmarkInternal($id); 666 } else { 667 $this->pageBookmark = $id; 668 } 669 } 670 671 /** 672 * Insert a bookmark. 673 * 674 * @param string $id ID of the bookmark 675 */ 676 protected function insertBookmarkInternal($id, $openParagraph=true){ 677 if ($openParagraph) { 678 $this->paragraphOpen(); 679 } 680 $this->content .= '<text:bookmark text:name="'.$id.'"/>'; 681 $this->bookmarks [] = $id; 682 } 683 684 /** 685 * Insert a pending page bookmark 686 * 687 * @param string $text the text to display 688 * @param int $level header level 689 * @param int $pos byte position in the original source 690 */ 691 function insertPendingPageBookmark(){ 692 // Insert page bookmark if requested and not done yet. 693 if ( !empty($this->pageBookmark) ) { 694 $this->insertBookmarkInternal($this->pageBookmark, false); 695 $this->pageBookmark = NULL; 696 } 697 } 698 699 /** 700 * Render a heading. 701 * 702 * @param string $text the text to display 703 * @param int $level header level 704 * @param int $pos byte position in the original source 705 * @see ODTHeading::heading for detailed documentation 706 */ 707 function heading($text, $level, $element=NULL, $attributes=NULL){ 708 ODTHeading::heading($this->params, $text, $level, $element, $attributes); 709 } 710 711 /** 712 * Make sure that a user field name only contains valid sings. 713 * (Code has been adopted from the fields plugin) 714 * 715 * @param string $name The name of the field 716 * @return string The cleaned up $name 717 * @author Aurelien Bompard <aurelien@bompard.org> 718 */ 719 protected function cleanupUserFieldName($name) { 720 // Keep only allowed chars in the name 721 return preg_replace('/[^a-zA-Z0-9_.]/', '', $name); 722 } 723 724 /** 725 * Add a user field. 726 * (Code has been adopted from the fields plugin) 727 * 728 * @param string $name The name of the field 729 * @param string $value The value of the field 730 * @author Aurelien Bompard <aurelien@bompard.org> 731 */ 732 public function addUserField($name, $value) { 733 $name = $this->cleanupUserFieldName($name); 734 $this->fields [$name] = $value; 735 } 736 737 /** 738 * Insert a user field reference. 739 * (Code has been adopted from the fields plugin) 740 * 741 * @param string $name The name of the field 742 * @author Aurelien Bompard <aurelien@bompard.org> 743 */ 744 public function insertUserField($name) { 745 $name = $this->cleanupUserFieldName($name); 746 if (array_key_exists($name, $this->fields)) { 747 $this->content .= '<text:user-field-get text:name="'.$name.'">'.$this->fields [$name].'</text:user-field-get>'; 748 } 749 } 750 751 /** 752 * This function encodes the <text:user-field-decls> section of a 753 * ODT document. 754 * 755 * @return string 756 */ 757 protected function getUserFieldDecls() { 758 $value = '<text:user-field-decls>'; 759 foreach ($this->fields as $fname => $fvalue) { 760 $value .= '<text:user-field-decl office:value-type="string" text:name="'.$fname.'" office:string-value="'.$fvalue.'"/>'; 761 } 762 $value .= '</text:user-field-decls>'; 763 return $value; 764 } 765 766 /** 767 * Get ODT file as string (ZIP archive). 768 * 769 * @param string $content The content 770 * @return string String containing ODT ZIP stream 771 */ 772 public function getODTFileAsString($ODTtemplate=NULL, $tempDir=NULL) { 773 // Close any open paragraph if not done yet. 774 $this->paragraphClose(); 775 776 // Replace local link placeholders with links to headings or bookmarks 777 $styleName = $this->getStyleName('local link'); 778 $visitedStyleName = $this->getStyleName('visited local link'); 779 ODTUtility::replaceLocalLinkPlaceholders($this->content, $this->toc, $this->bookmarks, $styleName, $visitedStyleName); 780 781 // Build indexes 782 ODTIndex::replaceIndexesPlaceholders($this->params, $this->indexesData, $this->toc); 783 784 // Delete paragraphs which only contain whitespace (but keep pagebreaks!) 785 ODTUtility::deleteUselessElements($this->content, $this->preventDeletetionStyles); 786 787 //$this->trace_dump .= $this->htmlStack->getDump(); 788 //$this->trace_dump .= $this->importnew->rulesToString(); 789 790 if (!empty($this->trace_dump)) { 791 $this->paragraphOpen(); 792 $this->linebreak(); 793 $this->content .= 'Tracedump: '; 794 $this->addPreformattedText($this->trace_dump); 795 $this->paragraphClose(); 796 } 797 798 // Get meta content 799 $metaContent = $this->meta->getContent(); 800 801 // Get user field declarations 802 $userFieldDecls = $this->getUserFieldDecls(); 803 804 // Build the document 805 ODTExport::buildZIPFile($this->params, 806 $metaContent, 807 $userFieldDecls, 808 $this->pageStyles, 809 $ODTtemplate, 810 $tempDir); 811 812 // Return document 813 return $this->ZIP->getArchive(); 814 } 815 816 /** 817 * Import CSS code for styles from a string. 818 * 819 * @param string $cssCode The CSS code to import 820 * @param string $mediaSel The media selector to use e.g. 'print' 821 * @param string $mediaPath Local path to media files 822 */ 823 public function importCSSFromString($cssCode, $mediaSel=NULL, $URLCallback=NULL, $forceStyles=false, $listAlign='right') { 824 // Import CSS as styles? 825 $importStyles = false; 826 if ($this->CSSUsage == 'basic' || $this->CSSUsage == 'full' || $forceStyles) { 827 $importStyles = true; 828 } 829 ODTImport::importCSSFromString ($this->params, $cssCode, $mediaSel, array($this, 'adjustLengthCallback'), $URLCallback, $this->registrations, $importStyles, $listAlign); 830 } 831 832 /** 833 * Import CSS code for styles from a file. 834 * 835 * @param string $CSSTemplate String containing the path and file name of the CSS file to import 836 * @param string $mediaSel The media selector to use e.g. 'print' 837 * @param string $mediaPath Local path to media files 838 */ 839 public function importCSSFromFile($CSSTemplate, $mediaSel=NULL, $URLCallback=NULL, $listAlign='right') { 840 // Import CSS as styles? 841 $importStyles = false; 842 if ($this->CSSUsage == 'basic' || $this->CSSUsage == 'full') { 843 $importStyles = true; 844 } 845 ODTImport::importCSSFromFile ($this->params, $CSSTemplate, $mediaSel, array($this, 'adjustLengthCallback'), $URLCallback, $this->registrations, $importStyles, $listAlign); 846 } 847 848 public function importODTStyles($template=NULL, $tempDir=NULL) { 849 ODTImport::importODTStyles($this->params, $template, $tempDir); 850 } 851 852 /** 853 * General internal function for closing an element. 854 * Can always be used to close any open element if no more actions 855 * are required apart from generating the closing tag and 856 * removing the element from the state stack. 857 */ 858 public function closeCurrentElement() { 859 $current = $this->state->getCurrent(); 860 if (isset($current)) { 861 $this->content .= $current->getClosingTag($this->content); 862 $this->state->leave(); 863 } 864 } 865 866 /** 867 * This function creates a style for changing the page format if required. 868 * It returns NULL if no page format change is pending or if the current 869 * page format is equal to the required page format. 870 * 871 * @param string $parent Parent style name. 872 * @return string Name of the style to be used for changing page format 873 * 874 * FIXME: make protected as soon as function header is moved here also! 875 */ 876 public function doPageFormatChange ($parent = NULL) { 877 if ( !isset($this->changePageFormat) ) { 878 // Error. 879 return NULL; 880 } 881 $data = $this->changePageFormat; 882 $this->changePageFormat = NULL; 883 884 if ( empty($parent) ) { 885 $parent = 'Standard'; 886 } 887 888 // Create page layout style 889 $format_string = $this->page->formatToString ($data['format'], $data['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); 890 $properties ['style-name'] = 'Style-Page-'.$format_string; 891 $properties ['width'] = $data ['width']; 892 $properties ['height'] = $data ['height']; 893 $properties ['margin-top'] = $data ['margin-top']; 894 $properties ['margin-bottom'] = $data ['margin-bottom']; 895 $properties ['margin-left'] = $data ['margin-left']; 896 $properties ['margin-right'] = $data ['margin-right']; 897 $style_obj = ODTPageLayoutStyle::createPageLayoutStyle($properties); 898 $style_name = $style_obj->getProperty('style-name'); 899 900 // It is iassumed the proper media selector has been set by calling setMediaSelector() 901 if (($this->CSSUsage == 'basic' || $this->CSSUsage == 'full') && isset($this->importnew)) { 902 ODTImport::set_page_properties($this->params, $style_obj); 903 } 904 905 // Save style data in page style array, in common styles and set current page format 906 $master_page_style_name = $format_string; 907 $this->pageStyles [$master_page_style_name] = $style_name; 908 $this->addAutomaticStyle($style_obj); 909 $this->page->setFormat($data ['format'], $data ['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); 910 911 // Create paragraph style. 912 $properties = array(); 913 $properties ['style-name'] = 'Style-'.$format_string; 914 $properties ['style-parent'] = $parent; 915 $properties ['style-master-page-name'] = $master_page_style_name; 916 $properties ['page-number'] = 'auto'; 917 $style_obj = ODTParagraphStyle::createParagraphStyle($properties); 918 $style_name = $style_obj->getProperty('style-name'); 919 $this->addAutomaticStyle($style_obj); 920 921 // Save paragraph style name in 'Do not delete array'! 922 $this->preventDeletetionStyles [] = $style_name; 923 924 return $style_name; 925 } 926 927 public function createPagebreakStyle($parent=NULL,$before=true) { 928 $style_name = 'pagebreak'; 929 if ( !$before ) { 930 $style_name .= '_after'; 931 } 932 if ( !empty($parent) ) { 933 $style_name .= '_'.$parent; 934 } 935 if ( !$this->styleExists($style_name) ) { 936 $style_obj = ODTParagraphStyle::createPagebreakStyle($style_name, $parent, $before); 937 $this->addAutomaticStyle($style_obj); 938 939 // Save paragraph style name in 'Do not delete array'! 940 $this->preventDeletetionStyles [] = $style_name; 941 } 942 943 return $style_name; 944 } 945 946 /** 947 * Replace XML entities 948 * 949 * @param string $value 950 * @return string 951 */ 952 function replaceXMLEntities($value) { 953 return str_replace( array('&','"',"'",'<','>'), array('&','"',''','<','>'), $value); 954 } 955 956 /** 957 * Open/start a footnote. 958 * 959 * @author Andreas Gohr <andi@splitbrain.org> 960 * @see ODTFootnote::footnoteOpen for detailed documentation 961 */ 962 function footnoteOpen() { 963 ODTFootnote::footnoteOpen($this->params); 964 } 965 966 /** 967 * Close/end a footnote. 968 * 969 * @author Andreas Gohr 970 * @see ODTFootnote::footnoteClose for detailed documentation 971 */ 972 function footnoteClose() { 973 ODTFootnote::footnoteClose($this->params); 974 } 975 976 function quoteOpen() { 977 // Do not go higher than 5 because only 5 quotation styles are defined. 978 if ( $this->quote_depth < 5 ) { 979 $this->quote_depth++; 980 } 981 unset($this->params->elementObj); 982 ODTTable::tableOpen($this->params, 1, 1, 'Table_Quotation'.$this->quote_depth, 'blockquote', NULL); 983 $this->tableRowOpen(); 984 unset($this->params->elementObj); 985 ODTTable::tableCellOpen($this->params, 1, 1, 'left', 'Cell_Quotation'.$this->quote_depth, NULL, NULL, NULL); 986 } 987 988 function quoteClose() { 989 $this->paragraphClose(); 990 $this->tableCellClose(); 991 $this->tableRowClose(); 992 $this->tableClose(); 993 if ( $this->quote_depth > 0 ) { 994 $this->quote_depth--; 995 } 996 } 997 998 /** 999 * Opens a list. 1000 * The list style specifies if the list is an ordered or unordered list. 1001 * 1002 * @param bool $continue Continue numbering? 1003 * @param string $styleName Name of style to use for the list 1004 * @see ODTList::listOpen for detailed documentation 1005 */ 1006 function listOpen($continue=false, $styleName, $element=NULL, $attributes=NULL) { 1007 if (!isset($element)) { 1008 if ($styleName == $this->getStyleName('list')) { 1009 $element = 'ul'; 1010 } 1011 if ($styleName == $this->getStyleName('numbering')) { 1012 $element = 'ol'; 1013 } 1014 } 1015 ODTList::listOpen($this->params, $continue, $styleName, $element, $attributes); 1016 } 1017 1018 /** 1019 * Close a list. 1020 * 1021 * @see ODTList::listClose for detailed documentation 1022 */ 1023 function listClose() { 1024 ODTList::listClose($this->params); 1025 } 1026 1027 /** 1028 * Open a list item. 1029 * 1030 * @param int $level The nesting level 1031 * @see ODTList::listItemOpen for detailed documentation 1032 */ 1033 function listItemOpen($level, $element=NULL, $attributes=NULL) { 1034 ODTList::listItemOpen($this->params, $level, $element, $attributes); 1035 } 1036 1037 /** 1038 * Close a list item. 1039 * 1040 * @see ODTList::listItemClose for detailed documentation 1041 */ 1042 function listItemClose() { 1043 ODTList::listItemClose($this->params); 1044 } 1045 1046 /** 1047 * Open a list header. 1048 * 1049 * @param int $level The nesting level 1050 * @see ODTList::listHeaderOpen for detailed documentation 1051 */ 1052 function listHeaderOpen($level, $element=NULL, $attributes=NULL) { 1053 ODTList::listHeaderOpen($this->params, $level, $element, $attributes); 1054 } 1055 1056 /** 1057 * Close a list header. 1058 * 1059 * @see ODTList::listHeaderClose for detailed documentation 1060 */ 1061 function listHeaderClose() { 1062 ODTList::listHeaderClose($this->params); 1063 } 1064 1065 /** 1066 * Open list content/a paragraph in a list item. 1067 * 1068 * @see ODTList::listContentOpen for detailed documentation 1069 */ 1070 function listContentOpen($element=NULL, $attributes=NULL) { 1071 ODTList::listContentOpen($this->params, $element, $attributes); 1072 } 1073 1074 /** 1075 * Close list content/a paragraph in a list item. 1076 * 1077 * @see ODTList::listContentClose for detailed documentation 1078 */ 1079 function listContentClose() { 1080 ODTList::listContentClose($this->params); 1081 } 1082 1083 /** 1084 * Open/start a table. 1085 * 1086 * @param int $maxcols maximum number of columns 1087 * @param int $numrows NOT IMPLEMENTED 1088 * @see ODTTable::tableOpen for detailed documentation 1089 */ 1090 function tableOpen($maxcols = NULL, $numrows = NULL, $element=NULL, $attributes=NULL){ 1091 unset($this->params->elementObj); 1092 ODTTable::tableOpen($this->params, $maxcols, $numrows, NULL, $element, $attributes); 1093 } 1094 1095 /** 1096 * Close/finish a table. 1097 * 1098 * @param int $maxcols maximum number of columns 1099 * @param int $numrows NOT IMPLEMENTED 1100 * @see ODTTable::tableClose for detailed documentation 1101 */ 1102 function tableClose(){ 1103 unset($this->params->elementObj); 1104 ODTTable::tableClose($this->params); 1105 } 1106 1107 /** 1108 * Add a column to a table. 1109 * 1110 * @see ODTTable::tableAddColumn for detailed documentation 1111 */ 1112 function tableAddColumn (){ 1113 unset($this->params->elementObj); 1114 ODTTable::tableAddColumn ($this->params); 1115 } 1116 1117 /** 1118 * Open a table row. 1119 * 1120 * @see ODTTable::tableRowOpen for detailed documentation 1121 */ 1122 function tableRowOpen($element=NULL, $attributes=NULL){ 1123 unset($this->params->elementObj); 1124 ODTTable::tableRowOpen($this->params, NULL, $element, $attributes); 1125 } 1126 1127 /** 1128 * Close a table row. 1129 * 1130 * @see ODTTable::tableRowClose for detailed documentation 1131 */ 1132 function tableRowClose(){ 1133 unset($this->params->elementObj); 1134 ODTTable::tableRowClose($this->params); 1135 } 1136 1137 /** 1138 * Open a table header cell. 1139 * 1140 * @see ODTTable::tableHeaderOpen for detailed documentation 1141 */ 1142 function tableHeaderOpen($colspan = 1, $rowspan = 1, $align, $element=NULL, $attributes=NULL){ 1143 unset($this->params->elementObj); 1144 ODTTable::tableHeaderOpen($this->params, $colspan, $rowspan, $align, NULL, NULL, $element, $attributes); 1145 } 1146 1147 /** 1148 * Close a table header cell. 1149 * 1150 * @see ODTTable::tableHeaderClose for detailed documentation 1151 */ 1152 function tableHeaderClose(){ 1153 unset($this->params->elementObj); 1154 ODTTable::tableHeaderClose($this->params); 1155 } 1156 1157 /** 1158 * Open a table cell. 1159 * 1160 * @see ODTTable::tableCellOpen for detailed documentation 1161 */ 1162 function tableCellOpen($colspan, $rowspan, $align, $element=NULL, $attributes=NULL){ 1163 unset($this->params->elementObj); 1164 ODTTable::tableCellOpen($this->params, $colspan, $rowspan, $align, NULL, NULL, $element, $attributes); 1165 } 1166 1167 /** 1168 * Close a table cell. 1169 * 1170 * @see ODTTable::tableCellClose for detailed documentation 1171 */ 1172 function tableCellClose(){ 1173 unset($this->params->elementObj); 1174 ODTTable::tableCellClose($this->params); 1175 } 1176 1177 /** 1178 * Open a table using CSS. 1179 * 1180 * @see ODTTable::tableOpenUseCSS for detailed documentation 1181 */ 1182 function tableOpenUseCSS($maxcols=NULL, $numrows=NULL, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 1183 if (!isset($import)) { 1184 $import = $this->importnew; 1185 } 1186 if (!isset($element)) { 1187 $element = 'table'; 1188 } 1189 1190 unset($this->params->elementObj); 1191 $this->params->import = $import; 1192 ODTTable::tableOpenUseCSS($this->params, $maxcols, $numrows, $element, $attributes); 1193 $this->params->import = $this->importnew; 1194 } 1195 1196 /** 1197 * Open a table using properties. 1198 * 1199 * @see ODTTable::tableOpenUseProperties for detailed documentation 1200 */ 1201 function tableOpenUseProperties ($properties, $maxcols = 0, $numrows = 0){ 1202 unset($this->params->elementObj); 1203 ODTTable::tableOpenUseProperties($this->params, $properties, $maxcols, $numrows); 1204 } 1205 1206 /** 1207 * Add a table column using properties. 1208 * 1209 * @see ODTTable::tableAddColumnUseProperties for detailed documentation 1210 */ 1211 function tableAddColumnUseProperties ($properties){ 1212 unset($this->params->elementObj); 1213 ODTTable::tableAddColumnUseProperties($this->params, $properties); 1214 } 1215 1216 /** 1217 * Open a table header using CSS. 1218 * 1219 * @see ODTTable::tableHeaderOpenUseCSS for detailed documentation 1220 */ 1221 function tableHeaderOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 1222 if (!isset($import)) { 1223 $import = $this->importnew; 1224 } 1225 if (!isset($element)) { 1226 $element = 'th'; 1227 } 1228 1229 unset($this->params->elementObj); 1230 $this->params->import = $import; 1231 ODTTable::tableHeaderOpenUseCSS($this->params, $colspan, $rowspan, $element, $attributes); 1232 $this->params->import = $this->importnew; 1233 } 1234 1235 /** 1236 * Open a table header using properties. 1237 * 1238 * @see ODTTable::tableHeaderOpenUseProperties for detailed documentation 1239 */ 1240 function tableHeaderOpenUseProperties($properties, $colspan = 1, $rowspan = 1){ 1241 unset($this->params->elementObj); 1242 ODTTable::tableHeaderOpenUseProperties($this->params, $properties, $colspan, $rowspan); 1243 } 1244 1245 /** 1246 * Open a table row using CSS. 1247 * 1248 * @see ODTTable::tableRowOpenUseCSS for detailed documentation 1249 */ 1250 function tableRowOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 1251 if (!isset($import)) { 1252 $import = $this->importnew; 1253 } 1254 if (!isset($element)) { 1255 $element = 'tr'; 1256 } 1257 1258 unset($this->params->elementObj); 1259 $this->params->import = $import; 1260 ODTTable::tableRowOpenUseCSS($this->params, $element, $attributes); 1261 $this->params->import = $this->importnew; 1262 } 1263 1264 /** 1265 * Open a table row using properties. 1266 * 1267 * @see ODTTable::tableRowOpenUseProperties for detailed documentation 1268 */ 1269 function tableRowOpenUseProperties($properties){ 1270 unset($this->params->elementObj); 1271 ODTTable::tableRowOpenUseProperties($this->params, $properties); 1272 } 1273 1274 /** 1275 * Open a table cell using CSS. 1276 * 1277 * @see ODTTable::tableCellOpenUseCSS for detailed documentation 1278 */ 1279 function tableCellOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ 1280 if (!isset($import)) { 1281 $import = $this->importnew; 1282 } 1283 if (!isset($element)) { 1284 $element = 'td'; 1285 } 1286 1287 unset($this->params->elementObj); 1288 $this->params->import = $import; 1289 ODTTable::tableCellOpenUseCSS($this->params, $element, $attributes, $colspan, $rowspan); 1290 $this->params->import = $this->importnew; 1291 } 1292 1293 /** 1294 * Open a table cell using properties. 1295 * 1296 * @see ODTTable::tableCellOpenUseProperties for detailed documentation 1297 */ 1298 function tableCellOpenUseProperties($properties, $colspan = 1, $rowspan = 1){ 1299 unset($this->params->elementObj); 1300 ODTTable::tableCellOpenUseProperties($this->params, $properties, $colspan, $rowspan); 1301 } 1302 1303 /** 1304 * Open a text box in a frame using CSS. 1305 * 1306 * @see ODTFrame::openTextBoxUseCSS for detailed documentation 1307 */ 1308 function openTextBoxUseCSS ($element=NULL, $attributes=NULL, cssimportnew $import=NULL) { 1309 if (!isset($import)) { 1310 $import = $this->importnew; 1311 } 1312 if (!isset($element)) { 1313 $element = 'div'; 1314 } 1315 1316 unset($this->params->elementObj); 1317 $this->params->import = $import; 1318 ODTFrame::openTextBoxUseCSS($this->params, $element, $attributes); 1319 $this->params->import = $this->importnew; 1320 } 1321 1322 /** 1323 * Open a text box in a frame using properties. 1324 * 1325 * @see ODTFrame::openTextBoxUseProperties for detailed documentation 1326 */ 1327 function openTextBoxUseProperties ($properties) { 1328 unset($this->params->elementObj); 1329 ODTFrame::openTextBoxUseProperties($this->params, $properties); 1330 } 1331 1332 /** 1333 * This function closes a textbox. 1334 * 1335 * @see ODTFrame::closeTextBox for detailed documentation 1336 */ 1337 function closeTextBox () { 1338 unset($this->params->elementObj); 1339 ODTFrame::closeTextBox($this->params); 1340 } 1341 1342 /** 1343 * Open a frame using properties. 1344 * 1345 * @see ODTFrame::openFrameUseProperties for detailed documentation 1346 */ 1347 function openFrameUseProperties ($properties) { 1348 unset($this->params->elementObj); 1349 ODTFrame::openFrameUseProperties($this->params, $properties); 1350 } 1351 1352 /** 1353 * This function closes a textbox. 1354 * 1355 * @see ODTFrame::closeTextBox for detailed documentation 1356 */ 1357 function closeFrame () { 1358 unset($this->params->elementObj); 1359 ODTFrame::closeFrame($this->params); 1360 } 1361 1362 /** 1363 * Open a multi column text box in a frame using properties. 1364 * 1365 * @see ODTFrame::openMultiColumnTextBoxUseProperties for detailed documentation 1366 */ 1367 function openMultiColumnTextBoxUseProperties ($properties) { 1368 unset($this->params->elementObj); 1369 ODTFrame::openMultiColumnTextBoxUseProperties($this->params, $properties); 1370 } 1371 1372 /** 1373 * This function closes a multi column textbox. 1374 * 1375 * @see ODTFrame::closeTextBox for detailed documentation 1376 */ 1377 function closeMultiColumnTextBox () { 1378 unset($this->params->elementObj); 1379 ODTFrame::closeMultiColumnTextBox($this->params); 1380 } 1381 1382 /** 1383 * Change outline style to given value. 1384 * Currently only 'Numbers' is supported. Any other value will 1385 * not change anything. 1386 * 1387 * @param string $type Type of outline style to set 1388 */ 1389 public function setOutlineStyle ($type) { 1390 $outline_style = $this->getStyle('Outline'); 1391 if (!isset($outline_style)) { 1392 // Outline style not found! 1393 return; 1394 } 1395 switch ($type) { 1396 case 'Numbers': 1397 for ($level = 1 ; $level < 11 ; $level++) { 1398 $outline_style->setPropertyForLevel($level, 'num-format', '1'); 1399 $outline_style->setPropertyForLevel($level, 'num-suffix', NULL); 1400 $outline_style->setPropertyForLevel($level, 'num-prefix', NULL); 1401 $outline_style->setPropertyForLevel($level, 'display-levels', $level); 1402 } 1403 break; 1404 } 1405 } 1406 1407 /** 1408 * This function creates a text style for spans with the given properties. 1409 * If $common is true it will be added to the common styles otherwise it 1410 * will be dadded to the automatic styles. 1411 * 1412 * Common styles are visible for the user after export e.g. in LibreOffice 1413 * 'Styles and Formatting' view. Therefore they should have 1414 * $properties ['style-display-name'] set to a meaningfull name. 1415 * 1416 * @param $properties The properties to use 1417 * @param $common Add style to common or automatic styles? 1418 * @see ODTTextStyle::createTextStyle for more documentation 1419 */ 1420 public function createTextStyle ($properties, $common=true) { 1421 $style_obj = ODTTextStyle::createTextStyle($properties, NULL, $this); 1422 if ($common == true) { 1423 $this->addStyle($style_obj); 1424 } else { 1425 $this->addAutomaticStyle($style_obj); 1426 } 1427 } 1428 1429 /** 1430 * This function creates a paragraph style for paragraphs with the given properties. 1431 * If $common is true it will be added to the common styles otherwise it 1432 * will be dadded to the automatic styles. 1433 * 1434 * Common styles are visible for the user after export e.g. in LibreOffice 1435 * 'Styles and Formatting' view. Therefore they should have 1436 * $properties ['style-display-name'] set to a meaningfull name. 1437 * 1438 * @param $properties The properties to use 1439 * @param $common Add style to common or automatic styles? 1440 * @see ODTParagraphStyle::createParagraphStyle for more documentation 1441 */ 1442 public function createParagraphStyle ($properties, $common=true) { 1443 $style_obj = ODTParagraphStyle::createParagraphStyle($properties, NULL, $this); 1444 if ($common == true) { 1445 $this->addStyle($style_obj); 1446 } else { 1447 $this->addAutomaticStyle($style_obj); 1448 } 1449 } 1450 1451 /** 1452 * This function creates a table style for tables with the given properties. 1453 * If $common is true it will be added to the common styles otherwise it 1454 * will be dadded to the automatic styles. 1455 * 1456 * Common styles are visible for the user after export e.g. in LibreOffice 1457 * 'Styles and Formatting' view. Therefore they should have 1458 * $properties ['style-display-name'] set to a meaningfull name. 1459 * 1460 * @param $properties The properties to use 1461 * @param $common Add style to common or automatic styles? 1462 * @see ODTTableStyle::createTableTableStyle for more documentation 1463 */ 1464 public function createTableStyle ($properties, $common=true) { 1465 $style_obj = ODTTableStyle::createTableTableStyle($properties); 1466 if ($common == true) { 1467 $this->addStyle($style_obj); 1468 } else { 1469 $this->addAutomaticStyle($style_obj); 1470 } 1471 } 1472 1473 /** 1474 * This function creates a table row style for table rows with the given properties. 1475 * If $common is true it will be added to the common styles otherwise it 1476 * will be dadded to the automatic styles. 1477 * 1478 * Common styles are visible for the user after export e.g. in LibreOffice 1479 * 'Styles and Formatting' view. Therefore they should have 1480 * $properties ['style-display-name'] set to a meaningfull name. 1481 * 1482 * @param $properties The properties to use 1483 * @param $common Add style to common or automatic styles? 1484 * @see ODTTableRowStyle::createTableRowStyle for more documentation 1485 */ 1486 public function createTableRowStyle ($properties, $common=true) { 1487 $style_obj = ODTTableRowStyle::createTableRowStyle($properties); 1488 if ($common == true) { 1489 $this->addStyle($style_obj); 1490 } else { 1491 $this->addAutomaticStyle($style_obj); 1492 } 1493 } 1494 1495 /** 1496 * This function creates a table cell style for table cells with the given properties. 1497 * If $common is true it will be added to the common styles otherwise it 1498 * will be dadded to the automatic styles. 1499 * 1500 * Common styles are visible for the user after export e.g. in LibreOffice 1501 * 'Styles and Formatting' view. Therefore they should have 1502 * $properties ['style-display-name'] set to a meaningfull name. 1503 * 1504 * @param $properties The properties to use 1505 * @param $common Add style to common or automatic styles? 1506 * @see ODTTableCellStyle::createTableCellStyle for more documentation 1507 */ 1508 public function createTableCellStyle ($properties, $common=true) { 1509 $style_obj = ODTTableCellStyle::createTableCellStyle($properties); 1510 if ($common == true) { 1511 $this->addStyle($style_obj); 1512 } else { 1513 $this->addAutomaticStyle($style_obj); 1514 } 1515 } 1516 1517 /** 1518 * This function creates a table column style for table columns with the given properties. 1519 * If $common is true it will be added to the common styles otherwise it 1520 * will be dadded to the automatic styles. 1521 * 1522 * Common styles are visible for the user after export e.g. in LibreOffice 1523 * 'Styles and Formatting' view. Therefore they should have 1524 * $properties ['style-display-name'] set to a meaningfull name. 1525 * 1526 * @param $properties The properties to use 1527 * @param $common Add style to common or automatic styles? 1528 * @see ODTTableColumnStyle::createTableColumnStyle for more documentation 1529 */ 1530 public function createTableColumnStyle ($properties, $common=true) { 1531 $style_obj = ODTTableColumnStyle::createTableColumnStyle($properties); 1532 if ($common == true) { 1533 $this->addStyle($style_obj); 1534 } else { 1535 $this->addAutomaticStyle($style_obj); 1536 } 1537 } 1538 1539 /** 1540 * The function tries to examine the width and height 1541 * of the image stored in file $src. 1542 * 1543 * @see ODTUtility::getImageSize for a detailed description 1544 */ 1545 public function getImageSize($src, $maxwidth=NULL, $maxheight=NULL){ 1546 return ODTUtility::getImageSize($src, $maxwidth, $maxheight); 1547 } 1548 1549 /** 1550 * @param string $src 1551 * @param $width 1552 * @param $height 1553 * @return array 1554 */ 1555 public function getImageSizeString($src, $width = NULL, $height = NULL){ 1556 return ODTUtility::getImageSizeString($src, $width, $height, false, $this->params->units); 1557 } 1558 1559 /** 1560 * Adds an image $src to the document. 1561 * 1562 * @param string $src The path to the image file 1563 * @param string $width Width of the picture (NULL=original size) 1564 * @param string $height Height of the picture (NULL=original size) 1565 * @param string $align Alignment 1566 * @param string $title Title 1567 * @param string $style Optional "draw:style-name" 1568 * @param boolean $returnonly Only return code 1569 * 1570 * @see ODTImage::addImage for a detailed description 1571 */ 1572 public function addImage($src, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL, $returnonly = false){ 1573 if ($returnonly) { 1574 return ODTImage::addImage($this->params, $src, $width, $height, $align, $title, $style, $returnonly); 1575 } else { 1576 ODTImage::addImage($this->params, $src, $width, $height, $align, $title, $style, $returnonly); 1577 } 1578 } 1579 1580 /** 1581 * Adds an image $src to the document using the parameters set in $properties. 1582 * 1583 * @param string $src The path to the image file 1584 * @param array $properties Properties (width, height... see ODTImage::addImageUseProperties) 1585 * @param boolean $returnonly Only return code 1586 * 1587 * @see ODTImage::addImageUseProperties for a detailed description 1588 */ 1589 public function addImageUseProperties($src, $properties, $returnonly = false){ 1590 if ($returnonly) { 1591 return ODTImage::addImageUseProperties($this->params, $src, $properties, $returnonly); 1592 } else { 1593 ODTImage::addImageUseProperties($this->params, $src, $properties, $returnonly); 1594 } 1595 } 1596 1597 /** 1598 * The function adds $string as an SVG image file. 1599 * It does NOT insert the image in the document. 1600 * 1601 * @see ODTImage::addStringAsSVGImageFile for a detailed description 1602 */ 1603 public function addStringAsSVGImageFile($string) { 1604 return ODTImage::addStringAsSVGImageFile($this, $string); 1605 } 1606 1607 /** 1608 * Adds the content of $string as a SVG picture to the document. 1609 * 1610 * @see ODTImage::addStringAsSVGImage for a detailed description 1611 */ 1612 public function addStringAsSVGImage($string, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL) { 1613 return ODTImage::addStringAsSVGImage($this->params, $string, $width, $height, $align, $title, $style); 1614 } 1615 1616 /** 1617 * Get properties defined in a CSS style statement. 1618 * 1619 * @see ODTUtility::getCSSStylePropertiesForODT 1620 */ 1621 public function getCSSStylePropertiesForODT(&$properties, $style, $baseURL = NULL){ 1622 ODTUtility::getCSSStylePropertiesForODT($properties, $style, $baseURL, $this->units); 1623 } 1624 1625 /** 1626 * This function sets the page format for the FIRST page. 1627 * The format, orientation and page margins can be changed. 1628 * See function queryFormat() in ODT/page.php for supported formats. 1629 * 1630 * @param string $format e.g. 'A4', 'A3' 1631 * @param string $orientation e.g. 'portrait' or 'landscape' 1632 * @param numeric $margin_top Top-Margin in cm, default 2 1633 * @param numeric $margin_right Right-Margin in cm, default 2 1634 * @param numeric $margin_bottom Bottom-Margin in cm, default 2 1635 * @param numeric $margin_left Left-Margin in cm, default 2 1636 */ 1637 public function setStartPageFormat ($format=NULL, $orientation=NULL, $margin_top=NULL, $margin_right=NULL, $margin_bottom=NULL, $margin_left=NULL) { 1638 // Setup page format. 1639 // Set the page format of the current page for calculation ($this->page) 1640 $this->page->setFormat 1641 ($format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left); 1642 1643 // Change the standard page layout style 1644 $first_page = $this->getStyleByAlias('first page'); 1645 if (isset($first_page)) { 1646 $first_page->setProperty('width', $this->page->getWidth().'cm'); 1647 $first_page->setProperty('height', $this->page->getHeight().'cm'); 1648 $first_page->setProperty('margin-top', $this->page->getMarginTop().'cm'); 1649 $first_page->setProperty('margin-right', $this->page->getMarginRight().'cm'); 1650 $first_page->setProperty('margin-bottom', $this->page->getMarginBottom().'cm'); 1651 $first_page->setProperty('margin-left', $this->page->getMarginLeft().'cm'); 1652 } 1653 } 1654 1655 /** 1656 * This function sets the page format. 1657 * The format, orientation and page margins can be changed. 1658 * See function queryFormat() in ODT/page.php for supported formats. 1659 * 1660 * @param string $format e.g. 'A4', 'A3' 1661 * @param string $orientation e.g. 'portrait' or 'landscape' 1662 * @param numeric $margin_top Top-Margin in cm, default 2 1663 * @param numeric $margin_right Right-Margin in cm, default 2 1664 * @param numeric $margin_bottom Bottom-Margin in cm, default 2 1665 * @param numeric $margin_left Left-Margin in cm, default 2 1666 */ 1667 public function setPageFormat ($format=NULL, $orientation=NULL, $margin_top=NULL, $margin_right=NULL, $margin_bottom=NULL, $margin_left=NULL) { 1668 $data = array (); 1669 1670 // Fill missing values with current settings 1671 if ( empty($format) ) { 1672 $format = $this->page->getFormat(); 1673 } 1674 if ( empty($orientation) ) { 1675 $orientation = $this->page->getOrientation(); 1676 } 1677 if ( empty($margin_top) ) { 1678 $margin_top = $this->page->getMarginTop(); 1679 } 1680 if ( empty($margin_right) ) { 1681 $margin_right = $this->page->getMarginRight(); 1682 } 1683 if ( empty($margin_bottom) ) { 1684 $margin_bottom = $this->page->getMarginBottom(); 1685 } 1686 if ( empty($margin_left) ) { 1687 $margin_left = $this->page->getMarginLeft(); 1688 } 1689 1690 // Adjust given parameters, query resulting format data and get format-string 1691 $this->page->queryFormat ($data, $format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left); 1692 $format_string = $this->page->formatToString ($data['format'], $data['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); 1693 1694 if ( $format_string == $this->page->toString () ) { 1695 // Current page already uses this format, no need to do anything... 1696 return; 1697 } 1698 1699 if ($this->text_empty) { 1700 // If the text is still empty, then we change the start page format now. 1701 $this->page->setFormat($data ['format'], $data ['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); 1702 $first_page = $this->getStyleByAlias('first page'); 1703 if (isset($first_page)) { 1704 $first_page->setProperty('width', $this->page->getWidth().'cm'); 1705 $first_page->setProperty('height', $this->page->getHeight().'cm'); 1706 $first_page->setProperty('margin-top', $this->page->getMarginTop().'cm'); 1707 $first_page->setProperty('margin-right', $this->page->getMarginRight().'cm'); 1708 $first_page->setProperty('margin-bottom', $this->page->getMarginBottom().'cm'); 1709 $first_page->setProperty('margin-left', $this->page->getMarginLeft().'cm'); 1710 } 1711 } else { 1712 // Set marker and save data for pending change format. 1713 // The format change istelf will be done on the next call to p_open or header() 1714 // to prevent empty lines after the format change. 1715 $this->changePageFormat = $data; 1716 1717 // Close paragraph if open 1718 $this->paragraphClose(); 1719 } 1720 } 1721 1722 /** 1723 * Return total page width in centimeters 1724 * (margins are included) 1725 * 1726 * @author LarsDW223 1727 */ 1728 function getPageWidth(){ 1729 return $this->page->getWidth(); 1730 } 1731 1732 /** 1733 * Return total page height in centimeters 1734 * (margins are included) 1735 * 1736 * @author LarsDW223 1737 */ 1738 function getPageHeight(){ 1739 return $this->page->getHeight(); 1740 } 1741 1742 /** 1743 * Return left margin in centimeters 1744 * 1745 * @author LarsDW223 1746 */ 1747 function getLeftMargin(){ 1748 return $this->page->getMarginLeft(); 1749 } 1750 1751 /** 1752 * Return right margin in centimeters 1753 * 1754 * @author LarsDW223 1755 */ 1756 function getRightMargin(){ 1757 return $this->page->getMarginRight(); 1758 } 1759 1760 /** 1761 * Return top margin in centimeters 1762 * 1763 * @author LarsDW223 1764 */ 1765 function _getTopMargin(){ 1766 return $this->page->getMarginTop(); 1767 } 1768 1769 /** 1770 * Return bottom margin in centimeters 1771 * 1772 * @author LarsDW223 1773 */ 1774 function _getBottomMargin(){ 1775 return $this->page->getMarginBottom(); 1776 } 1777 1778 /** 1779 * Return width percentage value if margins are taken into account. 1780 * Usually "100%" means 21cm in case of A4 format. 1781 * But usually you like to take care of margins. This function 1782 * adjusts the percentage to the value which should be used for margins. 1783 * So 100% == 21cm e.g. becomes 80.9% == 17cm (assuming a margin of 2 cm on both sides). 1784 * 1785 * @author LarsDW223 1786 * 1787 * @param int|string $percentage 1788 * @return int|string 1789 */ 1790 function getRelWidthMindMargins ($percentage = '100'){ 1791 return $this->page->getRelWidthMindMargins($percentage); 1792 } 1793 1794 /** 1795 * Like _getRelWidthMindMargins but returns the absulute width 1796 * in centimeters. 1797 * 1798 * @author LarsDW223 1799 * @param string|int|float $percentage 1800 * @return float 1801 */ 1802 function getAbsWidthMindMargins ($percentage = '100'){ 1803 return $this->page->getAbsWidthMindMargins($percentage); 1804 } 1805 1806 /** 1807 * Return height percentage value if margins are taken into account. 1808 * Usually "100%" means 29.7cm in case of A4 format. 1809 * But usually you like to take care of margins. This function 1810 * adjusts the percentage to the value which should be used for margins. 1811 * So 100% == 29.7cm e.g. becomes 86.5% == 25.7cm (assuming a margin of 2 cm on top and bottom). 1812 * 1813 * @author LarsDW223 1814 * 1815 * @param string|float|int $percentage 1816 * @return float|string 1817 */ 1818 function getRelHeightMindMargins ($percentage = '100'){ 1819 return $this->page->getRelHeightMindMargins($percentage); 1820 } 1821 1822 /** 1823 * Like _getRelHeightMindMargins but returns the absulute width 1824 * in centimeters. 1825 * 1826 * @author LarsDW223 1827 * 1828 * @param string|int|float $percentage 1829 * @return float 1830 */ 1831 function getAbsHeightMindMargins ($percentage = '100'){ 1832 return $this->page->getAbsHeightMindMargins($percentage); 1833 } 1834 1835 /** 1836 * Sets the twips per pixel (X axis) used for px to pt conversion. 1837 * 1838 * @param int $value The value to be set. 1839 */ 1840 function setTwipsPerPixelX ($value) { 1841 $this->units->setTwipsPerPixelX ($value); 1842 } 1843 1844 /** 1845 * Sets the twips per pixel (Y axis) unit used for px to pt conversion. 1846 * 1847 * @param int $value The value to be set. 1848 */ 1849 function setTwipsPerPixelY ($value) { 1850 $this->units->setTwipsPerPixelY ($value); 1851 } 1852 1853 /** 1854 * Sets the pixel per em unit used for px to em conversion. 1855 * 1856 * @param int $value The value to be set. 1857 */ 1858 public function setPixelPerEm ($value) { 1859 $this->units->setPixelPerEm ($value); 1860 } 1861 1862 /** 1863 * Convert length value with valid XSL unit to points. 1864 * 1865 * @param string $value String with length value, e.g. '20px', '20cm'... 1866 * @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'. 1867 * Only relevant for conversion from 'px' or 'em'. 1868 * @return string The current value. 1869 */ 1870 public function toPoints ($value, $axis = 'y') { 1871 return $this->units->toPoints ($value, $axis); 1872 } 1873 1874 /** 1875 * Convert length value with valid XSL unit to pixel. 1876 * 1877 * @param string $value String with length value, e.g. '20pt', '20cm'... 1878 * @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'. 1879 * Only relevant for conversion from 'px' or 'em'. 1880 * @return string The current value. 1881 */ 1882 public function toPixel ($value, $axis = 'y') { 1883 return $this->units->toPixel ($value, $axis); 1884 } 1885 1886 public function setTitle ($title) { 1887 // Set title in meta info. 1888 $this->meta->setTitle($title); 1889 } 1890 1891 /** 1892 * Get closest previous TOC entry with $level. 1893 * The function search backwards (previous) in the TOC entries 1894 * for the next entry with level $level and retunrs it reference ID. 1895 * 1896 * @param int $level the nesting level 1897 * @return string The reference ID or NULL 1898 */ 1899 public function getPreviousToCItem($level) { 1900 $index = count($this->toc); 1901 for (; $index >= 0 ; $index--) { 1902 $item = $this->toc[$index]; 1903 $params = explode (',', $item); 1904 if ($params [3] == $level) { 1905 return $params [0]; 1906 } 1907 } 1908 return NULL; 1909 } 1910 1911 /** 1912 * Insert cross reference to a "destination" inside of the ODT document. 1913 * To insert a link to an external destination use insertHyperlink(). 1914 * 1915 * The function only inserts a placeholder and resolves 1916 * the reference on calling replaceLocalLinkPlaceholders(); 1917 * 1918 * @fixme add image handling 1919 * 1920 * @param string $destination The resource to link to (e.g. heading ID) 1921 * @param string $text Text for the link (text inserted instead of $destination) 1922 */ 1923 function insertCrossReference($destination, $text){ 1924 $this->content .= '<locallink name="'.$text.'">'.$destination.'</locallink>'; 1925 } 1926 1927 function openImageLink ($url, $returnonly = false) { 1928 $encoded = ''; 1929 if ($this->linksEnabled) { 1930 $url = ODTUtility::stringToIRI($url); 1931 $encoded = '<draw:a xlink:type="simple" xlink:href="'.$url.'">'; 1932 } 1933 if ($returnonly) { 1934 return $encoded; 1935 } 1936 $this->content .= $encoded; 1937 } 1938 1939 function closeImageLink ($returnonly = false) { 1940 $encoded = ''; 1941 if ($this->linksEnabled) { 1942 $encoded = '</draw:a>'; 1943 } 1944 if ($returnonly) { 1945 return $encoded; 1946 } 1947 $this->content .= $encoded; 1948 } 1949 1950 function openHyperlink ($url, $styleName = NULL, $visitedStyleName = NULL, $returnonly = false) { 1951 $encoded = ''; 1952 if ($url && $this->linksEnabled) { 1953 if (empty($styleName)) { 1954 $styleName = $this->getStyleName('internet link'); 1955 } 1956 if (empty($visitedStyleName)) { 1957 $visitedStyleName = $this->getStyleName('visited internet link'); 1958 } 1959 $url = ODTUtility::stringToIRI($url); 1960 $encoded .= '<text:a xlink:type="simple" xlink:href="'.$url.'"'; 1961 $encoded .= ' text:style-name="'.$styleName.'"'; 1962 $encoded .= ' text:visited-style-name="'.$visitedStyleName.'"'; 1963 $encoded .= '>'; 1964 } 1965 if ($returnonly) { 1966 return $encoded; 1967 } 1968 $this->content .= $encoded; 1969 } 1970 1971 function closeHyperlink ($returnonly = false) { 1972 $encoded = ''; 1973 if ($this->linksEnabled) { 1974 $encoded .= '</text:a>'; 1975 } 1976 if ($returnonly) { 1977 return $encoded; 1978 } 1979 $this->content .= $encoded; 1980 } 1981 1982 function insertHyperlink ($url, $text, $styleName = NULL, $visitedStyleName = NULL, $returnonly = false) { 1983 $encoded = ''; 1984 if ($url && $this->linksEnabled) { 1985 if (empty($styleName)) { 1986 $styleName = $this->getStyleName('internet link'); 1987 } 1988 if (empty($visitedStyleName)) { 1989 $visitedStyleName = $this->getStyleName('visited internet link'); 1990 } 1991 $url = ODTUtility::stringToIRI($url); 1992 $encoded .= '<text:a xlink:type="simple" xlink:href="'.$url.'"'; 1993 $encoded .= ' text:style-name="'.$styleName.'"'; 1994 $encoded .= ' text:visited-style-name="'.$visitedStyleName.'"'; 1995 $encoded .= '>'; 1996 } 1997 // We get the text already XML encoded 1998 $encoded .= $text; 1999 if ($url && $this->linksEnabled) { 2000 $encoded .= '</text:a>'; 2001 } 2002 if ($returnonly) { 2003 return $encoded; 2004 } 2005 $this->content .= $encoded; 2006 } 2007 2008 /** 2009 * Get CSS properties for a given element and adjust them for ODT. 2010 * 2011 * @param array $dest Properties found will be written in $dest as key value pairs, 2012 * e.g. $dest ['color'] = 'black'; 2013 * @param iElementCSSMatchable $element The element object for which the properties are queried. 2014 * The class of the element needs to implement the interface 2015 * iElementCSSMatchable. 2016 * @param string $media_sel The media selector to use for the query e.g. 'print'. May be empty. 2017 */ 2018 public function getODTProperties (array &$dest, $element, $attributes=NULL, $media_sel=NULL, $inherit=true) { 2019 if (!isset($this->importnew)) { 2020 return; 2021 } 2022 2023 $save = $this->importnew->getMedia(); 2024 $this->importnew->setMedia($media_sel); 2025 2026 $maxWidth = $this->getAbsWidthMindMargins().'cm'; 2027 ODTUtility::getHTMLElementProperties($this->params, $dest, $element, $attributes, $maxWidth, $inherit); 2028 2029 $this->importnew->setMedia($save); 2030 } 2031 2032 public function getODTPropertiesFromElement (array &$dest, iElementCSSMatchable $element, $media_sel=NULL, $inherit=true) { 2033 if (!isset($this->importnew)) { 2034 return; 2035 } 2036 2037 $save = $this->importnew->getMedia(); 2038 $this->importnew->setMedia($media_sel); 2039 2040 // Get properties for our class/element from imported CSS 2041 $this->importnew->getPropertiesForElement($dest, $element, $this->units, $inherit); 2042 2043 // Adjust values for ODT 2044 $maxWidth = $this->getAbsWidthMindMargins().'cm'; 2045 ODTUtility::adjustValuesForODT($dest, $this->units, $maxWidth); 2046 2047 $this->importnew->setMedia($save); 2048 } 2049 2050 public function adjustValuesForODT (array &$properties) { 2051 ODTUtility::adjustValuesForODT($properties, $this->units); 2052 } 2053 2054 public function adjustValueForODT ($property, $value) { 2055 return ODTUtility::adjustValueForODT($property, $value, $this->units); 2056 } 2057 2058 /** 2059 * Adds an $element with $attributes to the internal HTML stack for 2060 * CSS matching. HTML elments added from extern using this function 2061 * are supposed to never be closed so only root elements should be 2062 * added like 'html' or 'body' or maybe a 'div' that should always 2063 * be present for proper CSS matching. 2064 * 2065 * @param string $element The element name, e.g. 'body' 2066 * @param string $attributes The elements attributes, e.g. 'lang="en" dir="ltr"' 2067 */ 2068 public function addHTMLElement ($element, $attributes = NULL) { 2069 $this->htmlStack->open($element, $attributes); 2070 $this->htmlStack->saveRootIndex (); 2071 } 2072 2073 public function getHTMLStack () { 2074 return $this->htmlStack; 2075 } 2076 2077 public function dumpHTMLStack () { 2078 $this->trace_dump .= $this->htmlStack->getDump(); 2079 } 2080 2081 /** 2082 * Check if a file already exists in the document. 2083 * 2084 * @param string $fileName Full file name in the document 2085 * e.g. 'Pictures/myimage.png' 2086 * @return bool 2087 */ 2088 public function fileExists($name) { 2089 return $this->manifest->exists($name); 2090 } 2091 2092 /** 2093 * Add a file to the document. 2094 * 2095 * @param string $fileName Full file name in the document 2096 * e.g. 'Pictures/myimage.png' 2097 * @param string $mime Mime type 2098 * @param string $content The content of the file 2099 */ 2100 public function addFile($fileName, $mime, $content) { 2101 if(!$this->manifest->exists($fileName)){ 2102 $this->manifest->add($fileName, $mime); 2103 $this->ZIP->addData($fileName, $content); 2104 return true; 2105 } 2106 2107 // File with that name already exists! 2108 return false; 2109 } 2110 2111 /** 2112 * Adds the image $fileName as a picture file without adding it to 2113 * the content of the document. The link name which can be used for 2114 * the ODT draw:image xlink:href is returned. 2115 * 2116 * @param string $fileName 2117 * @return string 2118 */ 2119 function addFileAsPicture($fileName){ 2120 $name = ''; 2121 if (file_exists($fileName)) { 2122 list($ext,$mime) = mimetype($fileName); 2123 $name = 'Pictures/'.md5($fileName).'.'.$ext; 2124 $this->addFile($name, $mime, io_readfile($fileName,false)); 2125 } 2126 return $name; 2127 } 2128 2129 /** 2130 * Add style object to the document as a common style. 2131 * 2132 * @param ODTStyle $new Object to add 2133 */ 2134 public function addStyle(ODTStyle $new) { 2135 return $this->styleset->addStyle($new); 2136 } 2137 2138 /** 2139 * Add style object to the document as an automatic style. 2140 * 2141 * @param ODTStyle $new Object to add 2142 */ 2143 public function addAutomaticStyle(ODTStyle $new) { 2144 return $this->styleset->addAutomaticStyle($new); 2145 } 2146 2147 /** 2148 * Check if a style with $styleName already exists. 2149 * 2150 * @param string $styleName The style name ofthe style style. 2151 * @return bool 2152 */ 2153 public function styleExists ($name) { 2154 return $this->styleset->styleExists($name); 2155 } 2156 2157 /** 2158 * Get the style object with style name $styleName. 2159 * 2160 * @param string $styleName The style name ofthe style style. 2161 * @return ODTStyle The style object 2162 */ 2163 public function getStyle ($styleName) { 2164 return $this->styleset->getStyle($styleName); 2165 } 2166 2167 public function getDefaultStyle ($family) { 2168 return $this->styleset->getDefaultStyle($family); 2169 } 2170 2171 /** 2172 * Get the style name for a style alias. 2173 * 2174 * @param string $alias The alias for the style. 2175 * @return string The style name used in the ODT document 2176 */ 2177 public function getStyleName($alias) { 2178 return $this->styleset->getStyleName($alias); 2179 } 2180 2181 /** 2182 * The function returns the style at the given index 2183 * 2184 * @param $element Element of the style e.g. 'office:styles' 2185 * @return ODTStyle or NULL 2186 */ 2187 public function getStyleAtIndex($element, $index) { 2188 return $this->styleset->getStyleAtIndex($element, $index); 2189 } 2190 2191 /** 2192 * Get the style object by $alias. 2193 * 2194 * @param string $alias The alias for the style. 2195 * @return ODTStyle The style object 2196 */ 2197 public function getStyleByAlias($alias) { 2198 return $this->styleset->getStyle($this->styleset->getStyleName($alias)); 2199 } 2200 2201 public function registerHTMLElementForCSSImport ($style_type, $element, $attributes=NULL) { 2202 $this->registrations [$style_type]['element'] = $element; 2203 $this->registrations [$style_type]['attributes'] = $attributes; 2204 } 2205 2206 public function addToValue ($value, $add) { 2207 $valueInPt = $this->units->toPoints($value, 'y'); 2208 $valueInPt = $this->units->getDigits($valueInPt); 2209 $addInPt = $this->units->toPoints($add, 'y'); 2210 $addInPt = $this->units->getDigits($addInPt); 2211 return ($valueInPt + $addInPt).'pt'; 2212 } 2213 2214 public function subFromValue ($value, $sub) { 2215 $valueInPt = $this->units->toPoints($value, 'y'); 2216 $valueInPt = $this->units->getDigits($valueInPt); 2217 $subInPt = $this->units->toPoints($sub, 'y'); 2218 $subInPt = $this->units->getDigits($subInPt); 2219 return ($valueInPt - $subInPt).'pt'; 2220 } 2221 2222 /** 2223 * Adjust font sizes of all styles to $newBaseSize. 2224 * The $newBaseSize will be the new default font-size and all 2225 * other font-sizes will be re-calculated. 2226 * 2227 * @param string $newBaseSize The new base size e.g. '16pt' 2228 */ 2229 public function adjustFontSizes($newBaseSize) { 2230 // First get the old base size 2231 $default = $this->styleset->getDefaultStyle('paragraph'); 2232 if (!isset($default)) { 2233 // ??? 2234 return; 2235 } 2236 $oldBaseSize = $default->getProperty('font-size'); 2237 if (!isset($oldBaseSize)) { 2238 return; 2239 } 2240 $oldBaseSizeInPt = trim($this->units->toPoints($oldBaseSize, 'y'), 'pt'); 2241 2242 // Convert new base size to pt 2243 $newBaseSizeInPt = trim($this->units->toPoints($newBaseSize, 'y'), 'pt'); 2244 2245 $styles_list = array(); 2246 $styles_list [] = $this->styleset->getStyles(); 2247 $styles_list [] = $this->styleset->getAutomaticStyles(); 2248 $styles_list [] = $this->styleset->getMasterStyles(); 2249 2250 // Go through the list of style arrays and adjust each one 2251 // having a 'font-size' property 2252 foreach ($styles_list as $styles) { 2253 foreach ($styles as $style) { 2254 $fontSize = $style->getProperty('font-size'); 2255 if (isset($fontSize)) { 2256 $fontSizeInPt = trim($this->units->toPoints($fontSize, 'y'), 'pt'); 2257 $fontSizeInPt = ($fontSizeInPt/$oldBaseSizeInPt) * $newBaseSizeInPt; 2258 $fontSizeInPt = round($fontSizeInPt, 2); 2259 $style->setProperty('font-size', $fontSizeInPt.'pt'); 2260 } 2261 } 2262 } 2263 2264 $this->trace_dump .= 'newBaseSize: '.$newBaseSize."\n"; 2265 $this->trace_dump .= 'newBaseSizeInPt: '.$newBaseSizeInPt."\n"; 2266 // Also set default font-size to the new base size! 2267 $default->setProperty('font-size', $newBaseSizeInPt.'pt'); 2268 } 2269 2270 /** 2271 * The function sets the alignment and indentation for ordered lists. 2272 * This means the alignment of the numbers if front of each list item. 2273 * For each alignment predefined values for the attributes 'list-tab-stop-position', 2274 * 'text-indent' and 'margin-left' is set. 2275 * 2276 * @param string $align Alignment to set ('left'/'start', 'center', 'right'/'end') 2277 * @param integer $paddingLeft Left padding in centimeters, moves the whole list to the right 2278 * @param integer $marginLeft Left margin in centimeters, specifies the indent per level 2279 */ 2280 public function setOrderedListParams($setLevel=NULL, $align, $paddingLeft=0, $marginLeft=1) { 2281 if (empty($align)) { 2282 return; 2283 } 2284 $name = $this->styleset->getStyleName('numbering'); 2285 $style = $this->styleset->getStyle($name); 2286 if ( !isset($style) ) { 2287 return; 2288 } 2289 2290 if ( !isset($setLevel) ) { 2291 for ($level = 1 ; $level < 11 ; $level++) { 2292 switch ($align) { 2293 case 'left': 2294 case 'start': 2295 $dist = 1; 2296 $style->setPropertyForLevel($level, 'text-align', 'left'); 2297 break; 2298 case 'center': 2299 $dist = 0.5; 2300 $style->setPropertyForLevel($level, 'text-align', 'center'); 2301 break; 2302 case 'right': 2303 case 'end': 2304 default: 2305 $dist = 0.25; 2306 $style->setPropertyForLevel($level, 'text-align', 'end'); 2307 break; 2308 } 2309 $position = $paddingLeft + ($marginLeft * $level) + $dist; 2310 $style->setPropertyForLevel($level, 'list-level-position-and-space-mode', 'label-alignment'); 2311 $style->setPropertyForLevel($level, 'label-followed-by', 'listtab'); 2312 $style->setPropertyForLevel($level, 'list-tab-stop-position', $position.'cm'); 2313 $style->setPropertyForLevel($level, 'text-indent', ($dist*-1).'cm'); 2314 $style->setPropertyForLevel($level, 'margin-left', $position.'cm'); 2315 } 2316 } else { 2317 switch ($align) { 2318 case 'left': 2319 case 'start': 2320 $dist = 1; 2321 $style->setPropertyForLevel($setLevel, 'text-align', 'left'); 2322 break; 2323 case 'center': 2324 $dist = 0.5; 2325 $style->setPropertyForLevel($setLevel, 'text-align', 'center'); 2326 break; 2327 case 'right': 2328 case 'end': 2329 default: 2330 $dist = 0.25; 2331 $style->setPropertyForLevel($setLevel, 'text-align', 'end'); 2332 break; 2333 } 2334 $position = $paddingLeft + ($marginLeft * $setLevel) + $dist; 2335 $style->setPropertyForLevel($setLevel, 'list-level-position-and-space-mode', 'label-alignment'); 2336 $style->setPropertyForLevel($setLevel, 'label-followed-by', 'listtab'); 2337 $style->setPropertyForLevel($setLevel, 'list-tab-stop-position', $position.'cm'); 2338 $style->setPropertyForLevel($setLevel, 'text-indent', ($dist*-1).'cm'); 2339 $style->setPropertyForLevel($setLevel, 'margin-left', $position.'cm'); 2340 } 2341 } 2342 2343 /** 2344 * The function sets the alignment and indentation for unordered lists. 2345 * This means the alignment of the icons/buttons if front of each list item. 2346 * For each alignment predefined values for the attributes 'list-tab-stop-position', 2347 * 'text-indent' and 'margin-left' is set. 2348 * 2349 * @param string $align Alignment to set ('left'/'start', 'center', 'right'/'end') 2350 * @param integer $paddingLeft Left padding in centimeters, moves the whole list to the right 2351 * @param integer $marginLeft Left margin in centimeters, specifies the indent per level 2352 */ 2353 public function setUnorderedListParams($setLevel=NULL, $align, $paddingLeft=0, $marginLeft=1) { 2354 if (empty($align)) { 2355 return; 2356 } 2357 $name = $this->styleset->getStyleName('list'); 2358 $style = $this->styleset->getStyle($name); 2359 if ( !isset($style) ) { 2360 return; 2361 } 2362 2363 if ( !isset($setLevel) ) { 2364 for ($level = 1 ; $level < 11 ; $level++) { 2365 switch ($align) { 2366 case 'left': 2367 case 'start': 2368 $dist = 1; 2369 $style->setPropertyForLevel($level, 'text-align', 'left'); 2370 break; 2371 case 'center': 2372 $dist = 0.5; 2373 $style->setPropertyForLevel($level, 'text-align', 'center'); 2374 break; 2375 case 'right': 2376 case 'end': 2377 default: 2378 $dist = 0.25; 2379 $style->setPropertyForLevel($level, 'text-align', 'end'); 2380 break; 2381 } 2382 $position = $paddingLeft + ($marginLeft * $level) + $dist; 2383 $style->setPropertyForLevel($level, 'list-level-position-and-space-mode', 'label-alignment'); 2384 $style->setPropertyForLevel($level, 'label-followed-by', 'listtab'); 2385 $style->setPropertyForLevel($level, 'list-tab-stop-position', $position.'cm'); 2386 $style->setPropertyForLevel($level, 'text-indent', ($dist*-1).'cm'); 2387 $style->setPropertyForLevel($level, 'margin-left', $position.'cm'); 2388 } 2389 } else { 2390 switch ($align) { 2391 case 'left': 2392 case 'start': 2393 $dist = 1; 2394 $style->setPropertyForLevel($setLevel, 'text-align', 'left'); 2395 break; 2396 case 'center': 2397 $dist = 0.5; 2398 $style->setPropertyForLevel($setLevel, 'text-align', 'center'); 2399 break; 2400 case 'right': 2401 case 'end': 2402 default: 2403 $dist = 0.25; 2404 $style->setPropertyForLevel($setLevel, 'text-align', 'end'); 2405 break; 2406 } 2407 $position = $paddingLeft + ($marginLeft * $setLevel) + $dist; 2408 $style->setPropertyForLevel($setLevel, 'list-level-position-and-space-mode', 'label-alignment'); 2409 $style->setPropertyForLevel($setLevel, 'label-followed-by', 'listtab'); 2410 $style->setPropertyForLevel($setLevel, 'list-tab-stop-position', $position.'cm'); 2411 $style->setPropertyForLevel($setLevel, 'text-indent', ($dist*-1).'cm'); 2412 $style->setPropertyForLevel($setLevel, 'margin-left', $position.'cm'); 2413 } 2414 } 2415 2416 /** 2417 * Automatically generate ODT format for given $HTMLCode. 2418 * 2419 * @param string $HTMLCode 2420 * @see ODTUtility::generateODTfromHTMLCode for detailed documentation 2421 */ 2422 public function generateODTfromHTMLCode($HTMLCode, array $options){ 2423 ODTUtility::generateODTfromHTMLCode($this->params, $HTMLCode, $options); 2424 } 2425} 2426