state = new ODTState(); // Initialize HTML state $this->htmlStack = new cssdocument(); // Create default styles/styles storage. $this->styleset = new ODTDefaultStyles(); $this->styleset->import(); // Set standard page format: A4, portrait, 2cm margins $this->page = new pageFormat(); $this->setStartPageFormat ('A4', 'portrait', 2, 2, 2, 2); // Create units object and set default values $this->units = new ODTUnits(); $this->units->setPixelPerEm(16); $this->units->setTwipsPerPixelX(16); $this->units->setTwipsPerPixelY(20); // Setup meta data store/handler $this->meta = new ODTMeta(); // Setup manifest data $this->manifest = new ODTManifest(); // Prepare the zipper // (This instance is only for our to-be-created ODT-ZIP-Archive // - NOT to be used for extracting any ODT-Templates!) if (class_exists('\splitbrain\PHPArchive\Zip')) { $this->ZIP = new \splitbrain\PHPArchive\Zip(); $this->ZIP->create(); } $this->params = new ODTInternalParams(); } /** * Initialize the document. */ public function initialize () { $this->state->setDocument($this); $this->params->document = $this; $this->params->htmlStack = $this->htmlStack; $this->params->units = $this->units; $this->params->content = &$this->content; $this->params->ZIP = $this->ZIP; $this->params->manifest = $this->manifest; $this->params->styleset = $this->styleset; if (!isset($this->ZIP)) { return false; } return true; } /** * Set CSS usage. * * @param string $usage */ public function setCSSUsage ($usage) { switch (strtolower($usage)) { case 'basic': case 'full': $this->CSSUsage = $usage; break; default: $this->CSSUsage = 'off'; break; } } protected function setupImport() { if (!isset($this->importnew)) { // No CSS imported yet. Create object. $this->importnew = new cssimportnew(); if (!isset($this->importnew)) { return; } } $this->params->import = $this->importnew; } /** * Set commom CSS media selector. * * @param string $mediaSel */ public function setMediaSelector ($mediaSel) { if (!isset($this->importnew)) { $this->setupImport(); } $this->importnew->setMedia ($mediaSel); } /** * Callback function which adjusts all CSS length values to point. * * @param $property The name of the current CSS property, e.g. 'border-left' * @param $value The current value from the original CSS code * @param $type There are 3 possible values: * - LengthValueXAxis: the property represents a value on the X axis * - LengthValueYAxis: the property represents a value on the Y axis * - CSSValueType::StrokeOrBorderWidth: the property represents a stroke * or border width * @return string The new, adjusted value for the property */ public function adjustLengthCallback ($property, $value, $type, $rule) { // Get the digits and unit $digits = ODTUnits::getDigits($value); $unit = ODTUnits::stripDigits($value); if ( $unit == 'px' ) { // Replace px with pt (px does not seem to be supported by ODT) switch ($type) { case CSSValueType::LengthValueXAxis: $adjusted = $this->toPoints($value, 'x'); break; case CSSValueType::StrokeOrBorderWidth: switch ($property) { case 'border': case 'border-left': case 'border-right': case 'border-top': case 'border-bottom': // border in ODT spans does not support 'px' units, so we convert it. $adjusted = $this->toPoints($value, 'y'); break; default: $adjusted = $value; break; } break; case CSSValueType::LengthValueYAxis: default: switch ($property) { case 'line-height': $adjusted = $this->toPoints($value, 'y'); break; default: $adjusted = $this->toPoints($value, 'y'); break; } break; } return $adjusted; } else { if ($property == 'line-height' && $value != 'normal') { if ($unit == '%' || empty($unit)) { // Relative values must be handled later return $value; } $adjusted = $this->toPoints($value, 'y'); return $adjusted; } return $value; } return $value; } public function replaceURLPrefixes ($callback) { if (isset($this->importnew)) { $this->importnew->replaceURLPrefixes ($callback); } } public function enableLinks () { $this->linksEnabled = true; } public function disableLinks () { $this->linksEnabled = false; } // Functions generating content for now will have to be passed // $renderer->doc. Later this will be removed and an internal doc // variable will be maintained. This will break backwards compatibility // with plugins writing to $renderer->doc directly (instead of calling cdata). /** * Render plain text data * * @param string $text */ function addPlainText($text) { // Check if there is some content in the text. // Only insert bookmark/pagebreak/format change if text is not empty. // Otherwise a empty paragraph/line would be created! if ( !empty($text) && !ctype_space($text) ) { // Insert page bookmark if requested and not done yet. $this->insertPendingPageBookmark(); // Insert pagebreak or page format change if still pending. // Attention: NOT if $text is empty. This would lead to empty lines before headings // right after a pagebreak! $in_paragraph = $this->state->getInParagraph(); if ( ($this->pagebreakIsPending() || $this->pageFormatChangeIsPending()) || !$in_paragraph ) { $this->paragraphOpen(); } } $this->content .= $this->replaceXMLEntities($text); if ($this->text_empty && !ctype_space($text)) { $this->text_empty = false; } } /** * Open a text span. * * @param string $styleName The style to use. * @see ODTSpan::spanOpen for detailed documentation */ function spanOpen($styleName, $element=NULL, $attributes=NULL){ $in_paragraph = $this->state->getInParagraph(); if ( !$in_paragraph ) { $this->paragraphOpen(); } unset($this->params->elementObj); ODTSpan::spanOpen($this->params, $styleName, $element, $attributes); } /** * Open a text span using CSS. * * @see ODTSpan::spanOpenUseCSS for detailed documentation */ function spanOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ $in_paragraph = $this->state->getInParagraph(); if ( !$in_paragraph ) { $this->paragraphOpen(); } if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'span'; } unset($this->params->elementObj); $this->params->import = $import; ODTSpan::spanOpenUseCSS($this->params, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a text span using properties. * * @see ODTSpan::spanOpenUseProperties for detailed documentation */ function spanOpenUseProperties($properties){ $in_paragraph = $this->state->getInParagraph(); if ( !$in_paragraph ) { $this->paragraphOpen(); } ODTUtility::adjustValuesForODT($properties, $this->units); unset($this->params->elementObj); ODTSpan::spanOpenUseProperties($this->params, $properties); } /** * Close a text span. * * @param string $style_name The style to use. * @see ODTSpan::spanClose for detailed documentation */ function spanClose() { unset($this->params->elementObj); ODTSpan::spanClose($this->params); } /** * Automatically generate ODT format for $HTMLCode * including text spans. * * @param string $style_name The style to use. * @see ODTSpan::generateSpansfromHTMLCode for detailed documentation */ function generateSpansfromHTMLCode($HTMLCode){ ODTSpan::generateSpansfromHTMLCode($this->params, $HTMLCode); } /** * Open a paragraph * * @param string $styleName The style to use. * @see ODTParagraph::paragraphOpen for detailed documentation */ function paragraphOpen($styleName=NULL, $element=NULL, $attributes=NULL){ unset($this->params->elementObj); ODTParagraph::paragraphOpen($this->params, $styleName, $element, $attributes); } /** * Close a paragraph * * @see ODTParagraph::paragraphClose for detailed documentation */ function paragraphClose(){ unset($this->params->elementObj); ODTParagraph::paragraphClose($this->params); } /** * Open a paragraph using CSS. * * @see ODTParagraph::paragraphOpenUseCSS for detailed documentation */ function paragraphOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'p'; } unset($this->params->elementObj); $this->params->import = $import; ODTParagraph::paragraphOpenUseCSS($this->params, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a paragraph using properties. * * @see ODTParagraph::paragraphOpenUseProperties for detailed documentation */ function paragraphOpenUseProperties($properties){ ODTUtility::adjustValuesForODT($properties, $this->units); unset($this->params->elementObj); ODTParagraph::paragraphOpenUseProperties($this->params, $properties); } /** * Insert a horizontal rule */ function horizontalRule() { $this->paragraphClose(); $styleName = $this->getStyleName('horizontal line'); $this->paragraphOpen($styleName); $this->paragraphClose(); // Save paragraph style name in 'Do not delete array'! $this->preventDeletetionStyles [] = $styleName; } /** * static call back to replace spaces * * @param array $matches * @return string */ function _preserveSpace($matches){ $spaces = $matches[1]; $len = strlen($spaces); return ''; } /** * @param string $text * @param string $style * @param bool $notescaped */ function addPreformattedText($text, $style=null, $notescaped=true) { if (empty($style)) { $style = $this->getStyleName('preformatted'); } if ($notescaped) { $text = $this->replaceXMLEntities($text); } // Check newline at start $first_newline = strpos($text, "\n"); if ($first_newline !== FALSE and $first_newline == 0) { // text starts with a newline, remove it $text = substr($text,1); } // Check newline at end $length = strlen($text); if ($text[$length-1] == "\n") { $text = substr($text, 0, $length-1); } $text = str_replace("\n",'',$text); $text = str_replace("\t",'',$text); $text = preg_replace_callback('/( +)/',array($this,'_preserveSpace'),$text); $list_item = $this->state->getCurrentListItem(); if (isset($list_item)) { // if we're in a list item, we must close the tag $this->paragraphClose(); $this->paragraphOpen($style); $this->content .= $text; $this->paragraphClose(); // FIXME: query previous style before preformatted text was opened and re-use it here $this->paragraphOpen(); } else { $this->paragraphClose(); $this->paragraphOpen($style); $this->content .= $text; $this->paragraphClose(); } } /** * Add a linebreak */ function linebreak() { $this->content .= ''; } /** * Add a pagebreak */ function pagebreak() { // Only set marker to insert a pagebreak on "next occasion". // The pagebreak will then be inserted in the next call to p_open() or header(). // The style will be a "pagebreak" style with the paragraph or header style as the parent. // This prevents extra empty lines after the pagebreak. $this->paragraphClose(); $this->pagebreak = true; } /** * Check if a pagebreak is pending * * @return bool */ function pagebreakIsPending() { return $this->pagebreak; } /** * Check if a page format change is pending * * @return bool */ function pageFormatChangeIsPending() { if (isset($this->changePageFormat)) { return true; } return false; } /** * Set pagebreak pending. * * @return bool */ function setPagebreakPending($value) { return $this->pagebreak = $value; } /** * Check if a header with $title exists. * * @return bool */ function headerExists($title) { return in_array($title, $this->headers); } /** * Add $title to headers. * * @return bool */ function addHeader($title) { $this->headers[] = $title; } /** * Insert an index into the document using the parameters in $settings. * * @see ODTIndex::insertIndex for detailed documentation */ function insertIndex($type='toc', array $settings=NULL) { ODTIndex::insertIndex($this->params, $this->indexesData, $type, $settings); } /** * Creates a reference ID for the TOC * * @param string $title The headline/item title * @return string * * @author LarsDW223 */ public function buildTOCReferenceID($title) { // FIXME: not DokuWiki dependant function woud be nicer... $title = str_replace(':','',cleanID($title)); $title = ltrim($title,'0123456789._-'); if(empty($title)) { $title='NoTitle'; } $this->refIDCount++; // The reference ID needs to start with '__RefHeading___'. // Otherwise LibreOffice will display $ref instead of the heading // name when moving the mouse over the link in the TOC. $ref = '__RefHeading___'.$title.'_'.$this->refIDCount; return $ref; } /** * Add an item to the TOC * * @param string $refID the reference ID * @param string $hid the hash link * @param string $text the text to display * @param int $level the nesting level */ function tocAddItemInternal($refID, $hid, $text, $level) { $item = $refID.','.$hid.','.$text.','. $level; $this->toc[] = $item; } /** * Set bookmark for the start of the page. This just saves the title temporarily. * It is then to be inserted in the first header or paragraph. * * @param string $id ID of the bookmark */ function setPageBookmark($id){ $inParagraph = $this->state->getInParagraph(); if ($inParagraph) { $this->insertBookmarkInternal($id, true); } else { $this->pageBookmark = $id; } } /** * Insert a bookmark. If $now is true then the bookmark will be created * immediately. This eventually causes a paragraph to be opened. * If $now is false then the bookmark will be inserted with the next * cdata text. * * @param string $id ID of the bookmark * @param string $now Insert bookmark immediately? */ public function insertBookmark($id, $now) { if ($now) { $this->insertBookmarkInternal($id); } else { $this->pageBookmark = $id; } } /** * Insert a bookmark. * * @param string $id ID of the bookmark */ protected function insertBookmarkInternal($id, $openParagraph=true){ if ($openParagraph) { $this->paragraphOpen(); } $this->content .= ''; $this->bookmarks [] = $id; } /** * Insert a pending page bookmark * * @param string $text the text to display * @param int $level header level * @param int $pos byte position in the original source */ function insertPendingPageBookmark(){ // Insert page bookmark if requested and not done yet. if ( !empty($this->pageBookmark) ) { $this->insertBookmarkInternal($this->pageBookmark, false); $this->pageBookmark = NULL; } } /** * Render a heading. * * @param string $text the text to display * @param int $level header level * @param int $pos byte position in the original source * @see ODTHeading::heading for detailed documentation */ function heading($text, $level, $element=NULL, $attributes=NULL){ ODTHeading::heading($this->params, $text, $level, $element, $attributes); } /** * Make sure that a user field name only contains valid sings. * (Code has been adopted from the fields plugin) * * @param string $name The name of the field * @return string The cleaned up $name * @author Aurelien Bompard */ protected function cleanupUserFieldName($name) { // Keep only allowed chars in the name return preg_replace('/[^a-zA-Z0-9_.]/', '', $name); } /** * Add a user field. * (Code has been adopted from the fields plugin) * * @param string $name The name of the field * @param string $value The value of the field * @author Aurelien Bompard */ public function addUserField($name, $value) { $name = $this->cleanupUserFieldName($name); $this->fields [$name] = $value; } /** * Insert a user field reference. * (Code has been adopted from the fields plugin) * * @param string $name The name of the field * @author Aurelien Bompard */ public function insertUserField($name) { $name = $this->cleanupUserFieldName($name); if (array_key_exists($name, $this->fields)) { $this->content .= ''.$this->fields [$name].''; } } /** * This function encodes the section of a * ODT document. * * @return string */ protected function getUserFieldDecls() { $value = ''; foreach ($this->fields as $fname => $fvalue) { $value .= ''; } $value .= ''; return $value; } /** * Get ODT file as string (ZIP archive). * * @param string $content The content * @return string String containing ODT ZIP stream */ public function getODTFileAsString($ODTtemplate=NULL, $tempDir=NULL) { // Close any open paragraph if not done yet. $this->paragraphClose(); // Replace local link placeholders with links to headings or bookmarks $styleName = $this->getStyleName('local link'); $visitedStyleName = $this->getStyleName('visited local link'); ODTUtility::replaceLocalLinkPlaceholders($this->content, $this->toc, $this->bookmarks, $styleName, $visitedStyleName); // Build indexes ODTIndex::replaceIndexesPlaceholders($this->params, $this->indexesData, $this->toc); // Delete paragraphs which only contain whitespace (but keep pagebreaks!) ODTUtility::deleteUselessElements($this->content, $this->preventDeletetionStyles); //$this->trace_dump .= $this->htmlStack->getDump(); //$this->trace_dump .= $this->importnew->rulesToString(); if (!empty($this->trace_dump)) { $this->paragraphOpen(); $this->linebreak(); $this->content .= 'Tracedump: '; $this->addPreformattedText($this->trace_dump); $this->paragraphClose(); } // Get meta content $metaContent = $this->meta->getContent(); // Get user field declarations $userFieldDecls = $this->getUserFieldDecls(); // Build the document ODTExport::buildZIPFile($this->params, $metaContent, $userFieldDecls, $this->pageStyles, $ODTtemplate, $tempDir); // Return document return $this->ZIP->getArchive(); } /** * Import CSS code for styles from a string. * * @param string $cssCode The CSS code to import * @param string $mediaSel The media selector to use e.g. 'print' * @param string $mediaPath Local path to media files */ public function importCSSFromString($cssCode, $mediaSel=NULL, $URLCallback=NULL, $forceStyles=false, $listAlign='right') { // Import CSS as styles? $importStyles = false; if ($this->CSSUsage == 'basic' || $this->CSSUsage == 'full' || $forceStyles) { $importStyles = true; } ODTImport::importCSSFromString ($this->params, $cssCode, $mediaSel, array($this, 'adjustLengthCallback'), $URLCallback, $this->registrations, $importStyles, $listAlign); } /** * Import CSS code for styles from a file. * * @param string $CSSTemplate String containing the path and file name of the CSS file to import * @param string $mediaSel The media selector to use e.g. 'print' * @param string $mediaPath Local path to media files */ public function importCSSFromFile($CSSTemplate, $mediaSel=NULL, $URLCallback=NULL, $listAlign='right') { // Import CSS as styles? $importStyles = false; if ($this->CSSUsage == 'basic' || $this->CSSUsage == 'full') { $importStyles = true; } ODTImport::importCSSFromFile ($this->params, $CSSTemplate, $mediaSel, array($this, 'adjustLengthCallback'), $URLCallback, $this->registrations, $importStyles, $listAlign); } public function importODTStyles($template=NULL, $tempDir=NULL) { ODTImport::importODTStyles($this->params, $template, $tempDir); } /** * General internal function for closing an element. * Can always be used to close any open element if no more actions * are required apart from generating the closing tag and * removing the element from the state stack. */ public function closeCurrentElement() { $current = $this->state->getCurrent(); if (isset($current)) { $this->content .= $current->getClosingTag($this->content); $this->state->leave(); } } /** * This function creates a style for changing the page format if required. * It returns NULL if no page format change is pending or if the current * page format is equal to the required page format. * * @param string $parent Parent style name. * @return string Name of the style to be used for changing page format * * FIXME: make protected as soon as function header is moved here also! */ public function doPageFormatChange ($parent = NULL) { if ( !isset($this->changePageFormat) ) { // Error. return NULL; } $data = $this->changePageFormat; $this->changePageFormat = NULL; if ( empty($parent) ) { $parent = 'Standard'; } // Create page layout style $format_string = $this->page->formatToString ($data['format'], $data['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); $properties ['style-name'] = 'Style-Page-'.$format_string; $properties ['width'] = $data ['width']; $properties ['height'] = $data ['height']; $properties ['margin-top'] = $data ['margin-top']; $properties ['margin-bottom'] = $data ['margin-bottom']; $properties ['margin-left'] = $data ['margin-left']; $properties ['margin-right'] = $data ['margin-right']; $style_obj = ODTPageLayoutStyle::createPageLayoutStyle($properties); $style_name = $style_obj->getProperty('style-name'); // It is iassumed the proper media selector has been set by calling setMediaSelector() if (($this->CSSUsage == 'basic' || $this->CSSUsage == 'full') && isset($this->importnew)) { ODTImport::set_page_properties($this->params, $style_obj); } // Save style data in page style array, in common styles and set current page format $master_page_style_name = $format_string; $this->pageStyles [$master_page_style_name] = $style_name; $this->addAutomaticStyle($style_obj); $this->page->setFormat($data ['format'], $data ['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); // Create paragraph style. $properties = array(); $properties ['style-name'] = 'Style-'.$format_string; $properties ['style-parent'] = $parent; $properties ['style-master-page-name'] = $master_page_style_name; $properties ['page-number'] = 'auto'; $style_obj = ODTParagraphStyle::createParagraphStyle($properties); $style_name = $style_obj->getProperty('style-name'); $this->addAutomaticStyle($style_obj); // Save paragraph style name in 'Do not delete array'! $this->preventDeletetionStyles [] = $style_name; return $style_name; } public function createPagebreakStyle($parent=NULL,$before=true) { $style_name = 'pagebreak'; if ( !$before ) { $style_name .= '_after'; } if ( !empty($parent) ) { $style_name .= '_'.$parent; } if ( !$this->styleExists($style_name) ) { $style_obj = ODTParagraphStyle::createPagebreakStyle($style_name, $parent, $before); $this->addAutomaticStyle($style_obj); // Save paragraph style name in 'Do not delete array'! $this->preventDeletetionStyles [] = $style_name; } return $style_name; } /** * Replace XML entities * * @param string $value * @return string */ function replaceXMLEntities($value) { return str_replace( array('&','"',"'",'<','>'), array('&','"',''','<','>'), $value); } /** * Open/start a footnote. * * @author Andreas Gohr * @see ODTFootnote::footnoteOpen for detailed documentation */ function footnoteOpen() { ODTFootnote::footnoteOpen($this->params); } /** * Close/end a footnote. * * @author Andreas Gohr * @see ODTFootnote::footnoteClose for detailed documentation */ function footnoteClose() { ODTFootnote::footnoteClose($this->params); } function quoteOpen() { // Do not go higher than 5 because only 5 quotation styles are defined. if ( $this->quote_depth < 5 ) { $this->quote_depth++; } unset($this->params->elementObj); ODTTable::tableOpen($this->params, 1, 1, 'Table_Quotation'.$this->quote_depth, 'blockquote', NULL); $this->tableRowOpen(); unset($this->params->elementObj); ODTTable::tableCellOpen($this->params, 1, 1, 'left', 'Cell_Quotation'.$this->quote_depth, NULL, NULL, NULL); } function quoteClose() { $this->paragraphClose(); $this->tableCellClose(); $this->tableRowClose(); $this->tableClose(); if ( $this->quote_depth > 0 ) { $this->quote_depth--; } } /** * Opens a list. * The list style specifies if the list is an ordered or unordered list. * * @param bool $continue Continue numbering? * @param string $styleName Name of style to use for the list * @see ODTList::listOpen for detailed documentation */ function listOpen($continue=false, $styleName, $element=NULL, $attributes=NULL) { if (!isset($element)) { if ($styleName == $this->getStyleName('list')) { $element = 'ul'; } if ($styleName == $this->getStyleName('numbering')) { $element = 'ol'; } } ODTList::listOpen($this->params, $continue, $styleName, $element, $attributes); } /** * Close a list. * * @see ODTList::listClose for detailed documentation */ function listClose() { ODTList::listClose($this->params); } /** * Open a list item. * * @param int $level The nesting level * @see ODTList::listItemOpen for detailed documentation */ function listItemOpen($level, $element=NULL, $attributes=NULL) { ODTList::listItemOpen($this->params, $level, $element, $attributes); } /** * Close a list item. * * @see ODTList::listItemClose for detailed documentation */ function listItemClose() { ODTList::listItemClose($this->params); } /** * Open a list header. * * @param int $level The nesting level * @see ODTList::listHeaderOpen for detailed documentation */ function listHeaderOpen($level, $element=NULL, $attributes=NULL) { ODTList::listHeaderOpen($this->params, $level, $element, $attributes); } /** * Close a list header. * * @see ODTList::listHeaderClose for detailed documentation */ function listHeaderClose() { ODTList::listHeaderClose($this->params); } /** * Open list content/a paragraph in a list item. * * @see ODTList::listContentOpen for detailed documentation */ function listContentOpen($element=NULL, $attributes=NULL) { ODTList::listContentOpen($this->params, $element, $attributes); } /** * Close list content/a paragraph in a list item. * * @see ODTList::listContentClose for detailed documentation */ function listContentClose() { ODTList::listContentClose($this->params); } /** * Open/start a table. * * @param int $maxcols maximum number of columns * @param int $numrows NOT IMPLEMENTED * @see ODTTable::tableOpen for detailed documentation */ function tableOpen($maxcols = NULL, $numrows = NULL, $element=NULL, $attributes=NULL){ unset($this->params->elementObj); ODTTable::tableOpen($this->params, $maxcols, $numrows, NULL, $element, $attributes); } /** * Close/finish a table. * * @param int $maxcols maximum number of columns * @param int $numrows NOT IMPLEMENTED * @see ODTTable::tableClose for detailed documentation */ function tableClose(){ unset($this->params->elementObj); ODTTable::tableClose($this->params); } /** * Add a column to a table. * * @see ODTTable::tableAddColumn for detailed documentation */ function tableAddColumn (){ unset($this->params->elementObj); ODTTable::tableAddColumn ($this->params); } /** * Open a table row. * * @see ODTTable::tableRowOpen for detailed documentation */ function tableRowOpen($element=NULL, $attributes=NULL){ unset($this->params->elementObj); ODTTable::tableRowOpen($this->params, NULL, $element, $attributes); } /** * Close a table row. * * @see ODTTable::tableRowClose for detailed documentation */ function tableRowClose(){ unset($this->params->elementObj); ODTTable::tableRowClose($this->params); } /** * Open a table header cell. * * @see ODTTable::tableHeaderOpen for detailed documentation */ function tableHeaderOpen($colspan = 1, $rowspan = 1, $align, $element=NULL, $attributes=NULL){ unset($this->params->elementObj); ODTTable::tableHeaderOpen($this->params, $colspan, $rowspan, $align, NULL, NULL, $element, $attributes); } /** * Close a table header cell. * * @see ODTTable::tableHeaderClose for detailed documentation */ function tableHeaderClose(){ unset($this->params->elementObj); ODTTable::tableHeaderClose($this->params); } /** * Open a table cell. * * @see ODTTable::tableCellOpen for detailed documentation */ function tableCellOpen($colspan, $rowspan, $align, $element=NULL, $attributes=NULL){ unset($this->params->elementObj); ODTTable::tableCellOpen($this->params, $colspan, $rowspan, $align, NULL, NULL, $element, $attributes); } /** * Close a table cell. * * @see ODTTable::tableCellClose for detailed documentation */ function tableCellClose(){ unset($this->params->elementObj); ODTTable::tableCellClose($this->params); } /** * Open a table using CSS. * * @see ODTTable::tableOpenUseCSS for detailed documentation */ function tableOpenUseCSS($maxcols=NULL, $numrows=NULL, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'table'; } unset($this->params->elementObj); $this->params->import = $import; ODTTable::tableOpenUseCSS($this->params, $maxcols, $numrows, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a table using properties. * * @see ODTTable::tableOpenUseProperties for detailed documentation */ function tableOpenUseProperties ($properties, $maxcols = 0, $numrows = 0){ unset($this->params->elementObj); ODTTable::tableOpenUseProperties($this->params, $properties, $maxcols, $numrows); } /** * Add a table column using properties. * * @see ODTTable::tableAddColumnUseProperties for detailed documentation */ function tableAddColumnUseProperties ($properties){ unset($this->params->elementObj); ODTTable::tableAddColumnUseProperties($this->params, $properties); } /** * Open a table header using CSS. * * @see ODTTable::tableHeaderOpenUseCSS for detailed documentation */ function tableHeaderOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'th'; } unset($this->params->elementObj); $this->params->import = $import; ODTTable::tableHeaderOpenUseCSS($this->params, $colspan, $rowspan, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a table header using properties. * * @see ODTTable::tableHeaderOpenUseProperties for detailed documentation */ function tableHeaderOpenUseProperties($properties, $colspan = 1, $rowspan = 1){ unset($this->params->elementObj); ODTTable::tableHeaderOpenUseProperties($this->params, $properties, $colspan, $rowspan); } /** * Open a table row using CSS. * * @see ODTTable::tableRowOpenUseCSS for detailed documentation */ function tableRowOpenUseCSS($element=NULL, $attributes=NULL, cssimportnew $import=NULL){ if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'tr'; } unset($this->params->elementObj); $this->params->import = $import; ODTTable::tableRowOpenUseCSS($this->params, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a table row using properties. * * @see ODTTable::tableRowOpenUseProperties for detailed documentation */ function tableRowOpenUseProperties($properties){ unset($this->params->elementObj); ODTTable::tableRowOpenUseProperties($this->params, $properties); } /** * Open a table cell using CSS. * * @see ODTTable::tableCellOpenUseCSS for detailed documentation */ function tableCellOpenUseCSS($colspan = 1, $rowspan = 1, $element=NULL, $attributes=NULL, cssimportnew $import=NULL){ if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'td'; } unset($this->params->elementObj); $this->params->import = $import; ODTTable::tableCellOpenUseCSS($this->params, $element, $attributes, $colspan, $rowspan); $this->params->import = $this->importnew; } /** * Open a table cell using properties. * * @see ODTTable::tableCellOpenUseProperties for detailed documentation */ function tableCellOpenUseProperties($properties, $colspan = 1, $rowspan = 1){ unset($this->params->elementObj); ODTTable::tableCellOpenUseProperties($this->params, $properties, $colspan, $rowspan); } /** * Open a text box in a frame using CSS. * * @see ODTFrame::openTextBoxUseCSS for detailed documentation */ function openTextBoxUseCSS ($element=NULL, $attributes=NULL, cssimportnew $import=NULL) { if (!isset($import)) { $import = $this->importnew; } if (!isset($element)) { $element = 'div'; } unset($this->params->elementObj); $this->params->import = $import; ODTFrame::openTextBoxUseCSS($this->params, $element, $attributes); $this->params->import = $this->importnew; } /** * Open a text box in a frame using properties. * * @see ODTFrame::openTextBoxUseProperties for detailed documentation */ function openTextBoxUseProperties ($properties) { unset($this->params->elementObj); ODTFrame::openTextBoxUseProperties($this->params, $properties); } /** * This function closes a textbox. * * @see ODTFrame::closeTextBox for detailed documentation */ function closeTextBox () { unset($this->params->elementObj); ODTFrame::closeTextBox($this->params); } /** * Open a frame using properties. * * @see ODTFrame::openFrameUseProperties for detailed documentation */ function openFrameUseProperties ($properties) { unset($this->params->elementObj); ODTFrame::openFrameUseProperties($this->params, $properties); } /** * This function closes a textbox. * * @see ODTFrame::closeTextBox for detailed documentation */ function closeFrame () { unset($this->params->elementObj); ODTFrame::closeFrame($this->params); } /** * Open a multi column text box in a frame using properties. * * @see ODTFrame::openMultiColumnTextBoxUseProperties for detailed documentation */ function openMultiColumnTextBoxUseProperties ($properties) { unset($this->params->elementObj); ODTFrame::openMultiColumnTextBoxUseProperties($this->params, $properties); } /** * This function closes a multi column textbox. * * @see ODTFrame::closeTextBox for detailed documentation */ function closeMultiColumnTextBox () { unset($this->params->elementObj); ODTFrame::closeMultiColumnTextBox($this->params); } /** * Change outline style to given value. * Currently only 'Numbers' is supported. Any other value will * not change anything. * * @param string $type Type of outline style to set */ public function setOutlineStyle ($type) { $outline_style = $this->getStyle('Outline'); if (!isset($outline_style)) { // Outline style not found! return; } switch ($type) { case 'Numbers': for ($level = 1 ; $level < 11 ; $level++) { $outline_style->setPropertyForLevel($level, 'num-format', '1'); $outline_style->setPropertyForLevel($level, 'num-suffix', NULL); $outline_style->setPropertyForLevel($level, 'num-prefix', NULL); $outline_style->setPropertyForLevel($level, 'display-levels', $level); } break; } } /** * This function creates a text style for spans with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTTextStyle::createTextStyle for more documentation */ public function createTextStyle ($properties, $common=true) { $style_obj = ODTTextStyle::createTextStyle($properties, NULL, $this); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * This function creates a paragraph style for paragraphs with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTParagraphStyle::createParagraphStyle for more documentation */ public function createParagraphStyle ($properties, $common=true) { $style_obj = ODTParagraphStyle::createParagraphStyle($properties, NULL, $this); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * This function creates a table style for tables with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTTableStyle::createTableTableStyle for more documentation */ public function createTableStyle ($properties, $common=true) { $style_obj = ODTTableStyle::createTableTableStyle($properties); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * This function creates a table row style for table rows with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTTableRowStyle::createTableRowStyle for more documentation */ public function createTableRowStyle ($properties, $common=true) { $style_obj = ODTTableRowStyle::createTableRowStyle($properties); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * This function creates a table cell style for table cells with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTTableCellStyle::createTableCellStyle for more documentation */ public function createTableCellStyle ($properties, $common=true) { $style_obj = ODTTableCellStyle::createTableCellStyle($properties); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * This function creates a table column style for table columns with the given properties. * If $common is true it will be added to the common styles otherwise it * will be dadded to the automatic styles. * * Common styles are visible for the user after export e.g. in LibreOffice * 'Styles and Formatting' view. Therefore they should have * $properties ['style-display-name'] set to a meaningfull name. * * @param $properties The properties to use * @param $common Add style to common or automatic styles? * @see ODTTableColumnStyle::createTableColumnStyle for more documentation */ public function createTableColumnStyle ($properties, $common=true) { $style_obj = ODTTableColumnStyle::createTableColumnStyle($properties); if ($common == true) { $this->addStyle($style_obj); } else { $this->addAutomaticStyle($style_obj); } } /** * The function tries to examine the width and height * of the image stored in file $src. * * @see ODTUtility::getImageSize for a detailed description */ public function getImageSize($src, $maxwidth=NULL, $maxheight=NULL){ return ODTUtility::getImageSize($src, $maxwidth, $maxheight); } /** * @param string $src * @param $width * @param $height * @return array */ public function getImageSizeString($src, $width = NULL, $height = NULL){ return ODTUtility::getImageSizeString($src, $width, $height, false, $this->params->units); } /** * Adds an image $src to the document. * * @param string $src The path to the image file * @param string $width Width of the picture (NULL=original size) * @param string $height Height of the picture (NULL=original size) * @param string $align Alignment * @param string $title Title * @param string $style Optional "draw:style-name" * @param boolean $returnonly Only return code * * @see ODTImage::addImage for a detailed description */ public function addImage($src, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL, $returnonly = false){ if ($returnonly) { return ODTImage::addImage($this->params, $src, $width, $height, $align, $title, $style, $returnonly); } else { ODTImage::addImage($this->params, $src, $width, $height, $align, $title, $style, $returnonly); } } /** * Adds an image $src to the document using the parameters set in $properties. * * @param string $src The path to the image file * @param array $properties Properties (width, height... see ODTImage::addImageUseProperties) * @param boolean $returnonly Only return code * * @see ODTImage::addImageUseProperties for a detailed description */ public function addImageUseProperties($src, $properties, $returnonly = false){ if ($returnonly) { return ODTImage::addImageUseProperties($this->params, $src, $properties, $returnonly); } else { ODTImage::addImageUseProperties($this->params, $src, $properties, $returnonly); } } /** * The function adds $string as an SVG image file. * It does NOT insert the image in the document. * * @see ODTImage::addStringAsSVGImageFile for a detailed description */ public function addStringAsSVGImageFile($string) { return ODTImage::addStringAsSVGImageFile($this, $string); } /** * Adds the content of $string as a SVG picture to the document. * * @see ODTImage::addStringAsSVGImage for a detailed description */ public function addStringAsSVGImage($string, $width = NULL, $height = NULL, $align = NULL, $title = NULL, $style = NULL) { return ODTImage::addStringAsSVGImage($this->params, $string, $width, $height, $align, $title, $style); } /** * Get properties defined in a CSS style statement. * * @see ODTUtility::getCSSStylePropertiesForODT */ public function getCSSStylePropertiesForODT(&$properties, $style, $baseURL = NULL){ ODTUtility::getCSSStylePropertiesForODT($properties, $style, $baseURL, $this->units); } /** * This function sets the page format for the FIRST page. * The format, orientation and page margins can be changed. * See function queryFormat() in ODT/page.php for supported formats. * * @param string $format e.g. 'A4', 'A3' * @param string $orientation e.g. 'portrait' or 'landscape' * @param numeric $margin_top Top-Margin in cm, default 2 * @param numeric $margin_right Right-Margin in cm, default 2 * @param numeric $margin_bottom Bottom-Margin in cm, default 2 * @param numeric $margin_left Left-Margin in cm, default 2 */ public function setStartPageFormat ($format=NULL, $orientation=NULL, $margin_top=NULL, $margin_right=NULL, $margin_bottom=NULL, $margin_left=NULL) { // Setup page format. // Set the page format of the current page for calculation ($this->page) $this->page->setFormat ($format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left); // Change the standard page layout style $first_page = $this->getStyleByAlias('first page'); if (isset($first_page)) { $first_page->setProperty('width', $this->page->getWidth().'cm'); $first_page->setProperty('height', $this->page->getHeight().'cm'); $first_page->setProperty('margin-top', $this->page->getMarginTop().'cm'); $first_page->setProperty('margin-right', $this->page->getMarginRight().'cm'); $first_page->setProperty('margin-bottom', $this->page->getMarginBottom().'cm'); $first_page->setProperty('margin-left', $this->page->getMarginLeft().'cm'); } } /** * This function sets the page format. * The format, orientation and page margins can be changed. * See function queryFormat() in ODT/page.php for supported formats. * * @param string $format e.g. 'A4', 'A3' * @param string $orientation e.g. 'portrait' or 'landscape' * @param numeric $margin_top Top-Margin in cm, default 2 * @param numeric $margin_right Right-Margin in cm, default 2 * @param numeric $margin_bottom Bottom-Margin in cm, default 2 * @param numeric $margin_left Left-Margin in cm, default 2 */ public function setPageFormat ($format=NULL, $orientation=NULL, $margin_top=NULL, $margin_right=NULL, $margin_bottom=NULL, $margin_left=NULL) { $data = array (); // Fill missing values with current settings if ( empty($format) ) { $format = $this->page->getFormat(); } if ( empty($orientation) ) { $orientation = $this->page->getOrientation(); } if ( empty($margin_top) ) { $margin_top = $this->page->getMarginTop(); } if ( empty($margin_right) ) { $margin_right = $this->page->getMarginRight(); } if ( empty($margin_bottom) ) { $margin_bottom = $this->page->getMarginBottom(); } if ( empty($margin_left) ) { $margin_left = $this->page->getMarginLeft(); } // Adjust given parameters, query resulting format data and get format-string $this->page->queryFormat ($data, $format, $orientation, $margin_top, $margin_right, $margin_bottom, $margin_left); $format_string = $this->page->formatToString ($data['format'], $data['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); if ( $format_string == $this->page->toString () ) { // Current page already uses this format, no need to do anything... return; } if ($this->text_empty) { // If the text is still empty, then we change the start page format now. $this->page->setFormat($data ['format'], $data ['orientation'], $data['margin-top'], $data['margin-right'], $data['margin-bottom'], $data['margin-left']); $first_page = $this->getStyleByAlias('first page'); if (isset($first_page)) { $first_page->setProperty('width', $this->page->getWidth().'cm'); $first_page->setProperty('height', $this->page->getHeight().'cm'); $first_page->setProperty('margin-top', $this->page->getMarginTop().'cm'); $first_page->setProperty('margin-right', $this->page->getMarginRight().'cm'); $first_page->setProperty('margin-bottom', $this->page->getMarginBottom().'cm'); $first_page->setProperty('margin-left', $this->page->getMarginLeft().'cm'); } } else { // Set marker and save data for pending change format. // The format change istelf will be done on the next call to p_open or header() // to prevent empty lines after the format change. $this->changePageFormat = $data; // Close paragraph if open $this->paragraphClose(); } } /** * Return total page width in centimeters * (margins are included) * * @author LarsDW223 */ function getPageWidth(){ return $this->page->getWidth(); } /** * Return total page height in centimeters * (margins are included) * * @author LarsDW223 */ function getPageHeight(){ return $this->page->getHeight(); } /** * Return left margin in centimeters * * @author LarsDW223 */ function getLeftMargin(){ return $this->page->getMarginLeft(); } /** * Return right margin in centimeters * * @author LarsDW223 */ function getRightMargin(){ return $this->page->getMarginRight(); } /** * Return top margin in centimeters * * @author LarsDW223 */ function _getTopMargin(){ return $this->page->getMarginTop(); } /** * Return bottom margin in centimeters * * @author LarsDW223 */ function _getBottomMargin(){ return $this->page->getMarginBottom(); } /** * Return width percentage value if margins are taken into account. * Usually "100%" means 21cm in case of A4 format. * But usually you like to take care of margins. This function * adjusts the percentage to the value which should be used for margins. * So 100% == 21cm e.g. becomes 80.9% == 17cm (assuming a margin of 2 cm on both sides). * * @author LarsDW223 * * @param int|string $percentage * @return int|string */ function getRelWidthMindMargins ($percentage = '100'){ return $this->page->getRelWidthMindMargins($percentage); } /** * Like _getRelWidthMindMargins but returns the absulute width * in centimeters. * * @author LarsDW223 * @param string|int|float $percentage * @return float */ function getAbsWidthMindMargins ($percentage = '100'){ return $this->page->getAbsWidthMindMargins($percentage); } /** * Return height percentage value if margins are taken into account. * Usually "100%" means 29.7cm in case of A4 format. * But usually you like to take care of margins. This function * adjusts the percentage to the value which should be used for margins. * So 100% == 29.7cm e.g. becomes 86.5% == 25.7cm (assuming a margin of 2 cm on top and bottom). * * @author LarsDW223 * * @param string|float|int $percentage * @return float|string */ function getRelHeightMindMargins ($percentage = '100'){ return $this->page->getRelHeightMindMargins($percentage); } /** * Like _getRelHeightMindMargins but returns the absulute width * in centimeters. * * @author LarsDW223 * * @param string|int|float $percentage * @return float */ function getAbsHeightMindMargins ($percentage = '100'){ return $this->page->getAbsHeightMindMargins($percentage); } /** * Sets the twips per pixel (X axis) used for px to pt conversion. * * @param int $value The value to be set. */ function setTwipsPerPixelX ($value) { $this->units->setTwipsPerPixelX ($value); } /** * Sets the twips per pixel (Y axis) unit used for px to pt conversion. * * @param int $value The value to be set. */ function setTwipsPerPixelY ($value) { $this->units->setTwipsPerPixelY ($value); } /** * Sets the pixel per em unit used for px to em conversion. * * @param int $value The value to be set. */ public function setPixelPerEm ($value) { $this->units->setPixelPerEm ($value); } /** * Convert length value with valid XSL unit to points. * * @param string $value String with length value, e.g. '20px', '20cm'... * @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'. * Only relevant for conversion from 'px' or 'em'. * @return string The current value. */ public function toPoints ($value, $axis = 'y') { return $this->units->toPoints ($value, $axis); } /** * Convert length value with valid XSL unit to pixel. * * @param string $value String with length value, e.g. '20pt', '20cm'... * @param string $axis Is the value to be converted a value on the X or Y axis? Default is 'y'. * Only relevant for conversion from 'px' or 'em'. * @return string The current value. */ public function toPixel ($value, $axis = 'y') { return $this->units->toPixel ($value, $axis); } public function setTitle ($title) { // Set title in meta info. $this->meta->setTitle($title); } /** * Get closest previous TOC entry with $level. * The function search backwards (previous) in the TOC entries * for the next entry with level $level and retunrs it reference ID. * * @param int $level the nesting level * @return string The reference ID or NULL */ public function getPreviousToCItem($level) { $index = count($this->toc); for (; $index >= 0 ; $index--) { $item = $this->toc[$index]; $params = explode (',', $item); if ($params [3] == $level) { return $params [0]; } } return NULL; } /** * Insert cross reference to a "destination" inside of the ODT document. * To insert a link to an external destination use insertHyperlink(). * * The function only inserts a placeholder and resolves * the reference on calling replaceLocalLinkPlaceholders(); * * @fixme add image handling * * @param string $destination The resource to link to (e.g. heading ID) * @param string $text Text for the link (text inserted instead of $destination) */ function insertCrossReference($destination, $text){ $this->content .= ''.$destination.''; } function openImageLink ($url, $returnonly = false) { $encoded = ''; if ($this->linksEnabled) { $url = ODTUtility::stringToIRI($url); $encoded = ''; } if ($returnonly) { return $encoded; } $this->content .= $encoded; } function closeImageLink ($returnonly = false) { $encoded = ''; if ($this->linksEnabled) { $encoded = ''; } if ($returnonly) { return $encoded; } $this->content .= $encoded; } function openHyperlink ($url, $styleName = NULL, $visitedStyleName = NULL, $returnonly = false) { $encoded = ''; if ($url && $this->linksEnabled) { if (empty($styleName)) { $styleName = $this->getStyleName('internet link'); } if (empty($visitedStyleName)) { $visitedStyleName = $this->getStyleName('visited internet link'); } $url = ODTUtility::stringToIRI($url); $encoded .= 'content .= $encoded; } function closeHyperlink ($returnonly = false) { $encoded = ''; if ($this->linksEnabled) { $encoded .= ''; } if ($returnonly) { return $encoded; } $this->content .= $encoded; } function insertHyperlink ($url, $text, $styleName = NULL, $visitedStyleName = NULL, $returnonly = false) { $encoded = ''; if ($url && $this->linksEnabled) { if (empty($styleName)) { $styleName = $this->getStyleName('internet link'); } if (empty($visitedStyleName)) { $visitedStyleName = $this->getStyleName('visited internet link'); } $url = ODTUtility::stringToIRI($url); $encoded .= 'linksEnabled) { $encoded .= ''; } if ($returnonly) { return $encoded; } $this->content .= $encoded; } /** * Get CSS properties for a given element and adjust them for ODT. * * @param array $dest Properties found will be written in $dest as key value pairs, * e.g. $dest ['color'] = 'black'; * @param iElementCSSMatchable $element The element object for which the properties are queried. * The class of the element needs to implement the interface * iElementCSSMatchable. * @param string $media_sel The media selector to use for the query e.g. 'print'. May be empty. */ public function getODTProperties (array &$dest, $element, $attributes=NULL, $media_sel=NULL, $inherit=true) { if (!isset($this->importnew)) { return; } $save = $this->importnew->getMedia(); $this->importnew->setMedia($media_sel); $maxWidth = $this->getAbsWidthMindMargins().'cm'; ODTUtility::getHTMLElementProperties($this->params, $dest, $element, $attributes, $maxWidth, $inherit); $this->importnew->setMedia($save); } public function getODTPropertiesFromElement (array &$dest, iElementCSSMatchable $element, $media_sel=NULL, $inherit=true) { if (!isset($this->importnew)) { return; } $save = $this->importnew->getMedia(); $this->importnew->setMedia($media_sel); // Get properties for our class/element from imported CSS $this->importnew->getPropertiesForElement($dest, $element, $this->units, $inherit); // Adjust values for ODT $maxWidth = $this->getAbsWidthMindMargins().'cm'; ODTUtility::adjustValuesForODT($dest, $this->units, $maxWidth); $this->importnew->setMedia($save); } public function adjustValuesForODT (array &$properties) { ODTUtility::adjustValuesForODT($properties, $this->units); } public function adjustValueForODT ($property, $value) { return ODTUtility::adjustValueForODT($property, $value, $this->units); } /** * Adds an $element with $attributes to the internal HTML stack for * CSS matching. HTML elments added from extern using this function * are supposed to never be closed so only root elements should be * added like 'html' or 'body' or maybe a 'div' that should always * be present for proper CSS matching. * * @param string $element The element name, e.g. 'body' * @param string $attributes The elements attributes, e.g. 'lang="en" dir="ltr"' */ public function addHTMLElement ($element, $attributes = NULL) { $this->htmlStack->open($element, $attributes); $this->htmlStack->saveRootIndex (); } public function getHTMLStack () { return $this->htmlStack; } public function dumpHTMLStack () { $this->trace_dump .= $this->htmlStack->getDump(); } /** * Check if a file already exists in the document. * * @param string $fileName Full file name in the document * e.g. 'Pictures/myimage.png' * @return bool */ public function fileExists($name) { return $this->manifest->exists($name); } /** * Add a file to the document. * * @param string $fileName Full file name in the document * e.g. 'Pictures/myimage.png' * @param string $mime Mime type * @param string $content The content of the file */ public function addFile($fileName, $mime, $content) { if(!$this->manifest->exists($fileName)){ $this->manifest->add($fileName, $mime); $this->ZIP->addData($fileName, $content); return true; } // File with that name already exists! return false; } /** * Adds the image $fileName as a picture file without adding it to * the content of the document. The link name which can be used for * the ODT draw:image xlink:href is returned. * * @param string $fileName * @return string */ function addFileAsPicture($fileName){ $name = ''; if (file_exists($fileName)) { list($ext,$mime) = mimetype($fileName); $name = 'Pictures/'.md5($fileName).'.'.$ext; $this->addFile($name, $mime, io_readfile($fileName,false)); } return $name; } /** * Add style object to the document as a common style. * * @param ODTStyle $new Object to add */ public function addStyle(ODTStyle $new) { return $this->styleset->addStyle($new); } /** * Add style object to the document as an automatic style. * * @param ODTStyle $new Object to add */ public function addAutomaticStyle(ODTStyle $new) { return $this->styleset->addAutomaticStyle($new); } /** * Check if a style with $styleName already exists. * * @param string $styleName The style name ofthe style style. * @return bool */ public function styleExists ($name) { return $this->styleset->styleExists($name); } /** * Get the style object with style name $styleName. * * @param string $styleName The style name ofthe style style. * @return ODTStyle The style object */ public function getStyle ($styleName) { return $this->styleset->getStyle($styleName); } public function getDefaultStyle ($family) { return $this->styleset->getDefaultStyle($family); } /** * Get the style name for a style alias. * * @param string $alias The alias for the style. * @return string The style name used in the ODT document */ public function getStyleName($alias) { return $this->styleset->getStyleName($alias); } /** * The function returns the style at the given index * * @param $element Element of the style e.g. 'office:styles' * @return ODTStyle or NULL */ public function getStyleAtIndex($element, $index) { return $this->styleset->getStyleAtIndex($element, $index); } /** * Get the style object by $alias. * * @param string $alias The alias for the style. * @return ODTStyle The style object */ public function getStyleByAlias($alias) { return $this->styleset->getStyle($this->styleset->getStyleName($alias)); } public function registerHTMLElementForCSSImport ($style_type, $element, $attributes=NULL) { $this->registrations [$style_type]['element'] = $element; $this->registrations [$style_type]['attributes'] = $attributes; } public function addToValue ($value, $add) { $valueInPt = $this->units->toPoints($value, 'y'); $valueInPt = $this->units->getDigits($valueInPt); $addInPt = $this->units->toPoints($add, 'y'); $addInPt = $this->units->getDigits($addInPt); return ($valueInPt + $addInPt).'pt'; } public function subFromValue ($value, $sub) { $valueInPt = $this->units->toPoints($value, 'y'); $valueInPt = $this->units->getDigits($valueInPt); $subInPt = $this->units->toPoints($sub, 'y'); $subInPt = $this->units->getDigits($subInPt); return ($valueInPt - $subInPt).'pt'; } /** * Adjust font sizes of all styles to $newBaseSize. * The $newBaseSize will be the new default font-size and all * other font-sizes will be re-calculated. * * @param string $newBaseSize The new base size e.g. '16pt' */ public function adjustFontSizes($newBaseSize) { // First get the old base size $default = $this->styleset->getDefaultStyle('paragraph'); if (!isset($default)) { // ??? return; } $oldBaseSize = $default->getProperty('font-size'); if (!isset($oldBaseSize)) { return; } $oldBaseSizeInPt = trim($this->units->toPoints($oldBaseSize, 'y'), 'pt'); // Convert new base size to pt $newBaseSizeInPt = trim($this->units->toPoints($newBaseSize, 'y'), 'pt'); $styles_list = array(); $styles_list [] = $this->styleset->getStyles(); $styles_list [] = $this->styleset->getAutomaticStyles(); $styles_list [] = $this->styleset->getMasterStyles(); // Go through the list of style arrays and adjust each one // having a 'font-size' property foreach ($styles_list as $styles) { foreach ($styles as $style) { $fontSize = $style->getProperty('font-size'); if (isset($fontSize)) { $fontSizeInPt = trim($this->units->toPoints($fontSize, 'y'), 'pt'); $fontSizeInPt = ($fontSizeInPt/$oldBaseSizeInPt) * $newBaseSizeInPt; $fontSizeInPt = round($fontSizeInPt, 2); $style->setProperty('font-size', $fontSizeInPt.'pt'); } } } $this->trace_dump .= 'newBaseSize: '.$newBaseSize."\n"; $this->trace_dump .= 'newBaseSizeInPt: '.$newBaseSizeInPt."\n"; // Also set default font-size to the new base size! $default->setProperty('font-size', $newBaseSizeInPt.'pt'); } /** * The function sets the alignment and indentation for ordered lists. * This means the alignment of the numbers if front of each list item. * For each alignment predefined values for the attributes 'list-tab-stop-position', * 'text-indent' and 'margin-left' is set. * * @param string $align Alignment to set ('left'/'start', 'center', 'right'/'end') * @param integer $paddingLeft Left padding in centimeters, moves the whole list to the right * @param integer $marginLeft Left margin in centimeters, specifies the indent per level */ public function setOrderedListParams($setLevel=NULL, $align, $paddingLeft=0, $marginLeft=1) { if (empty($align)) { return; } $name = $this->styleset->getStyleName('numbering'); $style = $this->styleset->getStyle($name); if ( !isset($style) ) { return; } if ( !isset($setLevel) ) { for ($level = 1 ; $level < 11 ; $level++) { switch ($align) { case 'left': case 'start': $dist = 1; $style->setPropertyForLevel($level, 'text-align', 'left'); break; case 'center': $dist = 0.5; $style->setPropertyForLevel($level, 'text-align', 'center'); break; case 'right': case 'end': default: $dist = 0.25; $style->setPropertyForLevel($level, 'text-align', 'end'); break; } $position = $paddingLeft + ($marginLeft * $level) + $dist; $style->setPropertyForLevel($level, 'list-level-position-and-space-mode', 'label-alignment'); $style->setPropertyForLevel($level, 'label-followed-by', 'listtab'); $style->setPropertyForLevel($level, 'list-tab-stop-position', $position.'cm'); $style->setPropertyForLevel($level, 'text-indent', ($dist*-1).'cm'); $style->setPropertyForLevel($level, 'margin-left', $position.'cm'); } } else { switch ($align) { case 'left': case 'start': $dist = 1; $style->setPropertyForLevel($setLevel, 'text-align', 'left'); break; case 'center': $dist = 0.5; $style->setPropertyForLevel($setLevel, 'text-align', 'center'); break; case 'right': case 'end': default: $dist = 0.25; $style->setPropertyForLevel($setLevel, 'text-align', 'end'); break; } $position = $paddingLeft + ($marginLeft * $setLevel) + $dist; $style->setPropertyForLevel($setLevel, 'list-level-position-and-space-mode', 'label-alignment'); $style->setPropertyForLevel($setLevel, 'label-followed-by', 'listtab'); $style->setPropertyForLevel($setLevel, 'list-tab-stop-position', $position.'cm'); $style->setPropertyForLevel($setLevel, 'text-indent', ($dist*-1).'cm'); $style->setPropertyForLevel($setLevel, 'margin-left', $position.'cm'); } } /** * The function sets the alignment and indentation for unordered lists. * This means the alignment of the icons/buttons if front of each list item. * For each alignment predefined values for the attributes 'list-tab-stop-position', * 'text-indent' and 'margin-left' is set. * * @param string $align Alignment to set ('left'/'start', 'center', 'right'/'end') * @param integer $paddingLeft Left padding in centimeters, moves the whole list to the right * @param integer $marginLeft Left margin in centimeters, specifies the indent per level */ public function setUnorderedListParams($setLevel=NULL, $align, $paddingLeft=0, $marginLeft=1) { if (empty($align)) { return; } $name = $this->styleset->getStyleName('list'); $style = $this->styleset->getStyle($name); if ( !isset($style) ) { return; } if ( !isset($setLevel) ) { for ($level = 1 ; $level < 11 ; $level++) { switch ($align) { case 'left': case 'start': $dist = 1; $style->setPropertyForLevel($level, 'text-align', 'left'); break; case 'center': $dist = 0.5; $style->setPropertyForLevel($level, 'text-align', 'center'); break; case 'right': case 'end': default: $dist = 0.25; $style->setPropertyForLevel($level, 'text-align', 'end'); break; } $position = $paddingLeft + ($marginLeft * $level) + $dist; $style->setPropertyForLevel($level, 'list-level-position-and-space-mode', 'label-alignment'); $style->setPropertyForLevel($level, 'label-followed-by', 'listtab'); $style->setPropertyForLevel($level, 'list-tab-stop-position', $position.'cm'); $style->setPropertyForLevel($level, 'text-indent', ($dist*-1).'cm'); $style->setPropertyForLevel($level, 'margin-left', $position.'cm'); } } else { switch ($align) { case 'left': case 'start': $dist = 1; $style->setPropertyForLevel($setLevel, 'text-align', 'left'); break; case 'center': $dist = 0.5; $style->setPropertyForLevel($setLevel, 'text-align', 'center'); break; case 'right': case 'end': default: $dist = 0.25; $style->setPropertyForLevel($setLevel, 'text-align', 'end'); break; } $position = $paddingLeft + ($marginLeft * $setLevel) + $dist; $style->setPropertyForLevel($setLevel, 'list-level-position-and-space-mode', 'label-alignment'); $style->setPropertyForLevel($setLevel, 'label-followed-by', 'listtab'); $style->setPropertyForLevel($setLevel, 'list-tab-stop-position', $position.'cm'); $style->setPropertyForLevel($setLevel, 'text-indent', ($dist*-1).'cm'); $style->setPropertyForLevel($setLevel, 'margin-left', $position.'cm'); } } /** * Automatically generate ODT format for given $HTMLCode. * * @param string $HTMLCode * @see ODTUtility::generateODTfromHTMLCode for detailed documentation */ public function generateODTfromHTMLCode($HTMLCode, array $options){ ODTUtility::generateODTfromHTMLCode($this->params, $HTMLCode, $options); } }