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